Changeset 9063 in josm for trunk


Ignore:
Timestamp:
2015-11-25T09:54:02+01:00 (9 years ago)
Author:
bastiK
Message:

mapcss: partial fill - if partial fill would only leave a small gap in the center, fill area completely (see #12104)

Location:
trunk/src/org/openstreetmap/josm
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/MapPaintSettings.java

    r9061 r9063  
    5353    /** Preference: width of unclosed area highlight */
    5454    private double unclosedAreaHighlightWidth;
     55    /** Preference: parameter to avoid partial fill on small area objects:
     56     * If more than a certain percentage of the total area would be filled by
     57     * partial fill, then fill this area completely (avoiding narrow gap in the
     58     * center) */
     59    private double partialFillThreshold;
    5560    /** Color Preference for selected objects */
    5661    private Color selectedColor;
     
    112117        unclosedAreaHighlight = Main.pref.getBoolean("draw.unclosed_area_partial_fill_highlight", true);
    113118        unclosedAreaHighlightWidth = Main.pref.getDouble("draw.unclosed_area_partial_fill_highlight.width", 80);
     119        partialFillThreshold = Main.pref.getDouble("draw.area.partial_fill_threshold", 50);
    114120    }
    115121
     
    363369
    364370    /**
    365      * Returns the width of unclosed area highlight
     371     * Returns the width of unclosed area highlight.
    366372     * @return the width of unclosed area highlight
    367373     */
     
    369375        return unclosedAreaHighlightWidth;
    370376    }
     377
     378    /**
     379     * Returns the partial fill threshold.
     380     * This parameter is used to avoid partial fill on small area objects:
     381     * If more than a certain percentage of the total area would be filled by
     382     * partial fill, then fill this area completely (avoiding narrow gap in the
     383     * center)
     384     * @return the partial fill threshold
     385     */
     386    public double getPartialFillThreshold() {
     387        return partialFillThreshold;
     388    }
    371389}
  • trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRenderer.java

    r9061 r9063  
    7575import org.openstreetmap.josm.gui.mappaint.mapcss.Selector;
    7676import org.openstreetmap.josm.tools.CompositeList;
     77import org.openstreetmap.josm.tools.Geometry;
     78import org.openstreetmap.josm.tools.Geometry.AreaAndPerimeter;
    7779import org.openstreetmap.josm.tools.ImageProvider;
    7880import org.openstreetmap.josm.tools.Pair;
     
    335337    private boolean isUnclosedAreaHighlight;
    336338    private double unclosedAreaHighlightWidth;
     339    private double partialFillThreshold;
    337340
    338341    private Font orderFont;
     
    465468     * far to fill from the boundary towards the center of the area;
    466469     * if null, area will be filled completely
    467      * @param unClosedHighlight true, if the fact that the way / multipolygon is not
     470     * @param unclosedHighlight true, if the fact that the way / multipolygon is not
    468471     * properly closed should be highlighted; this parameter is only used
    469472     * for partial fill ({@code extent != null}), otherwise it is ignored
     
    471474     * @param text The text to write on the area.
    472475     */
    473     protected void drawArea(OsmPrimitive osm, Path2D.Double path, Color color, MapImage fillImage, Float extent, boolean unClosedHighlight,
     476    protected void drawArea(OsmPrimitive osm, Path2D.Double path, Color color, MapImage fillImage, Float extent, boolean unclosedHighlight,
    474477            boolean disabled, TextElement text) {
    475478
     
    486489                    g.fill(area);
    487490                } else {
    488                     if (unClosedHighlight) {
     491                    if (unclosedHighlight) {
    489492                        g.setStroke(new BasicStroke((int)(unclosedAreaHighlightWidth / 100 * extent),
    490493                                BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER));
     
    509512                    g.fill(area);
    510513                } else {
    511                     if (unClosedHighlight) {
     514                    if (unclosedHighlight) {
    512515                        g.setStroke(new BasicStroke((int)(unclosedAreaHighlightWidth / 100 * extent),
    513516                                BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER));
     
    622625                    continue;
    623626                }
     627                boolean unclosedHighlight = false;
     628                if (extent != null) {
     629                    if (pd.isClosed()) {
     630                        AreaAndPerimeter ap = pd.getAreaAndPerimeter();
     631                        // if partial fill would only leave a small gap in the center ...
     632                        if (ap.getPerimeter() * extent * circum / 100 > partialFillThreshold / 100 * ap.getArea()) {
     633                            // ... turn it off and fill completely
     634                            extent = null;
     635                        }
     636                    } else {
     637                        unclosedHighlight = isUnclosedAreaHighlight;
     638                    }
     639                }
    624640                drawArea(r, p,
    625641                        pd.selected ? paintSettings.getRelationSelectedColor(color.getAlpha()) : color,
    626                         fillImage, extent,
    627                         isUnclosedAreaHighlight && extent != null && !pd.isClosed(),
    628                         disabled, text);
     642                        fillImage, extent, unclosedHighlight, disabled, text);
    629643            }
    630644        }
     
    643657     */
    644658    public void drawArea(Way w, Color color, MapImage fillImage, Float extent, boolean disabled, TextElement text) {
     659        if (extent != null && w.isClosed()) {
     660            AreaAndPerimeter ap = Geometry.getAreaAndPerimeter(w.getNodes());
     661            // if partial fill would only leave a small gap in the center ...
     662            if (ap.getPerimeter() * extent * circum / 100 > partialFillThreshold / 100 * ap.getArea()) {
     663                // ... turn it off and fill completely
     664                extent = null;
     665            }
     666        }
    645667        drawArea(w, getPath(w), color, fillImage, extent, isUnclosedAreaHighlight && !w.isClosed(), disabled, text);
    646668    }
     
    15001522        isUnclosedAreaHighlight = paintSettings.isUnclosedAreaHighlight();
    15011523        unclosedAreaHighlightWidth = paintSettings.getUnclosedAreaHighlightWidth();
     1524        partialFillThreshold = paintSettings.getPartialFillThreshold();
    15021525        orderFont = new Font(Main.pref.get("mappaint.font", "Droid Sans"), Font.PLAIN, Main.pref.getInteger("mappaint.fontsize", 8));
    15031526
  • trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/relations/Multipolygon.java

    r9061 r9063  
    33
    44import java.awt.geom.Path2D;
    5 import java.awt.geom.Path2D.Double;
    65import java.awt.geom.PathIterator;
    76import java.awt.geom.Rectangle2D;
     
    2726import org.openstreetmap.josm.data.osm.event.WayNodesChangedEvent;
    2827import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon.PolyData.Intersection;
     28import org.openstreetmap.josm.tools.Geometry;
     29import org.openstreetmap.josm.tools.Geometry.AreaAndPerimeter;
    2930
    3031/**
     
    244245        public PolyData(PolyData copy) {
    245246            this.selected = copy.selected;
    246             this.poly = (Double) copy.poly.clone();
     247            this.poly = (Path2D.Double) copy.poly.clone();
    247248            this.wayIds = Collections.unmodifiableCollection(copy.wayIds);
    248249            this.nodes = new ArrayList<>(copy.nodes);
     
    368369            }
    369370            return true;
     371        }
     372
     373        public AreaAndPerimeter getAreaAndPerimeter() {
     374            AreaAndPerimeter ap = Geometry.getAreaAndPerimeter(nodes);
     375            double area = ap.getArea();
     376            double perimeter = ap.getPerimeter();
     377            for (PolyData inner : inners) {
     378                AreaAndPerimeter apInner = inner.getAreaAndPerimeter();
     379                area -= apInner.getArea();
     380                perimeter += apInner.getPerimeter();
     381            }
     382            return new AreaAndPerimeter(area, perimeter);
    370383        }
    371384    }
  • trunk/src/org/openstreetmap/josm/tools/Geometry.java

    r9062 r9063  
    951951        return false;
    952952    }
     953
     954    /**
     955     * Data class to hold two double values (area and perimeter of a polygon).
     956     */
     957    public static class AreaAndPerimeter {
     958        private final double area;
     959        private final double perimeter;
     960
     961        public AreaAndPerimeter(double area, double perimeter) {
     962            this.area = area;
     963            this.perimeter = perimeter;
     964        }
     965
     966        public double getArea() {
     967            return area;
     968        }
     969
     970        public double getPerimeter() {
     971            return perimeter;
     972        }
     973    }
     974
     975    /**
     976     * Calculate area and perimeter length of a polygon.
     977     *
     978     * Uses current projection; units are that of the projected coordinates.
     979     *
     980     * @param nodes the list of nodes representing the polygon (must be
     981     * closed, i.e. first node equals last node)
     982     * @return area and perimeter
     983     */
     984    public static AreaAndPerimeter getAreaAndPerimeter(List<Node> nodes) {
     985        if (nodes.get(0) != nodes.get(nodes.size() - 1)) {
     986            throw new IllegalArgumentException();
     987        }
     988        double area = 0;
     989        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();
     995                area += p1.east() * p2.north() - p2.east() * p1.north();
     996                perimeter += p1.distance(p2);
     997            }
     998            lastN = n;
     999        }
     1000        return new AreaAndPerimeter(Math.abs(area) / 2, perimeter);
     1001    }
    9531002}
Note: See TracChangeset for help on using the changeset viewer.