Ignore:
Timestamp:
2011-01-31T14:18:47+01:00 (13 years ago)
Author:
bastiK
Message:

mappaint restructuring aimed at mapcss support:

  • area- and line style of multipolygon outer & inner ways are no longer determined by MapPaintVisitor, but the information is calculated in advance and cached
  • cache is aware of zoom level
  • z_index property to allow more fancy styles in future

Performance: when the style cache is filled, painting is the same or ~5% faster. The first painting, which includes style generation, takes ~30% longer than before. (There is potential for optimization, though.) Memory usage unchanged.

Location:
trunk/src/org/openstreetmap/josm/data
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java

    r3824 r3836  
    300300     *--------*/
    301301    public StyleCache mappaintStyle = null;
    302     public int mappaintDrawnCode = 0;
    303302
    304303    /* This should not be called from outside. Fixing the UI to add relevant
     
    307306    public void clearCached()
    308307    {
    309         mappaintDrawnCode = 0;
    310308        mappaintStyle = null;
    311309    }
     
    808806    public boolean isSelected() {
    809807        return dataSet != null && dataSet.isSelected(this);
     808    }
     809
     810    public boolean isMemberOfSelected() {
     811        if (referrers == null)
     812            return false;
     813        if (referrers instanceof OsmPrimitive)
     814            return referrers instanceof Relation && ((OsmPrimitive) referrers).isSelected();
     815        for (OsmPrimitive ref : (OsmPrimitive[]) referrers) {
     816            if (ref instanceof Relation && ref.isSelected())
     817                return true;
     818        }
     819        return false;
    810820    }
    811821
  • trunk/src/org/openstreetmap/josm/data/osm/Way.java

    r3630 r3836  
    110110        }
    111111        return false;
    112     }
    113 
    114     /* mappaint data */
    115     public boolean isMappaintArea = false;
    116     public Integer mappaintDrawnAreaCode = 0;
    117     /* end of mappaint data */
    118     @Override public void clearCached() {
    119         super.clearCached();
    120         isMappaintArea = false;
    121         mappaintDrawnAreaCode = 0;
    122112    }
    123113
  • trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/MapPaintVisitor.java

    r3831 r3836  
    33
    44import java.awt.Graphics2D;
    5 import java.awt.Polygon;
    6 import java.awt.Rectangle;
    75import java.awt.RenderingHints;
    8 import java.awt.geom.Point2D;
    96import java.util.ArrayList;
    10 import java.util.Collection;
    117import java.util.Collections;
    128import java.util.Comparator;
    13 import java.util.LinkedList;
     9import java.util.List;
    1410
    1511import org.openstreetmap.josm.Main;
    1612import org.openstreetmap.josm.data.Bounds;
    17 import org.openstreetmap.josm.data.coor.EastNorth;
    18 import org.openstreetmap.josm.data.coor.LatLon;
    1913import org.openstreetmap.josm.data.osm.BBox;
    2014import org.openstreetmap.josm.data.osm.DataSet;
     
    2216import org.openstreetmap.josm.data.osm.OsmPrimitive;
    2317import org.openstreetmap.josm.data.osm.Relation;
    24 import org.openstreetmap.josm.data.osm.RelationMember;
    2518import org.openstreetmap.josm.data.osm.Way;
    26 import org.openstreetmap.josm.data.osm.visitor.AbstractVisitor;
    27 import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon;
    28 import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon.PolyData;
    2919import org.openstreetmap.josm.gui.NavigatableComponent;
    3020import org.openstreetmap.josm.gui.mappaint.AreaElemStyle;
    3121import org.openstreetmap.josm.gui.mappaint.ElemStyle;
    3222import org.openstreetmap.josm.gui.mappaint.ElemStyles;
    33 import org.openstreetmap.josm.gui.mappaint.IconElemStyle;
    3423import org.openstreetmap.josm.gui.mappaint.LineElemStyle;
    3524import org.openstreetmap.josm.gui.mappaint.MapPaintStyles;
    36 import org.openstreetmap.josm.gui.mappaint.StyleCache;
     25import org.openstreetmap.josm.gui.mappaint.NodeElemStyle;
     26import org.openstreetmap.josm.gui.mappaint.StyleCache.StyleList;
     27import org.openstreetmap.josm.tools.Pair;
    3728
    3829public class MapPaintVisitor implements PaintVisitor {
    3930
    4031    private Graphics2D g;
     32    private boolean inactive;
    4133    private NavigatableComponent nc;
    4234
    43     private boolean zoomLevelDisplay;
    44     private boolean drawMultipolygon;
    45     private boolean drawRestriction;
    46     private boolean leftHandTraffic;
    4735    private ElemStyles styles;
    4836    private double circum;
    49     private double dist;
    50     private static int paintid = 0;
    51     private EastNorth minEN;
    52     private EastNorth maxEN;
    5337    private MapPainter painter;
    5438    private MapPaintSettings paintSettings;
    55 
    56     private boolean inactive;
    57 
    58     protected boolean isZoomOk(ElemStyle e) {
    59         if (!zoomLevelDisplay) /* show everything if the user wishes so */
    60             return true;
    61 
    62         if(e == null) /* the default for things that don't have a rule (show, if scale is smaller than 1500m) */
    63             return (circum < 1500);
    64 
    65         return !(circum >= e.maxScale || circum < e.minScale);
    66     }
    67 
    68     public StyleCache getPrimitiveStyle(OsmPrimitive osm, boolean nodefault) {
    69         if(osm.mappaintStyle == null)
    70         {
    71             if(styles != null) {
    72                 osm.mappaintStyle = styles.get(osm);
    73                 if(osm instanceof Way) {
    74                     ((Way)osm).isMappaintArea = styles.isArea(osm);
    75                 }
    76             }
    77             if (osm.mappaintStyle.equals(StyleCache.EMPTY_STYLECACHE)) {
    78                 if(osm instanceof Node)
    79                     osm.mappaintStyle = StyleCache.SIMPLE_NODE_STYLECACHE;
    80                 else if (osm instanceof Way)
    81                     osm.mappaintStyle = StyleCache.UNTAGGED_WAY_STYLECACHE;
    82             }
    83         }
    84         if (nodefault && osm.mappaintStyle.equals(StyleCache.UNTAGGED_WAY_STYLECACHE))
    85             return StyleCache.EMPTY_STYLECACHE;
    86         return osm.mappaintStyle;
    87     }
    88 
    89     public IconElemStyle getPrimitiveNodeStyle(OsmPrimitive osm) {
    90         if(osm.mappaintStyle == null && styles != null) {
    91             IconElemStyle icon = styles.getIcon(osm);
    92             osm.mappaintStyle = StyleCache.create(icon);
    93             return icon;
    94         }
    95         for (ElemStyle s : osm.mappaintStyle.getStyles()) {
    96             if (s instanceof IconElemStyle)
    97                 return (IconElemStyle) s;
    98         }
    99         return null;
    100     }
    101 
    102     public boolean isPrimitiveArea(Way osm) {
    103         if(osm.mappaintStyle == null && styles != null) {
    104             osm.mappaintStyle = styles.get(osm);
    105             osm.isMappaintArea = styles.isArea(osm);
    106         }
    107         return osm.isMappaintArea;
    108     }
    109 
    110     public void drawNode(Node n) {
    111         /* check, if the node is visible at all */
    112         EastNorth en = n.getEastNorth();
    113         if((en.east()  > maxEN.east() ) ||
    114                 (en.north() > maxEN.north()) ||
    115                 (en.east()  < minEN.east() ) ||
    116                 (en.north() < minEN.north()))
    117             return;
    118 
    119         StyleCache sc = getPrimitiveStyle(n, false);
    120 
    121         for (ElemStyle s : sc.getStyles()) {
    122             if (isZoomOk(s)) {
    123                 s.paintPrimitive(n, paintSettings, painter, data.isSelected(n), false);
    124             }
    125 
    126         }
    127     }
    128 
    129     public void drawWay(Way w, int fillAreas) {
    130         if(w.getNodesCount() < 2)
    131             return;
    132 
    133         if (w.hasIncompleteNodes())
    134             return;
    135 
    136         /* check, if the way is visible at all */
    137         double minx = 10000;
    138         double maxx = -10000;
    139         double miny = 10000;
    140         double maxy = -10000;
    141 
    142         for (Node n : w.getNodes())
    143         {
    144             if(n.getEastNorth().east() > maxx) {
    145                 maxx = n.getEastNorth().east();
    146             }
    147             if(n.getEastNorth().north() > maxy) {
    148                 maxy = n.getEastNorth().north();
    149             }
    150             if(n.getEastNorth().east() < minx) {
    151                 minx = n.getEastNorth().east();
    152             }
    153             if(n.getEastNorth().north() < miny) {
    154                 miny = n.getEastNorth().north();
    155             }
    156         }
    157 
    158         if ((minx > maxEN.east()) ||
    159                 (miny > maxEN.north()) ||
    160                 (maxx < minEN.east()) ||
    161                 (maxy < minEN.north()))
    162             return;
    163 
    164         StyleCache sc = getPrimitiveStyle(w, false);
    165         for (ElemStyle s : sc.getStyles()) {
    166             if(!isZoomOk(s))
    167                 return;
    168             if (fillAreas > dist || !(s instanceof AreaElemStyle)) {
    169                 s.paintPrimitive(w, paintSettings, painter, data.isSelected(w), false);
    170             }
    171         }
    172     }
    173 
    174     public void paintUnselectedRelation(Relation r) {
    175         if (drawMultipolygon && "multipolygon".equals(r.get("type")))
    176             drawMultipolygon(r);
    177         else if (drawRestriction && "restriction".equals(r.get("type"))) {
    178             IconElemStyle nodeStyle = getPrimitiveNodeStyle(r);
    179             if (nodeStyle != null) {
    180                 painter.drawRestriction(r, leftHandTraffic, nodeStyle);
    181             }
    182         }
    183     }
    184 
    185     public boolean drawMultipolygon(Relation r) {
    186         boolean drawn = false;
    187 
    188         Multipolygon multipolygon = new Multipolygon(nc);
    189         multipolygon.load(r);
    190 
    191         AreaElemStyle areaStyle = null;
    192         LineElemStyle lineStyle = null;
    193         for (ElemStyle s : getPrimitiveStyle(r, false).getStyles()) {
    194             if (s instanceof AreaElemStyle) {
    195                 areaStyle = (AreaElemStyle) s;
    196             } else if (s instanceof LineElemStyle) {
    197                 lineStyle = (LineElemStyle) s;
    198             }
    199         }
    200 
    201         boolean disabled = r.isDisabled();
    202         // If area style was not found for relation then use style of ways
    203         if(styles != null && areaStyle == null) {
    204             for (Way w : multipolygon.getOuterWays()) {
    205                 for (ElemStyle s : styles.getArea(w).getStyles()) {
    206                     if (s instanceof AreaElemStyle) {
    207                         areaStyle = (AreaElemStyle) s;
    208                     } else if (s instanceof LineElemStyle) {
    209                         lineStyle = (LineElemStyle) s;
    210                     }
    211                 }
    212                 disabled = disabled || w.isDisabled();
    213                 if(areaStyle != null) {
    214                     break;
    215                 }
    216             }
    217         }
    218 
    219         if (areaStyle != null) {
    220             boolean zoomok = isZoomOk(areaStyle);
    221             boolean visible = false;
    222 
    223             drawn = true;
    224 
    225             if(zoomok && !disabled && !multipolygon.getOuterWays().isEmpty()) {
    226                 for (PolyData pd : multipolygon.getCombinedPolygons()) {
    227                     Polygon p = pd.get();
    228                     if(!isPolygonVisible(p)) {
    229                         continue;
    230                     }
    231 
    232                     boolean selected = pd.selected || data.isSelected(r);
    233                     painter.drawArea(p, selected ? paintSettings.getRelationSelectedColor()
    234                                 : areaStyle.color, painter.getAreaName(r));
    235                     visible = true;
    236                 }
    237             }
    238 
    239             if(!visible)
    240                 return drawn;
    241             for (Way wInner : multipolygon.getInnerWays()) {
    242                 StyleCache inner = getPrimitiveStyle(wInner, true);
    243                 AreaElemStyle innerArea = null;
    244                 for (ElemStyle s : inner.getStyles()) {
    245                     if (s instanceof AreaElemStyle) {
    246                         innerArea = (AreaElemStyle) s;
    247                         break;
    248                     }
    249                 }
    250 
    251                 if(inner.getStyles().isEmpty()) {
    252                     if (data.isSelected(wInner) || disabled)
    253                         continue;
    254                     if(zoomok && (wInner.mappaintDrawnCode != paintid || multipolygon.getOuterWays().isEmpty())) {
    255                         lineStyle.paintPrimitive(wInner, paintSettings,
    256                                 painter, (data.isSelected(wInner) || data.isSelected(r)), false);
    257                     }
    258                     wInner.mappaintDrawnCode = paintid;
    259                 }
    260                 else {
    261                     if(areaStyle.equals(innerArea)) {
    262                         wInner.mappaintDrawnAreaCode = paintid;
    263                        
    264                         if(!data.isSelected(wInner)) {
    265                             wInner.mappaintDrawnCode = paintid;
    266                             drawWay(wInner, 0);
    267                         }
    268                     }
    269                 }
    270             }
    271             for (Way wOuter : multipolygon.getOuterWays()) {
    272                 StyleCache outer = getPrimitiveStyle(wOuter, true);
    273                 boolean hasOuterArea = false;
    274                 for (ElemStyle s : outer.getStyles()) {
    275                     if (s instanceof AreaElemStyle) {
    276                         hasOuterArea = true;
    277                         break;
    278                     }
    279                 }
    280 
    281                 if (outer.getStyles().isEmpty()) {
    282                     // Selected ways are drawn at the very end
    283                     if (data.isSelected(wOuter))
    284                         continue;
    285                     if(zoomok) {
    286                         lineStyle.paintPrimitive(wOuter, paintSettings, painter,
    287                             (data.isSelected(wOuter) || data.isSelected(r)), r.isSelected());
    288                     }
    289                     wOuter.mappaintDrawnCode = paintid;
    290                 } else if (hasOuterArea) {
    291                     wOuter.mappaintDrawnAreaCode = paintid;
    292                     if(!data.isSelected(wOuter)) {
    293                         wOuter.mappaintDrawnCode = paintid;
    294                         drawWay(wOuter, 0);
    295                     }
    296                 }
    297             }
    298         }
    299         return drawn;
    300     }
    301 
    302     protected boolean isPolygonVisible(Polygon polygon) {
    303         Rectangle bounds = polygon.getBounds();
    304         if (bounds.width == 0 && bounds.height == 0) return false;
    305         if (bounds.x > nc.getWidth()) return false;
    306         if (bounds.y > nc.getHeight()) return false;
    307         if (bounds.x + bounds.width < 0) return false;
    308         if (bounds.y + bounds.height < 0) return false;
    309         return true;
    310     }
    311 
    312     protected Point2D getCentroid(Polygon p)
    313     {
    314         double cx = 0.0, cy = 0.0, a = 0.0;
    315 
    316         // usually requires points[0] == points[npoints] and can then use i+1 instead of j.
    317         // Faked it slowly using j.  If this is really gets used, this should be fixed.
    318         for (int i = 0;  i < p.npoints;  i++) {
    319             int j = i+1 == p.npoints ? 0 : i+1;
    320             a += (p.xpoints[i] * p.ypoints[j]) - (p.ypoints[i] * p.xpoints[j]);
    321             cx += (p.xpoints[i] + p.xpoints[j]) * (p.xpoints[i] * p.ypoints[j] - p.ypoints[i] * p.xpoints[j]);
    322             cy += (p.ypoints[i] + p.ypoints[j]) * (p.xpoints[i] * p.ypoints[j] - p.ypoints[i] * p.xpoints[j]);
    323         }
    324         return new Point2D.Double(cx / (3.0*a), cy / (3.0*a));
    325     }
    326 
    327     protected double getArea(Polygon p)
    328     {
    329         double sum = 0.0;
    330 
    331         // usually requires points[0] == points[npoints] and can then use i+1 instead of j.
    332         // Faked it slowly using j.  If this is really gets used, this should be fixed.
    333         for (int i = 0;  i < p.npoints;  i++) {
    334             int j = i+1 == p.npoints ? 0 : i+1;
    335             sum = sum + (p.xpoints[i] * p.ypoints[j]) - (p.ypoints[i] * p.xpoints[j]);
    336         }
    337         return Math.abs(sum/2.0);
    338     }
    339 
    340     DataSet data;
    341 
    342     <T extends OsmPrimitive> Collection<T> selectedLast(final DataSet data, Collection <T> prims) {
    343         ArrayList<T> sorted = new ArrayList<T>(prims);
    344         Collections.sort(sorted,
    345                 new Comparator<T>() {
    346             public int compare(T o1, T o2) {
    347                 boolean s1 = data.isSelected(o1);
    348                 boolean s2 = data.isSelected(o2);
    349                 if (s1 && !s2)
    350                     return 1;
    351                 if (!s1 && s2)
    352                     return -1;
    353                 return o1.compareTo(o2);
    354             }
    355         });
    356         return sorted;
    357     }
    358 
    359     /* Shows areas before non-areas */
     39    private DataSet data;
     40
     41    private class StyleCollector {
     42        private List<Pair<ElemStyle, OsmPrimitive>> styleElems;
     43        protected boolean memberSelected = false;
     44        private Class klass;
     45
     46        public StyleCollector(Class<?> klass) {
     47            styleElems = new ArrayList<Pair<ElemStyle, OsmPrimitive>>();
     48            this.klass = klass;
     49        }
     50
     51        public void add(OsmPrimitive osm) {
     52            StyleList sl = styles.get(osm, circum, nc);
     53            for (ElemStyle s : sl) {
     54                if (klass.isInstance(s)) {
     55                    styleElems.add(new Pair<ElemStyle, OsmPrimitive>(s, osm));
     56                }
     57            }
     58        }
     59
     60        public void drawAll() {
     61            Collections.sort(styleElems, STYLE_COMPARATOR);
     62            for (Pair<ElemStyle, OsmPrimitive> p : styleElems) {
     63                p.a.paintPrimitive(p.b, paintSettings, painter, data.isSelected(p.b), memberSelected);
     64            }
     65        }
     66
     67        public boolean isMemberSelected() {
     68            return memberSelected;
     69        }
     70
     71        public void setMemberSelected(boolean memberSelected) {
     72            this.memberSelected = memberSelected;
     73        }
     74    }
     75
     76    private final static Comparator<Pair<ElemStyle, OsmPrimitive>> STYLE_COMPARATOR = new Comparator<Pair<ElemStyle, OsmPrimitive>>() {
     77        @Override
     78        public int compare(Pair<ElemStyle, OsmPrimitive> p1, Pair<ElemStyle, OsmPrimitive> p2) {
     79            int d1 = Float.compare(p1.a.z_index, p2.a.z_index);
     80            if (d1 != 0)
     81                return d1;
     82            if (p1.a == NodeElemStyle.SIMPLE_NODE_ELEMSTYLE && p2.a != NodeElemStyle.SIMPLE_NODE_ELEMSTYLE)
     83                return 1;
     84            if (p1.a != NodeElemStyle.SIMPLE_NODE_ELEMSTYLE && p2.a == NodeElemStyle.SIMPLE_NODE_ELEMSTYLE)
     85                return -1;
     86            // newer primitives to the front
     87            long id = p1.b.getUniqueId() - p2.b.getUniqueId();
     88            if (id > 0)
     89                return 1;
     90            if (id < 0)
     91                return -1;
     92            return Float.compare(p1.a.object_z_index, p2.a.object_z_index);
     93        }
     94    };
     95
    36096    public void visitAll(final DataSet data, boolean virtual, Bounds bounds) {
    36197        //long start = System.currentTimeMillis();
    36298        BBox bbox = new BBox(bounds);
    36399        this.data = data;
    364         ++paintid;
    365 
    366         int fillAreas = Main.pref.getInteger("mappaint.fillareas", 10000000);
    367         LatLon ll1 = nc.getLatLon(0, 0);
    368         LatLon ll2 = nc.getLatLon(100, 0);
    369         dist = ll1.greatCircleDistance(ll2);
    370 
    371         zoomLevelDisplay = Main.pref.getBoolean("mappaint.zoomLevelDisplay", false);
     100
     101        styles = MapPaintStyles.getStyles();
     102
    372103        circum = nc.getDist100Pixel();
    373         styles = MapPaintStyles.getStyles();
    374         drawMultipolygon = Main.pref.getBoolean("mappaint.multipolygon", true);
    375         drawRestriction = Main.pref.getBoolean("mappaint.restriction", true);
    376         leftHandTraffic = Main.pref.getBoolean("mappaint.lefthandtraffic", false);
    377         minEN = nc.getEastNorth(0, nc.getHeight() - 1);
    378         maxEN = nc.getEastNorth(nc.getWidth() - 1, 0);
     104        boolean drawArea = circum <= Main.pref.getInteger("mappaint.fillareas", 10000000);
     105        boolean drawMultipolygon = drawArea && Main.pref.getBoolean("mappaint.multipolygon", true);
     106        styles.setDrawMultipolygon(drawMultipolygon);
     107        boolean drawRestriction = Main.pref.getBoolean("mappaint.restriction", true);
     108        boolean leftHandTraffic = Main.pref.getBoolean("mappaint.lefthandtraffic", false);
    379109
    380110        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
     
    383113
    384114        this.paintSettings = MapPaintSettings.INSTANCE;
    385         this.painter = new MapPainter(paintSettings, g, inactive, nc, virtual, dist, circum);
    386 
    387         if (fillAreas > dist && styles != null && styles.hasAreas()) {
    388             Collection<Way> noAreaWays = new LinkedList<Way>();
    389             final Collection<Way> ways = data.searchWays(bbox);
    390 
    391             /*** disabled ***/
    392             for (final Way osm : ways) {
    393                 if (osm.isDisabled() && osm.isDrawable() && osm.mappaintDrawnCode != paintid) {
    394                     drawWay(osm, 0);
    395                     osm.mappaintDrawnCode = paintid;
    396                 }
    397             }
    398 
    399             /*** RELATIONS ***/
    400             for (final Relation osm: data.searchRelations(bbox)) {
    401                 if (osm.isDrawable()) {
    402                     paintUnselectedRelation(osm);
    403                 }
    404             }
    405 
    406             /*** AREAS ***/
    407             for (final Way osm : selectedLast(data, ways)) {
    408                 if (osm.isDrawable() && osm.mappaintDrawnCode != paintid) {
    409                     if (isPrimitiveArea(osm)) {
    410                         if(osm.mappaintDrawnAreaCode != paintid)
    411                             drawWay(osm, fillAreas);
    412                     } else if(!data.isSelected(osm)) {
    413                         noAreaWays.add(osm);
    414                     }
    415                 }
    416             }
    417 
    418             /*** WAYS ***/
    419             for (final Way osm : noAreaWays) {
    420                 drawWay(osm, 0);
    421                 osm.mappaintDrawnCode = paintid;
    422             }
    423         } else {
    424             drawMultipolygon = false;
    425             final Collection<Way> ways = data.searchWays(bbox);
    426 
    427             /*** WAYS (disabled)  ***/
    428             for (final Way way: ways) {
    429                 if (way.isDisabled() && way.isDrawable() && !data.isSelected(way)) {
    430                     drawWay(way, 0);
    431                     way.mappaintDrawnCode = paintid;
    432                 }
    433             }
    434 
    435             /*** RELATIONS ***/
    436             for (final Relation osm: data.searchRelations(bbox)) {
    437                 if (osm.isDrawable()) {
    438                     paintUnselectedRelation(osm);
    439                 }
    440             }
    441 
    442             /*** WAYS (filling disabled)  ***/
    443             for (final Way way: ways) {
    444                 if (way.isDrawable() && !data.isSelected(way)) {
    445                     drawWay(way, 0);
    446                 }
    447             }
    448         }
    449 
    450         /*** SELECTED  ***/
    451         for (final OsmPrimitive osm : data.getSelected()) {
    452             if (osm.isUsable() && !(osm instanceof Node) && (osm instanceof Relation || osm.mappaintDrawnCode != paintid)) {
    453                 osm.visit(new AbstractVisitor() {
    454                     public void visit(Way w) {
    455                         drawWay(w, 0);
    456                     }
    457 
    458                     public void visit(Node n) {
    459                         // Selected nodes are painted in following part
    460                     }
    461 
    462                     public void visit(Relation r) {
    463                         for (RelationMember m : r.getMembers()) {
    464                             OsmPrimitive osm = m.getMember();
    465                             if(osm.isDrawable()) {
    466                                 StyleCache sc = getPrimitiveStyle(m.getMember(), false);
    467                                 if(osm instanceof Way)
    468                                 {
    469                                     for (ElemStyle s : sc.getStyles()) {
    470                                         if (!(s instanceof AreaElemStyle)) {
    471                                             s.paintPrimitive(osm, paintSettings, painter, data.isSelected(osm), true);
    472                                         }
    473                                     }
    474                                 }
    475                                 else if(osm instanceof Node)
    476                                 {
    477                                     for (ElemStyle s : sc.getStyles()) {
    478                                         if (isZoomOk(s)) {
    479                                             s.paintPrimitive(osm, paintSettings, painter, data.isSelected(osm), true);
    480                                         }
    481                                     }
    482                                 }
    483                                 osm.mappaintDrawnCode = paintid;
    484                             }
    485                         }
    486                     }
    487                 });
    488             }
    489         }
    490 
    491         /*** NODES ***/
    492         for (final Node osm: data.searchNodes(bbox)) {
    493             if (!osm.isIncomplete() && !osm.isDeleted() && (data.isSelected(osm) || !osm.isDisabledAndHidden())
    494                     && osm.mappaintDrawnCode != paintid) {
    495                 drawNode(osm);
    496             }
    497         }
     115        this.painter = new MapPainter(paintSettings, g, inactive, nc, virtual, circum, leftHandTraffic);
     116
     117        StyleCollector scDisabledLines = new StyleCollector(LineElemStyle.class);
     118        StyleCollector scSelectedLines = new StyleCollector(LineElemStyle.class);
     119        StyleCollector scSelectedAreas = new StyleCollector(AreaElemStyle.class);
     120        StyleCollector scMemberLines = new StyleCollector(LineElemStyle.class);
     121        scMemberLines.setMemberSelected(true);
     122        StyleCollector scNormalAreas = new StyleCollector(AreaElemStyle.class);
     123        StyleCollector scNormalLines = new StyleCollector(LineElemStyle.class);
     124        for (final Way w : data.searchWays(bbox)) {
     125            if (w.isDrawable()) {
     126                if (w.isDisabled()) {
     127                    scDisabledLines.add(w);
     128                } else if (w.isSelected()) {
     129                    scSelectedLines.add(w);
     130                    if (drawArea) {
     131                        scSelectedAreas.add(w);
     132                    }
     133                } else if (w.isMemberOfSelected()) {
     134                    scMemberLines.add(w);
     135                    if (drawArea) {
     136                        scNormalAreas.add(w);
     137                    }
     138                } else {
     139                    scNormalLines.add(w);
     140                    if (drawArea) {
     141                        scNormalAreas.add(w);
     142                    }
     143                }
     144            }
     145        }
     146        scDisabledLines.drawAll();
     147        scDisabledLines = null;
     148
     149        StyleCollector scDisabledNodes = new StyleCollector(NodeElemStyle.class);
     150        StyleCollector scSelectedNodes = new StyleCollector(NodeElemStyle.class);
     151        StyleCollector scMemberNodes = new StyleCollector(NodeElemStyle.class);
     152        scMemberNodes.setMemberSelected(true);
     153        StyleCollector scNormalNodes = new StyleCollector(NodeElemStyle.class);
     154        for (final Node n: data.searchNodes(bbox)) {
     155            if (n.isDrawable()) {
     156                if (n.isDisabled()) {
     157                    scDisabledNodes.add(n);
     158                } else if (n.isSelected()) {
     159                    scSelectedNodes.add(n);
     160                } else if (n.isMemberOfSelected()) {
     161                    scMemberNodes.add(n);
     162                } else {
     163                    scNormalNodes.add(n);
     164                }
     165            }
     166        }
     167        scDisabledNodes.drawAll();
     168        scDisabledNodes = null;
     169
     170        StyleCollector scDisabledRestrictions = new StyleCollector(NodeElemStyle.class);
     171        StyleCollector scNormalRestrictions = new StyleCollector(NodeElemStyle.class);
     172        StyleCollector scSelectedRestrictions = new StyleCollector(NodeElemStyle.class);
     173        for (Relation r: data.searchRelations(bbox)) {
     174            if (r.isDrawable()) {
     175                if (r.isDisabled()) {
     176                    if (drawRestriction) {
     177                        scDisabledRestrictions.add(r);
     178                    }
     179                } else if (r.isSelected()) {
     180                    if (drawMultipolygon) {
     181                        scSelectedAreas.add(r);
     182                    }
     183                    if (drawRestriction) {
     184                        scSelectedRestrictions.add(r);
     185                    }
     186                } else {
     187                    if (drawMultipolygon) {
     188                        scNormalAreas.add(r);
     189                    }
     190                    if (drawRestriction) {
     191                        scNormalRestrictions.add(r);
     192                    }
     193                }
     194            }
     195        }
     196        scDisabledRestrictions.drawAll();
     197        scDisabledRestrictions = null;
     198
     199        scNormalAreas.drawAll();
     200        scSelectedAreas.drawAll();
     201        scNormalLines.drawAll();
     202        scMemberLines.drawAll();
     203        scSelectedLines.drawAll();
     204        scNormalNodes.drawAll();
     205        scNormalRestrictions.drawAll();
     206        scMemberNodes.drawAll();
     207        scSelectedRestrictions.drawAll();
     208        scSelectedNodes.drawAll();
    498209
    499210        painter.drawVirtualNodes(data.searchWays(bbox));
    500         //System.err.println("PAINTING TOOK "+(System.currentTimeMillis() - start));
     211        //System.err.println("PAINTING TOOK "+(System.currentTimeMillis() - start)+ " (at scale "+circum+")");
    501212    }
    502213
  • trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/MapPainter.java

    r3831 r3836  
    2626import org.openstreetmap.josm.data.osm.RelationMember;
    2727import org.openstreetmap.josm.data.osm.Way;
     28import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon;
     29import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon.PolyData;
    2830import org.openstreetmap.josm.gui.NavigatableComponent;
    29 import org.openstreetmap.josm.gui.mappaint.IconElemStyle;
     31import org.openstreetmap.josm.gui.mappaint.NodeElemStyle;
    3032import org.openstreetmap.josm.tools.ImageProvider;
    3133import org.openstreetmap.josm.tools.LanguageInfo;
     
    5860    private final double circum;
    5961
     62    private final boolean leftHandTraffic;
     63
    6064    private final Collection<String> regionalNameOrder;
    6165
     
    6670    public MapPainter(MapPaintSettings settings, Graphics2D g,
    6771        boolean inactive, NavigatableComponent nc, boolean virtual,
    68         double dist, double circum) {
    69 
     72        double circum, boolean leftHandTraffic)
     73    {
    7074        this.g = g;
    7175        this.inactive = inactive;
    7276        this.nc = nc;
    73         this.useStrokes = settings.getUseStrokesDistance() > dist;
    74         this.showNames = settings.getShowNamesDistance() > dist;
    75         this.showIcons = settings.getShowIconsDistance() > dist;
     77        this.useStrokes = settings.getUseStrokesDistance() > circum;
     78        this.showNames = settings.getShowNamesDistance() > circum;
     79        this.showIcons = settings.getShowIconsDistance() > circum;
    7680        this.outlineOnly = settings.isOutlineOnly();
    7781
     
    9397        this.regionalNameOrder = Main.pref.getCollection("mappaint.nameOrder", Arrays.asList(names));
    9498        this.circum = circum;
    95     }
    96 
    97     public void drawWay(Way way, Color color, int width, float dashed[], Color dashedColor, boolean showDirection,
     99        this.leftHandTraffic = leftHandTraffic;
     100    }
     101
     102    public void drawWay(Way way, Color color, float width, float dashed[], Color dashedColor, boolean showDirection,
    98103            boolean reversedDirection, boolean showHeadArrowOnly) {
    99104
     
    154159    }
    155160
    156     private void displaySegments(GeneralPath path, GeneralPath arrows, Color color, int width, float dashed[], Color dashedColor) {
     161    private void displaySegments(GeneralPath path, GeneralPath arrows, Color color, float width, float dashed[], Color dashedColor) {
    157162        g.setColor(inactive ? inactiveColor : color);
    158163        if (useStrokes) {
    159             if (dashed.length > 0) {
     164            if (dashed == null || dashed.length > 0) {
    160165                g.setStroke(new BasicStroke(width,BasicStroke.CAP_BUTT,BasicStroke.JOIN_ROUND,0, dashed,0));
    161166            } else {
     
    168173        if(!inactive && useStrokes && dashedColor != null) {
    169174            g.setColor(dashedColor);
    170             if (dashed.length > 0) {
     175            if (dashed == null || dashed.length > 0) {
    171176                float[] dashedOffset = new float[dashed.length];
    172177                System.arraycopy(dashed, 1, dashedOffset, 0, dashed.length - 1);
     
    319324    }
    320325
     326    public void drawArea(Relation r, Color color, String name) {
     327        Multipolygon multipolygon = new Multipolygon(nc);
     328        multipolygon.load(r);
     329        if(!r.isDisabled() && !multipolygon.getOuterWays().isEmpty()) {
     330            for (PolyData pd : multipolygon.getCombinedPolygons()) {
     331                Polygon p = pd.get();
     332                if(!isPolygonVisible(p)) {
     333                    continue;
     334                }
     335                drawArea(p, color, getAreaName(r));
     336            }
     337        }
     338    }
     339
     340    private boolean isPolygonVisible(Polygon polygon) {
     341        Rectangle bounds = polygon.getBounds();
     342        if (bounds.width == 0 && bounds.height == 0) return false;
     343        if (bounds.x > nc.getWidth()) return false;
     344        if (bounds.y > nc.getHeight()) return false;
     345        if (bounds.x + bounds.width < 0) return false;
     346        if (bounds.y + bounds.height < 0) return false;
     347        return true;
     348    }
     349
    321350    public void drawRestriction(ImageIcon icon, Point pVia, double vx, double vx2, double vy, double vy2, double iconAngle, boolean selected) {
    322351        /* rotate icon with direction last node in from to */
     
    334363    }
    335364
    336     public void drawRestriction(Relation r, boolean leftHandTraffic, IconElemStyle icon) {
     365    public void drawRestriction(Relation r, NodeElemStyle icon) {
    337366
    338367        Way fromWay = null;
  • trunk/src/org/openstreetmap/josm/data/validation/tests/MultipolygonTest.java

    r3825 r3836  
    2626import org.openstreetmap.josm.gui.mappaint.ElemStyles;
    2727import org.openstreetmap.josm.gui.mappaint.MapPaintStyles;
    28 import org.openstreetmap.josm.gui.mappaint.StyleCache;
    2928import org.openstreetmap.josm.gui.mappaint.xml.AreaPrototype;
    3029
     
    4746    private final List<List<Node>> nonClosedWays = new ArrayList<List<Node>>();
    4847
     48    private final double SCALE = 1.0; // arbitrary scale - we could test every possible scale, but this should suffice
     49
    4950    public MultipolygonTest() {
    5051        super(tr("Multipolygon"),
     
    115116    public void visit(Way w) {
    116117        if (styles != null && !w.isClosed()) {
    117             AreaPrototype e = styles.getAreaProto(w);
    118             if (e != null && ! e.closed) {
    119                 errors.add( new TestError(this, Severity.WARNING, tr("Area style way is not closed"), NOT_CLOSED,  w));
     118            for (ElemStyle s : styles.generateStyles(w, SCALE, null, false).a) {
     119                if (s instanceof AreaElemStyle) {
     120                    errors.add( new TestError(this, Severity.WARNING, tr("Area style way is not closed"), NOT_CLOSED,  w));
     121                    break;
     122                }
    120123            }
    121124        }
     
    143146            List<List<Node>> outerWays = joinWays(polygon.getOuterWays());
    144147            if (styles != null) {
    145                 StyleCache sc = styles.get(r);
    146148
    147149                AreaElemStyle area = null;
    148                 for (ElemStyle s : sc.getStyles()) {
     150                for (ElemStyle s : styles.generateStyles(r, SCALE, null, false).a) {
    149151                    if (s instanceof AreaElemStyle) {
    150152                        area = (AreaElemStyle) s;
     
    155157                if (area == null) {
    156158                    errors.add( new TestError(this, Severity.OTHER, tr("No style in multipolygon relation"),
    157                     NO_STYLE_POLYGON, r));
     159                            NO_STYLE_POLYGON, r));
    158160                    for (Way w : polygon.getOuterWays()) {
    159161
    160                         for (ElemStyle s : styles.getArea(w).getStyles()) {
     162                        for (ElemStyle s : styles.generateStyles(r, SCALE, null, true).a) {
    161163                            if (s instanceof AreaElemStyle) {
    162164                                area = (AreaElemStyle) s;
     
    173175                    for (Way wInner : polygon.getInnerWays()) {
    174176                        AreaElemStyle areaInner = null;
    175                         for (ElemStyle s : styles.get(wInner).getStyles()) {
     177                        for (ElemStyle s : styles.generateStyles(wInner, SCALE, null, false).a) {
    176178                            if (s instanceof AreaElemStyle) {
    177179                                areaInner = (AreaElemStyle) s;
     
    185187                            l.add(wInner);
    186188                            errors.add( new TestError(this, Severity.WARNING, tr("Style for inner way equals multipolygon"),
    187                             INNER_STYLE_MISMATCH, l, Collections.singletonList(wInner)));
     189                                    INNER_STYLE_MISMATCH, l, Collections.singletonList(wInner)));
    188190                        }
    189191                    }
    190192                    for (Way wOuter : polygon.getOuterWays()) {
    191193                        AreaElemStyle areaOuter = null;
    192                         for (ElemStyle s : styles.get(wOuter).getStyles()) {
     194                        for (ElemStyle s : styles.generateStyles(wOuter, SCALE, null, false).a) {
    193195                            if (s instanceof AreaElemStyle) {
    194196                                areaOuter = (AreaElemStyle) s;
Note: See TracChangeset for help on using the changeset viewer.