Changeset 9099 in josm for trunk/src/org
- Timestamp:
- 2015-12-11T17:36:59+01:00 (9 years ago)
- Location:
- trunk/src/org/openstreetmap/josm
- Files:
-
- 7 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);
Note:
See TracChangeset
for help on using the changeset viewer.