Ignore:
Timestamp:
2011-12-03T00:14:54+01:00 (12 years ago)
Author:
Don-vip
Message:

Major performance improvements in multipolygons rendering

File:
1 edited

Legend:

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

    • Property svn:mime-type deleted
    r4623 r4627  
    22package org.openstreetmap.josm.data.osm.visitor.paint.relations;
    33
    4 import java.awt.Point;
    5 import java.awt.Polygon;
    6 import java.awt.Rectangle;
     4import java.awt.geom.Path2D;
     5import java.awt.geom.Path2D.Double;
     6import java.awt.geom.PathIterator;
     7import java.awt.geom.Point2D;
     8import java.awt.geom.Rectangle2D;
    79import java.util.ArrayList;
    810import java.util.Collection;
     
    1719import org.openstreetmap.josm.data.osm.Way;
    1820import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon.PolyData.Intersection;
    19 import org.openstreetmap.josm.gui.NavigatableComponent;
    2021
    2122public class Multipolygon {
     
    170171        public enum Intersection {INSIDE, OUTSIDE, CROSSING}
    171172
    172         public Polygon poly = new Polygon();
     173        public final Path2D.Double poly;
    173174        public final boolean selected;
    174         private Point lastP;
    175         private Rectangle bounds;
    176 
    177         public PolyData(NavigatableComponent nc, JoinedWay joinedWay) {
    178             this(nc, joinedWay.getNodes(), joinedWay.isSelected());
    179         }
    180 
    181         public PolyData(NavigatableComponent nc, List<Node> nodes, boolean selected) {
     175        private Rectangle2D bounds;
     176
     177        public PolyData(JoinedWay joinedWay) {
     178            this(joinedWay.getNodes(), joinedWay.isSelected());
     179        }
     180
     181        public PolyData(List<Node> nodes, boolean selected) {
    182182            this.selected = selected;
    183             Point p = null;
     183            boolean initial = true;
     184            this.poly = new Path2D.Double();
     185            this.poly.setWindingRule(Path2D.WIND_EVEN_ODD);
    184186            for (Node n : nodes)
    185187            {
    186                 p = nc.getPoint(n);
    187                 poly.addPoint(p.x,p.y);
    188             }
    189             if (!nodes.get(0).equals(nodes.get(nodes.size() - 1))) {
    190                 p = nc.getPoint(nodes.get(0));
    191                 poly.addPoint(p.x, p.y);
    192             }
    193             lastP = p;
     188                Point2D p = n.getEastNorth();
     189                if (initial) {
     190                    poly.moveTo(p.getX(), p.getY());
     191                    initial = false;
     192                } else {
     193                    poly.lineTo(p.getX(), p.getY());
     194                }
     195            }
     196            poly.closePath();
    194197        }
    195198
    196199        public PolyData(PolyData copy) {
    197             poly = new Polygon(copy.poly.xpoints, copy.poly.ypoints, copy.poly.npoints);
    198200            this.selected = copy.selected;
    199             lastP = copy.lastP;
    200         }
    201 
    202         public Intersection contains(Polygon p) {
    203             int contains = p.npoints;
    204             for(int i = 0; i < p.npoints; ++i)
    205             {
    206                 if(poly.contains(p.xpoints[i],p.ypoints[i])) {
    207                     --contains;
    208                 }
    209             }
    210             if(contains == 0) return Intersection.INSIDE;
    211             if(contains == p.npoints) return Intersection.OUTSIDE;
     201            this.poly = (Double) copy.poly.clone();
     202        }
     203       
     204        public Intersection contains(Path2D.Double p) {
     205            int contains = 0;
     206            int total = 0;
     207            double[] coords = new double[6];
     208            for (PathIterator it = p.getPathIterator(null); !it.isDone(); it.next()) {
     209                switch (it.currentSegment(coords)) {
     210                    case PathIterator.SEG_MOVETO:
     211                    case PathIterator.SEG_LINETO:
     212                        if (poly.contains(coords[0], coords[1])) {
     213                            contains++;
     214                        }
     215                        total++;
     216                }
     217            }
     218            if (contains == total) return Intersection.INSIDE;
     219            if (contains == 0) return Intersection.OUTSIDE;
    212220            return Intersection.CROSSING;
    213221        }
    214222
    215         public void addInner(Polygon p) {
    216             for(int i = 0; i < p.npoints; ++i) {
    217                 poly.addPoint(p.xpoints[i],p.ypoints[i]);
    218             }
    219             poly.addPoint(lastP.x, lastP.y);
    220         }
    221 
    222         public Polygon get() {
     223        public void addInner(Path2D.Double inner) {
     224            poly.append(inner.getPathIterator(null), false);
     225        }
     226
     227        public Path2D.Double get() {
    223228            return poly;
    224229        }
    225230
    226         public Rectangle getBounds() {
     231        public Rectangle2D getBounds() {
    227232            if (bounds == null) {
    228                 bounds = poly.getBounds();
     233                bounds = poly.getBounds2D();
    229234            }
    230235            return bounds;
    231         }
    232 
    233         @Override
    234         public String toString() {
    235             return "Points: " + poly.npoints + " Selected: " + selected;
    236236        }
    237237    }
     
    243243    private final List<PolyData> combinedPolygons = new ArrayList<PolyData>();
    244244
    245     public Multipolygon(NavigatableComponent nc, Relation r) {
    246         load(r, nc);
    247     }
    248 
    249     private void load(Relation r, NavigatableComponent nc) {
     245    public Multipolygon(Relation r) {
     246        load(r);
     247    }
     248
     249    private void load(Relation r) {
    250250        MultipolygonRoleMatcher matcher = getMultipolygonRoleMatcher();
    251251
     
    253253        for (RelationMember m : r.getMembers()) {
    254254            if (m.getMember().isDrawable()) {
    255                 if(m.isWay()) {
     255                if (m.isWay()) {
    256256                    Way w = m.getWay();
    257257
    258                     if(w.getNodesCount() < 2) {
     258                    if (w.getNodesCount() < 2) {
    259259                        continue;
    260260                    }
    261261
    262                     if(matcher.isInnerRole(m.getRole())) {
     262                    if (matcher.isInnerRole(m.getRole())) {
    263263                        innerWays.add(w);
    264                     } else if(matcher.isOuterRole(m.getRole())) {
     264                    } else if (matcher.isOuterRole(m.getRole())) {
    265265                        outerWays.add(w);
    266266                    } else if (!m.hasRole()) {
     
    271271        }
    272272
    273         createPolygons(nc, innerWays, innerPolygons);
    274         createPolygons(nc, outerWays, outerPolygons);
     273        createPolygons(innerWays, innerPolygons);
     274        createPolygons(outerWays, outerPolygons);
    275275        if (!outerPolygons.isEmpty()) {
    276276            addInnerToOuters();
     
    278278    }
    279279
    280     private void createPolygons(NavigatableComponent nc, List<Way> ways, List<PolyData> result) {
     280    private void createPolygons(List<Way> ways, List<PolyData> result) {
    281281        List<Way> waysToJoin = new ArrayList<Way>();
    282282        for (Way way: ways) {
    283283            if (way.isClosed()) {
    284                 result.add(new PolyData(nc, way.getNodes(), way.isSelected()));
     284                result.add(new PolyData(way.getNodes(), way.isSelected()));
    285285            } else {
    286286                waysToJoin.add(way);
     
    289289
    290290        for (JoinedWay jw: joinWays(waysToJoin)) {
    291             result.add(new PolyData(nc, jw));
     291            result.add(new PolyData(jw));
    292292        }
    293293    }
     
    390390
    391391    public PolyData findOuterPolygon(PolyData inner, List<PolyData> outerPolygons) {
     392
     393        // First try to test only bbox, use precise testing only if we don't get unique result
     394        Rectangle2D innerBox = inner.getBounds();
     395        PolyData insidePolygon = null;
     396        PolyData intersectingPolygon = null;
     397        int insideCount = 0;
     398        int intersectingCount = 0;
     399
     400        for (PolyData outer: outerPolygons) {
     401            if (outer.getBounds().contains(innerBox)) {
     402                insidePolygon = outer;
     403                insideCount++;
     404            } else if (outer.getBounds().intersects(innerBox)) {
     405                intersectingPolygon = outer;
     406                intersectingCount++;
     407            }
     408        }
     409       
     410        if (insideCount == 1)
     411            return insidePolygon;
     412        else if (intersectingCount == 1)
     413            return intersectingPolygon;
     414
    392415        PolyData result = null;
    393 
    394         {// First try to test only bbox, use precise testing only if we don't get unique result
    395             Rectangle innerBox = inner.getBounds();
    396             PolyData insidePolygon = null;
    397             PolyData intersectingPolygon = null;
    398             int insideCount = 0;
    399             int intersectingCount = 0;
    400 
    401             for (PolyData outer: outerPolygons) {
    402                 if (outer.getBounds().contains(innerBox)) {
    403                     insidePolygon = outer;
    404                     insideCount++;
    405                 } else if (outer.getBounds().intersects(innerBox)) {
    406                     intersectingPolygon = outer;
    407                     intersectingCount++;
    408                 }
    409             }
    410 
    411             if (insideCount == 1)
    412                 return insidePolygon;
    413             else if (intersectingCount == 1)
    414                 return intersectingPolygon;
    415         }
    416 
    417416        for (PolyData combined : outerPolygons) {
    418417            Intersection c = combined.contains(inner.poly);
    419             if(c != Intersection.OUTSIDE)
     418            if (c != Intersection.OUTSIDE)
    420419            {
    421                 if(result == null || result.contains(combined.poly) != Intersection.INSIDE) {
     420                if (result == null || result.contains(combined.poly) != Intersection.INSIDE) {
    422421                    result = combined;
    423422                }
     
    444443            for (PolyData pdInner: innerPolygons) {
    445444                PolyData o = findOuterPolygon(pdInner, combinedPolygons);
    446                 if(o == null) {
     445                if (o == null) {
    447446                    o = outerPolygons.get(0);
    448447                }
Note: See TracChangeset for help on using the changeset viewer.