Changeset 9099 in josm
- Timestamp:
- 2015-12-11T17:36:59+01:00 (9 years ago)
- Location:
- trunk
- Files:
-
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/MapPaintSettings.java
r9082 r9099 49 49 /** Preference: should only the data area outline be drawn */ 50 50 private boolean outlineOnly; 51 /** Preference: parameter to avoid partial fill on small area objects:52 * If more than a certain percentage of the total area would be filled by53 * partial fill, then fill this area completely (avoiding narrow gap in the54 * center) */55 private double partialFillThreshold;56 51 /** Color Preference for selected objects */ 57 52 private Color selectedColor; … … 111 106 112 107 outlineOnly = Main.pref.getBoolean("draw.data.area_outline_only", false); 113 partialFillThreshold = Main.pref.getDouble("draw.area.partial_fill_threshold", 70);114 108 } 115 109 … … 352 346 return outlineOnly; 353 347 } 354 355 /**356 * Returns the partial fill threshold.357 * This parameter is used to avoid partial fill on small area objects:358 * If more than a certain percentage of the total area would be filled by359 * partial fill, then fill this area completely (avoiding narrow gap in the360 * center)361 * @return the partial fill threshold362 */363 public double getPartialFillThreshold() {364 return partialFillThreshold;365 }366 348 } -
trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRenderer.java
r9082 r9099 336 336 private boolean showIcons; 337 337 private boolean isOutlineOnly; 338 private double partialFillThreshold;339 338 340 339 private Font orderFont; … … 467 466 * far to fill from the boundary towards the center of the area; 468 467 * if null, area will be filled completely 469 * @param pfClip clipping area for partial fill 468 * @param pfClip clipping area for partial fill (only needed for unclosed 469 * polygons) 470 470 * @param disabled If this should be drawn with a special disabled style. 471 471 * @param text The text to write on the area. … … 492 492 } 493 493 g.clip(clip); 494 g.setStroke(new BasicStroke(2 * extent, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER)); 494 g.setStroke(new BasicStroke(2 * extent, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 4)); 495 495 g.draw(area); 496 496 g.setClip(oldClip); … … 607 607 * far to fill from the boundary towards the center of the area; 608 608 * if null, area will be filled completely 609 * @param extentThreshold if not null, determines if the partial filled should 610 * be replaced by plain fill, when it covers a certain fraction of the total area 609 611 * @param disabled If this should be drawn with a special disabled style. 610 612 * @param text The text to write on the area. 611 613 */ 612 public void drawArea(Relation r, Color color, MapImage fillImage, Float extent, boolean disabled, TextElement text) { 614 public void drawArea(Relation r, Color color, MapImage fillImage, Float extent, Float extentThreshold, boolean disabled, TextElement text) { 613 615 Multipolygon multipolygon = MultipolygonCache.getInstance().get(nc, r); 614 616 if (!r.isDisabled() && !multipolygon.getOuterWays().isEmpty()) { … … 620 622 } 621 623 if (extent != null) { 622 if (pd.isClosed()) { 623 AreaAndPerimeter ap = pd.getAreaAndPerimeter(); 624 // if partial fill would only leave a small gap in the center ... 625 if (ap.getPerimeter() * extent * scale > partialFillThreshold / 100 * ap.getArea()) { 626 // ... turn it off and fill completely 627 extent = null; 628 } 629 } else { 624 if (!usePartialFill(pd.getAreaAndPerimeter(), extent, extentThreshold)) { 625 extent = null; 626 } else if (!pd.isClosed()) { 630 627 pfClip = getPFClip(pd, extent * scale); 631 628 } … … 646 643 * far to fill from the boundary towards the center of the area; 647 644 * if null, area will be filled completely 645 * @param extentThreshold if not null, determines if the partial filled should 646 * be replaced by plain fill, when it covers a certain fraction of the total area 648 647 * @param disabled If this should be drawn with a special disabled style. 649 648 * @param text The text to write on the area. 650 649 */ 651 public void drawArea(Way w, Color color, MapImage fillImage, Float extent, boolean disabled, TextElement text) { 650 public void drawArea(Way w, Color color, MapImage fillImage, Float extent, Float extentThreshold, boolean disabled, TextElement text) { 652 651 Path2D.Double pfClip = null; 653 652 if (extent != null) { 654 if (w.isClosed()) { 655 AreaAndPerimeter ap = Geometry.getAreaAndPerimeter(w.getNodes()); 656 // if partial fill would only leave a small gap in the center ... 657 if (ap.getPerimeter() * extent * scale > partialFillThreshold / 100 * ap.getArea()) { 658 // ... turn it off and fill completely 659 extent = null; 660 } 661 } else { 653 if (!usePartialFill(Geometry.getAreaAndPerimeter(w.getNodes()), extent, extentThreshold)) { 654 extent = null; 655 } else if (!w.isClosed()) { 662 656 pfClip = getPFClip(w, extent * scale); 663 657 } 664 658 } 665 659 drawArea(w, getPath(w), color, fillImage, extent, pfClip, disabled, text); 660 } 661 662 /** 663 * Determine, if partial fill should be turned off for this object, because 664 * only a small unfilled gap in the center of the area would be left. 665 * 666 * This is used to get a cleaner look for urban regions with many small 667 * areas like buildings, etc. 668 * @param ap the area and the perimeter of the object 669 * @param extent the "width" of partial fill 670 * @param threshold when the partial fill covers that much of the total 671 * area, the partial fill is turned off; can be greater than 100% as the 672 * covered area is estimated as <code>perimeter * extent</code> 673 * @return true, if the partial fill should be used, false otherwise 674 */ 675 private boolean usePartialFill(AreaAndPerimeter ap, float extent, Float threshold) { 676 if (threshold == null) return true; 677 return ap.getPerimeter() * extent * scale < threshold * ap.getArea(); 666 678 } 667 679 … … 1519 1531 showIcons = paintSettings.getShowIconsDistance() > circum; 1520 1532 isOutlineOnly = paintSettings.isOutlineOnly(); 1521 partialFillThreshold = paintSettings.getPartialFillThreshold();1522 1533 orderFont = new Font(Main.pref.get("mappaint.font", "Droid Sans"), Font.PLAIN, Main.pref.getInteger("mappaint.fontsize", 8)); 1523 1534 … … 1596 1607 } 1597 1608 1609 /** 1610 * Fix the clipping area of unclosed polygons for partial fill. 1611 * 1612 * The current algorithm for partial fill simply strokes the polygon with a 1613 * large stroke width after masking the outside with a clipping area. 1614 * This works, but for unclosed polygons, the mask can crop the corners at 1615 * both ends (see #12104). 1616 * 1617 * This method fixes the clipping area by sort of adding the corners to the 1618 * clip outline. 1619 * 1620 * @param clip the clipping area to modify (initially empty) 1621 * @param nodes nodes of the polygon 1622 * @param extent the extent 1623 */ 1598 1624 private static void buildPFClip(Path2D.Double clip, List<Node> nodes, double extent) { 1599 1625 boolean initial = true; … … 1629 1655 } 1630 1656 1657 /** 1658 * Get the point to add to the clipping area for partial fill of unclosed polygons. 1659 * 1660 * <code>(p1,p2)</code> is the first or last way segment and <code>p3</code> the 1661 * opposite endpoint. 1662 * 1663 * @param p1 1st point 1664 * @param p2 2nd point 1665 * @param p3 3rd point 1666 * @param extent the extent 1667 * @return a point q, such that p1,p2,q form a right angle 1668 * and the distance of q to p2 is <code>extent</code>. The point q lies on 1669 * the same side of the line p1,p2 as the point p3. 1670 * Returns null if p1,p2,p3 forms an angle greater 90 degrees. (In this case 1671 * the corner of the partial fill would not be cut off by the mask, so an 1672 * additional point is not necessary.) 1673 */ 1631 1674 private static EastNorth getPFDisplacedEndPoint(EastNorth p1, EastNorth p2, EastNorth p3, double extent) { 1632 1675 double dx1 = p2.getX() - p1.getX(); … … 1636 1679 if (dx1 * dx2 + dy1 * dy2 < 0) { 1637 1680 double len = Math.sqrt(dx1 * dx1 + dy1 * dy1); 1681 if (len == 0) return null; 1638 1682 double dxm = -dy1 * extent / len; 1639 1683 double dym = dx1 * extent / len; -
trunk/src/org/openstreetmap/josm/gui/mappaint/AreaElemStyle.java
r9008 r9099 26 26 public TextElement text; 27 27 public Float extent; 28 public Float extentThreshold; 28 29 29 protected AreaElemStyle(Cascade c, Color color, MapImage fillImage, Float extent, TextElement text) { 30 protected AreaElemStyle(Cascade c, Color color, MapImage fillImage, Float extent, Float extentThreshold, TextElement text) { 30 31 super(c, 1f); 31 32 CheckParameterUtil.ensureParameterNotNull(color); 32 33 this.color = color; 34 this.fillImage = fillImage; 33 35 this.extent = extent; 34 this. fillImage = fillImage;36 this.extentThreshold = extentThreshold; 35 37 this.text = text; 36 38 } … … 39 41 final Cascade c = env.mc.getCascade(env.layer); 40 42 MapImage fillImage = null; 41 Color color = null; 42 Float extent = null; 43 Color color; 43 44 44 45 IconReference iconRef = c.get(FILL_IMAGE, null, IconReference.class); … … 81 82 } 82 83 83 extent = c.get(FILL_EXTENT, null, float.class); 84 Float extent = c.get(FILL_EXTENT, null, float.class); 85 Float extentThreshold = c.get(FILL_EXTENT_THRESHOLD, null, float.class); 84 86 85 87 if (color != null) 86 return new AreaElemStyle(c, color, fillImage, extent, text); 88 return new AreaElemStyle(c, color, fillImage, extent, extentThreshold, text); 87 89 else 88 90 return null; … … 101 103 } 102 104 } 103 painter.drawArea((Way) osm, myColor, fillImage, extent, painter.isInactiveMode() || osm.isDisabled(), text); 105 painter.drawArea((Way) osm, myColor, fillImage, extent, extentThreshold, painter.isInactiveMode() || osm.isDisabled(), text); 104 106 } else if (osm instanceof Relation) { 105 107 if (color != null && (selected || outermember)) { 106 108 myColor = paintSettings.getRelationSelectedColor(color.getAlpha()); 107 109 } 108 painter.drawArea((Relation) osm, myColor, fillImage, extent, painter.isInactiveMode() || osm.isDisabled(), text); 110 painter.drawArea((Relation) osm, myColor, fillImage, extent, extentThreshold, painter.isInactiveMode() || osm.isDisabled(), text); 109 111 } 110 112 } … … 124 126 if (extent != other.extent) 125 127 return false; 128 if (extentThreshold != other.extentThreshold) 129 return false; 126 130 if (!Objects.equals(text, other.text)) 127 131 return false; … … 134 138 hash = 61 * hash + color.hashCode(); 135 139 hash = 61 * hash + (extent != null ? Float.floatToIntBits(extent) : 0); 140 hash = 61 * hash + (extentThreshold != null ? Float.floatToIntBits(extent) : 0); 136 141 hash = 61 * hash + (fillImage != null ? fillImage.hashCode() : 0); 137 142 hash = 61 * hash + (text != null ? text.hashCode() : 0); -
trunk/src/org/openstreetmap/josm/gui/mappaint/StyleKeys.java
r9005 r9099 11 11 String FILL_COLOR = "fill-color"; 12 12 String FILL_EXTENT = "fill-extent"; 13 String FILL_EXTENT_THRESHOLD = "fill-extent-threshold"; 13 14 String FILL_IMAGE = "fill-image"; 14 15 String FILL_OPACITY = "fill-opacity"; -
trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Condition.java
r9087 r9099 633 633 return IN_DOWNLOADED_AREA.evaluate(e.osm); 634 634 } 635 636 static boolean completely_downloaded(Environment e) { 637 if (e.osm instanceof Relation) { 638 return !((Relation) e.osm).hasIncompleteMembers(); 639 } else { 640 return true; 641 } 642 } 643 644 static boolean closed2(Environment e) { 645 if (e.osm instanceof Way && ((Way) e.osm).isClosed()) 646 return true; 647 if (e.osm instanceof Relation && ((Relation) e.osm).isMultipolygon()) 648 return MultipolygonCache.getInstance().get(Main.map.mapView, (Relation) e.osm).getOpenEnds().isEmpty(); 649 return false; 650 } 635 651 } 636 652 -
trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSParser.jj
r8874 r9099 204 204 | < ELEMENT_OF: "∈" > 205 205 | < CROSSING: "⧉" > 206 | < PERCENT: "%" > 206 207 | < COMMENT_START: "/*" > : COMMENT 207 208 | < UNEXPECTED_CHAR : ~[] > // avoid TokenMgrErrors because they are hard to recover from … … 1126 1127 } 1127 1128 { 1128 f=ufloat() ( u=ident() | <DEG> { u = "°"; } ) 1129 f=ufloat() ( u=ident() | <DEG> { u = "°"; } | <PERCENT> { u = "%"; } ) 1129 1130 { 1130 1131 Double m = unit_factor(u); … … 1143 1144 case "grad": return Math.PI / 200; 1144 1145 case "turn": return 2 * Math.PI; 1146 case "%": return 0.01; 1145 1147 case "px": return 1.; 1146 1148 case "cm": return 96/2.54; -
trunk/src/org/openstreetmap/josm/tools/Geometry.java
r9063 r9099 978 978 * Uses current projection; units are that of the projected coordinates. 979 979 * 980 * @param nodes the list of nodes representing the polygon (must be 981 * closed, i.e. first node equals last node) 980 * @param nodes the list of nodes representing the polygon 982 981 * @return area and perimeter 983 982 */ 984 983 public static AreaAndPerimeter getAreaAndPerimeter(List<Node> nodes) { 985 if (nodes.get(0) != nodes.get(nodes.size() - 1)) {986 throw new IllegalArgumentException();987 }988 984 double area = 0; 989 985 double perimeter = 0; 990 Node lastN = null; 991 for (Node n : nodes) { 992 if (lastN != null) { 993 EastNorth p1 = lastN.getEastNorth(); 994 EastNorth p2 = n.getEastNorth(); 986 if (!nodes.isEmpty()) { 987 boolean closed = nodes.get(0) == nodes.get(nodes.size() - 1); 988 int numSegments = closed ? nodes.size() - 1 : nodes.size(); 989 EastNorth p1 = nodes.get(0).getEastNorth(); 990 for (int i=1; i<=numSegments; i++) { 991 EastNorth p2 = nodes.get(i == numSegments ? 0 : i).getEastNorth(); 995 992 area += p1.east() * p2.north() - p2.east() * p1.north(); 996 993 perimeter += p1.distance(p2); 997 }998 lastN = n;994 p1 = p2; 995 } 999 996 } 1000 997 return new AreaAndPerimeter(Math.abs(area) / 2, perimeter); -
trunk/styles/standard/elemstyles.mapcss
r9097 r9099 4866 4866 /*************/ 4867 4867 4868 /* small extent for unclosed area (see below for closed) */ 4868 4869 area[setting("partial_fill")] { 4870 fill-extent: 15; 4871 } 4872 4873 /* Turn partial fill off and us plain fill, when the partial fill covers about 4874 100% of the area. This reduces artifacts (typically for incomplete multipolygons). 4875 Switching between full and partial fill while drawing an area might be irritating, 4876 so only do this at low zoom. */ 4877 area|z-13[setting("partial_fill")] { 4878 fill-extent-threshold: 100%; 4879 } 4880 4881 /* Larger extent for closed areas. 4882 Turn partial fill off, when it covers more than about 70% of the area. This is avoids 4883 areas with small unfilled patches in the center. */ 4884 area[setting("partial_fill")]:closed2 { 4869 4885 fill-extent: 25; 4870 } 4886 fill-extent-threshold: 70%; 4887 } 4888
Note:
See TracChangeset
for help on using the changeset viewer.