Ignore:
Timestamp:
2015-12-11T17:36:59+01:00 (8 years ago)
Author:
bastiK
Message:

mapcss partial fill: move threshold parameter ([9063]) into the mapcss style
(new property fill-extent-threshold)

  • add support for this parameter when area is unclosed
  • smaller extent for unclosed areas

(see #12104)

File:
1 edited

Legend:

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

    r9082 r9099  
    336336    private boolean showIcons;
    337337    private boolean isOutlineOnly;
    338     private double partialFillThreshold;
    339338
    340339    private Font orderFont;
     
    467466     * far to fill from the boundary towards the center of the area;
    468467     * 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)
    470470     * @param disabled If this should be drawn with a special disabled style.
    471471     * @param text The text to write on the area.
     
    492492                    }
    493493                    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));
    495495                    g.draw(area);
    496496                    g.setClip(oldClip);
     
    607607     * far to fill from the boundary towards the center of the area;
    608608     * 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
    609611     * @param disabled If this should be drawn with a special disabled style.
    610612     * @param text The text to write on the area.
    611613     */
    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) {
    613615        Multipolygon multipolygon = MultipolygonCache.getInstance().get(nc, r);
    614616        if (!r.isDisabled() && !multipolygon.getOuterWays().isEmpty()) {
     
    620622                }
    621623                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()) {
    630627                        pfClip = getPFClip(pd, extent * scale);
    631628                    }
     
    646643     * far to fill from the boundary towards the center of the area;
    647644     * 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
    648647     * @param disabled If this should be drawn with a special disabled style.
    649648     * @param text The text to write on the area.
    650649     */
    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) {
    652651        Path2D.Double pfClip = null;
    653652        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()) {
    662656                pfClip = getPFClip(w, extent * scale);
    663657            }
    664658        }
    665659        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();
    666678    }
    667679
     
    15191531        showIcons = paintSettings.getShowIconsDistance() > circum;
    15201532        isOutlineOnly = paintSettings.isOutlineOnly();
    1521         partialFillThreshold = paintSettings.getPartialFillThreshold();
    15221533        orderFont = new Font(Main.pref.get("mappaint.font", "Droid Sans"), Font.PLAIN, Main.pref.getInteger("mappaint.fontsize", 8));
    15231534
     
    15961607    }
    15971608
     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     */
    15981624    private static void buildPFClip(Path2D.Double clip, List<Node> nodes, double extent) {
    15991625        boolean initial = true;
     
    16291655    }
    16301656
     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     */
    16311674    private static EastNorth getPFDisplacedEndPoint(EastNorth p1, EastNorth p2, EastNorth p3, double extent) {
    16321675        double dx1 = p2.getX() - p1.getX();
     
    16361679        if (dx1 * dx2 + dy1 * dy2 < 0) {
    16371680            double len = Math.sqrt(dx1 * dx1 + dy1 * dy1);
     1681            if (len == 0) return null;
    16381682            double dxm = -dy1 * extent / len;
    16391683            double dym = dx1 * extent / len;
Note: See TracChangeset for help on using the changeset viewer.