Changeset 4630 in josm


Ignore:
Timestamp:
2011-12-04T00:30:57+01:00 (12 years ago)
Author:
Don-vip
Message:

see #6987 - final (?) performance tweaks on multipolygon cache

Location:
trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/relations
Files:
2 edited

Legend:

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

    r4629 r4630  
    1010import java.util.Collection;
    1111import java.util.Collections;
     12import java.util.HashSet;
     13import java.util.Iterator;
    1214import java.util.List;
     15import java.util.Set;
    1316
    1417import org.openstreetmap.josm.Main;
    1518import org.openstreetmap.josm.data.Preferences.PreferenceChangeEvent;
    1619import org.openstreetmap.josm.data.Preferences.PreferenceChangedListener;
     20import org.openstreetmap.josm.data.osm.DataSet;
    1721import org.openstreetmap.josm.data.osm.Node;
     22import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
    1823import org.openstreetmap.josm.data.osm.Relation;
    1924import org.openstreetmap.josm.data.osm.RelationMember;
    2025import org.openstreetmap.josm.data.osm.Way;
    2126import org.openstreetmap.josm.data.osm.event.NodeMovedEvent;
     27import org.openstreetmap.josm.data.osm.event.WayNodesChangedEvent;
    2228import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon.PolyData.Intersection;
    2329
     
    150156    public static class JoinedWay {
    151157        private final List<Node> nodes;
     158        private final Collection<Long> wayIds;
    152159        private final boolean selected;
    153160
    154         public JoinedWay(List<Node> nodes, boolean selected) {
     161        public JoinedWay(List<Node> nodes, Collection<Long> wayIds, boolean selected) {
    155162            this.nodes = nodes;
     163            this.wayIds = wayIds;
    156164            this.selected = selected;
    157165        }
     
    161169        }
    162170
     171        public Collection<Long> getWayIds() {
     172            return wayIds;
     173        }
     174
    163175        public boolean isSelected() {
    164176            return selected;
     
    173185        public enum Intersection {INSIDE, OUTSIDE, CROSSING}
    174186
    175         public final Path2D.Double poly;
     187        private final Path2D.Double poly;
    176188        public boolean selected;
    177189        private Rectangle2D bounds;
    178         private final Collection<Way> ways;
     190        private final Collection<Long> wayIds;
    179191        private final List<Node> nodes;
    180192        private final List<PolyData> inners;
    181193
    182         public PolyData(JoinedWay joinedWay, Collection<Way> refWays) {
    183             this(joinedWay.getNodes(), joinedWay.isSelected(), refWays);
    184         }
    185 
    186         public PolyData(List<Node> nodes, boolean selected, Collection<Way> refWays) {
    187             this.ways = Collections.unmodifiableCollection(refWays);
    188             this.nodes = Collections.unmodifiableList(nodes);
     194        public PolyData(Way closedWay) {
     195            this(closedWay.getNodes(), closedWay.isSelected(), Collections.singleton(closedWay.getId()));
     196        }
     197
     198        public PolyData(JoinedWay joinedWay) {
     199            this(joinedWay.getNodes(), joinedWay.isSelected(), joinedWay.getWayIds());
     200        }
     201
     202        private PolyData(List<Node> nodes, boolean selected, Collection<Long> wayIds) {
     203            this.wayIds = Collections.unmodifiableCollection(wayIds);
     204            this.nodes = nodes;
    189205            this.selected = selected;
    190206            this.inners = new ArrayList<Multipolygon.PolyData>();
     
    196212        private void buildPoly() {
    197213            boolean initial = true;
    198             for (Node n : nodes)
    199             {
     214            for (Node n : nodes) {
    200215                Point2D p = n.getEastNorth();
    201216                if (initial) {
     
    215230            this.selected = copy.selected;
    216231            this.poly = (Double) copy.poly.clone();
    217             this.ways = Collections.unmodifiableCollection(copy.ways);
    218             this.nodes = Collections.unmodifiableList(copy.nodes);
     232            this.wayIds = Collections.unmodifiableCollection(copy.wayIds);
     233            this.nodes = new ArrayList<Node>(copy.nodes);
    219234            this.inners = new ArrayList<Multipolygon.PolyData>(copy.inners);
    220235        }
     
    259274        }
    260275       
    261         public Collection<Way> getWays() {
    262             return ways;
     276        public Collection<Long> getWayIds() {
     277            return wayIds;
     278        }
     279       
     280        private void resetNodes() {
     281            if (!nodes.isEmpty()) {
     282                DataSet ds = nodes.get(0).getDataSet();
     283                nodes.clear();
     284                if (wayIds.size() == 1) {
     285                    Way w = (Way) ds.getPrimitiveById(wayIds.iterator().next(), OsmPrimitiveType.WAY);
     286                    nodes.addAll(w.getNodes());
     287                } else {
     288                    List<Way> waysToJoin = new ArrayList<Way>();
     289                    for (Iterator<Long> it = wayIds.iterator(); it.hasNext(); ) {
     290                        waysToJoin.add((Way) ds.getPrimitiveById(it.next(), OsmPrimitiveType.WAY));
     291                    }
     292                    nodes.addAll(joinWays(waysToJoin).iterator().next().getNodes());
     293                }
     294                resetPoly();
     295            }
    263296        }
    264297       
     
    280313            if (nodes.contains(n) || innerChanged) {
    281314                resetPoly();
     315            }
     316        }
     317       
     318        public void wayNodesChanged(WayNodesChangedEvent event) {
     319            final Long wayId = event.getChangedWay().getId();
     320            boolean innerChanged = false;
     321            for (PolyData inner : inners) {
     322                if (inner.wayIds.contains(wayId)) {
     323                    inner.resetNodes();
     324                    innerChanged = true;
     325                }
     326            }
     327            if (wayIds.contains(wayId) || innerChanged) {
     328                resetNodes();
    282329            }
    283330        }
     
    329376        for (Way way: ways) {
    330377            if (way.isClosed()) {
    331                 result.add(new PolyData(way.getNodes(), way.isSelected(), Collections.singleton(way)));
     378                result.add(new PolyData(way));
    332379            } else {
    333380                waysToJoin.add(way);
     
    336383
    337384        for (JoinedWay jw: joinWays(waysToJoin)) {
    338             result.add(new PolyData(jw, waysToJoin));
    339         }
    340     }
    341 
    342     public static Collection<JoinedWay> joinWays(Collection<Way> join)
     385            result.add(new PolyData(jw));
     386        }
     387    }
     388
     389    public static Collection<JoinedWay> joinWays(Collection<Way> waysToJoin)
    343390    {
    344         Collection<JoinedWay> res = new ArrayList<JoinedWay>();
    345         Way[] joinArray = join.toArray(new Way[join.size()]);
    346         int left = join.size();
    347         while(left != 0)
    348         {
     391        final Collection<JoinedWay> result = new ArrayList<JoinedWay>();
     392        final Way[] joinArray = waysToJoin.toArray(new Way[waysToJoin.size()]);
     393        int left = waysToJoin.size();
     394        while (left > 0) {
    349395            Way w = null;
    350396            boolean selected = false;
    351             List<Node> n = null;
     397            List<Node> nodes = null;
     398            Set<Long> wayIds = new HashSet<Long>();
    352399            boolean joined = true;
    353             while(joined && left != 0)
    354             {
     400            while (joined && left > 0) {
    355401                joined = false;
    356                 for(int i = 0; i < joinArray.length && left != 0; ++i)
    357                 {
    358                     if(joinArray[i] != null)
    359                     {
     402                for (int i = 0; i < joinArray.length && left != 0; ++i) {
     403                    if (joinArray[i] != null) {
    360404                        Way c = joinArray[i];
    361                         if(w == null)
    362                         { w = c; selected = w.isSelected(); joinArray[i] = null; --left; }
    363                         else
    364                         {
     405                        if (w == null) {
     406                            w = c;
     407                            selected = w.isSelected();
     408                            joinArray[i] = null;
     409                            --left;
     410                        } else {
    365411                            int mode = 0;
    366412                            int cl = c.getNodesCount()-1;
    367413                            int nl;
    368                             if(n == null)
    369                             {
     414                            if (nodes == null) {
    370415                                nl = w.getNodesCount()-1;
    371                                 if(w.getNode(nl) == c.getNode(0)) {
     416                                if (w.getNode(nl) == c.getNode(0)) {
    372417                                    mode = 21;
    373                                 } else if(w.getNode(nl) == c.getNode(cl)) {
     418                                } else if (w.getNode(nl) == c.getNode(cl)) {
    374419                                    mode = 22;
    375                                 } else if(w.getNode(0) == c.getNode(0)) {
     420                                } else if (w.getNode(0) == c.getNode(0)) {
    376421                                    mode = 11;
    377                                 } else if(w.getNode(0) == c.getNode(cl)) {
     422                                } else if (w.getNode(0) == c.getNode(cl)) {
    378423                                    mode = 12;
    379424                                }
    380                             }
    381                             else
    382                             {
    383                                 nl = n.size()-1;
    384                                 if(n.get(nl) == c.getNode(0)) {
     425                            } else {
     426                                nl = nodes.size()-1;
     427                                if (nodes.get(nl) == c.getNode(0)) {
    385428                                    mode = 21;
    386                                 } else if(n.get(0) == c.getNode(cl)) {
     429                                } else if (nodes.get(0) == c.getNode(cl)) {
    387430                                    mode = 12;
    388                                 } else if(n.get(0) == c.getNode(0)) {
     431                                } else if (nodes.get(0) == c.getNode(0)) {
    389432                                    mode = 11;
    390                                 } else if(n.get(nl) == c.getNode(cl)) {
     433                                } else if (nodes.get(nl) == c.getNode(cl)) {
    391434                                    mode = 22;
    392435                                }
    393436                            }
    394                             if(mode != 0)
    395                             {
     437                            if (mode != 0) {
    396438                                joinArray[i] = null;
    397439                                joined = true;
    398                                 if(c.isSelected()) {
     440                                if (c.isSelected()) {
    399441                                    selected = true;
    400442                                }
    401443                                --left;
    402                                 if(n == null) {
    403                                     n = w.getNodes();
     444                                if (nodes == null) {
     445                                    nodes = w.getNodes();
     446                                    wayIds.add(w.getId());
    404447                                }
    405                                 n.remove((mode == 21 || mode == 22) ? nl : 0);
    406                                 if(mode == 21) {
    407                                     n.addAll(c.getNodes());
    408                                 } else if(mode == 12) {
    409                                     n.addAll(0, c.getNodes());
    410                                 } else if(mode == 22)
    411                                 {
    412                                     for(Node node : c.getNodes()) {
    413                                         n.add(nl, node);
     448                                nodes.remove((mode == 21 || mode == 22) ? nl : 0);
     449                                if (mode == 21) {
     450                                    nodes.addAll(c.getNodes());
     451                                } else if (mode == 12) {
     452                                    nodes.addAll(0, c.getNodes());
     453                                } else if (mode == 22) {
     454                                    for (Node node : c.getNodes()) {
     455                                        nodes.add(nl, node);
     456                                    }
     457                                } else /* mode == 11 */ {
     458                                    for (Node node : c.getNodes()) {
     459                                        nodes.add(0, node);
    414460                                    }
    415461                                }
    416                                 else /* mode == 11 */
    417                                 {
    418                                     for(Node node : c.getNodes()) {
    419                                         n.add(0, node);
    420                                     }
    421                                 }
     462                                wayIds.add(c.getId());
    422463                            }
    423464                        }
     
    426467            } /* while(joined) */
    427468
    428             if (n == null) {
    429                 n = w.getNodes();
    430             }
    431 
    432             res.add(new JoinedWay(n, selected));
     469            if (nodes == null) {
     470                nodes = w.getNodes();
     471                wayIds.add(w.getId());
     472            }
     473
     474            result.add(new JoinedWay(nodes, wayIds, selected));
    433475        } /* while(left != 0) */
    434476
    435         return res;
     477        return result;
    436478    }
    437479
     
    521563        return combinedPolygons;
    522564    }
    523 
    524565}
  • trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/relations/MultipolygonCache.java

    r4629 r4630  
    120120    }
    121121   
    122     private final void updateMultipolygonsReferringTo(final AbstractDatasetChangedEvent event) {
     122    private final void updateMultipolygonsReferringTo(AbstractDatasetChangedEvent event) {
    123123        updateMultipolygonsReferringTo(event, event.getPrimitives(), event.getDataset());
    124124    }
    125125
    126126    private final void updateMultipolygonsReferringTo(
    127             final AbstractDatasetChangedEvent event, final Collection<? extends OsmPrimitive> primitives, final DataSet ds) {
     127            final AbstractDatasetChangedEvent event, Collection<? extends OsmPrimitive> primitives, DataSet ds) {
    128128        updateMultipolygonsReferringTo(event, primitives, ds, null);
    129129    }
    130130   
    131131    private final Collection<Map<Relation, Multipolygon>> updateMultipolygonsReferringTo(
    132             final AbstractDatasetChangedEvent event, final Collection<? extends OsmPrimitive> primitives,
    133             final DataSet ds, final Collection<Map<Relation, Multipolygon>> initialMaps) {
     132            AbstractDatasetChangedEvent event, Collection<? extends OsmPrimitive> primitives,
     133            DataSet ds, Collection<Map<Relation, Multipolygon>> initialMaps) {
    134134        Collection<Map<Relation, Multipolygon>> maps = initialMaps;
    135135        if (primitives != null) {
     
    158158    }
    159159   
    160     private final void processEvent(final AbstractDatasetChangedEvent event, final Relation r, final Collection<Map<Relation, Multipolygon>> maps) {
    161         if (event instanceof NodeMovedEvent) {
    162             for (Map<Relation, Multipolygon> map : maps) {
    163                 Multipolygon m = map.get(r);
    164                 for (PolyData pd : m.getCombinedPolygons()) {
    165                     pd.nodeMoved((NodeMovedEvent) event);
    166                 }
     160    private final void processEvent(AbstractDatasetChangedEvent event, Relation r, Collection<Map<Relation, Multipolygon>> maps) {
     161        if (event instanceof NodeMovedEvent || event instanceof WayNodesChangedEvent) {
     162            dispatchEvent(event, r, maps);
     163        } else if (event instanceof PrimitivesRemovedEvent) {
     164            if (event.getPrimitives().contains(r)) {
     165                removeMultipolygonFrom(r, maps);
    167166            }
    168167        } else {
    169168            // Default (non-optimal) action: remove multipolygon from cache
    170             for (Map<Relation, Multipolygon> map : maps) {
    171                 map.remove(r);
    172             }
     169            removeMultipolygonFrom(r, maps);
     170        }
     171    }
     172   
     173    private final void dispatchEvent(AbstractDatasetChangedEvent event, Relation r, Collection<Map<Relation, Multipolygon>> maps) {
     174        for (Map<Relation, Multipolygon> map : maps) {
     175            Multipolygon m = map.get(r);
     176            for (PolyData pd : m.getCombinedPolygons()) {
     177                if (event instanceof NodeMovedEvent) {
     178                    pd.nodeMoved((NodeMovedEvent) event);
     179                } else if (event instanceof WayNodesChangedEvent) {
     180                    pd.wayNodesChanged((WayNodesChangedEvent)event);
     181                }
     182            }
     183        }
     184    }
     185   
     186    private final void removeMultipolygonFrom(Relation r, Collection<Map<Relation, Multipolygon>> maps) {
     187        for (Map<Relation, Multipolygon> map : maps) {
     188            map.remove(r);
    173189        }
    174190    }
     
    181197    @Override
    182198    public void primitivesRemoved(PrimitivesRemovedEvent event) {
    183         updateMultipolygonsReferringTo(event);// FIXME: See if it is possible to update only concerned PolyData
     199        updateMultipolygonsReferringTo(event);
    184200    }
    185201
    186202    @Override
    187203    public void tagsChanged(TagsChangedEvent event) {
    188         //removeMultipolygonsReferringTo(event);
     204        // Do nothing
    189205    }
    190206
     
    196212    @Override
    197213    public void wayNodesChanged(WayNodesChangedEvent event) {
    198         updateMultipolygonsReferringTo(event);// FIXME: See if it is possible to update only concerned PolyData
     214        updateMultipolygonsReferringTo(event);
    199215    }
    200216
    201217    @Override
    202218    public void relationMembersChanged(RelationMembersChangedEvent event) {
    203         updateMultipolygonsReferringTo(event);// FIXME: See if it is possible to update only concerned PolyData
     219        updateMultipolygonsReferringTo(event);
    204220    }
    205221
    206222    @Override
    207223    public void otherDatasetChange(AbstractDatasetChangedEvent event) {
    208         updateMultipolygonsReferringTo(event);// FIXME: See if it is possible to update only concerned PolyData
     224        // Do nothing
    209225    }
    210226
    211227    @Override
    212228    public void dataChanged(DataChangedEvent event) {
    213         updateMultipolygonsReferringTo(event);// FIXME: See if it is possible to update only concerned PolyData
     229        // Do nothing
    214230    }
    215231
     
    260276                            if (multipolygon != null) {
    261277                                for (PolyData pd : multipolygon.getCombinedPolygons()) {
    262                                     if (pd.getWays().contains(p)) {
     278                                    if (pd.getWayIds().contains(p.getId())) {
    263279                                        pd.selected = true;
    264280                                        selectedPolyData.add(pd);
Note: See TracChangeset for help on using the changeset viewer.