Changeset 6609 in josm


Ignore:
Timestamp:
2014-01-03T12:30:28+01:00 (7 years ago)
Author:
simon04
Message:

see #9516 - MapCSS: greatly improve performance of spatial "element of" (was: "contains") expression

The current syntax is inner ∈ outer.

The order plus symbol has been changed since now the left side is matched in the end.

Location:
trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSParser.jj

    r6607 r6609  
    8080|   < CARET: "^" >
    8181|   < FULLSTOP: "." >
    82 |   < CONTAINS: "∋" >
     82|   < ELEMENT_OF: "∈" >
    8383|   < COMMENT_START: "/*" > : COMMENT
    8484|   < UNEXPECTED_CHAR : ~[] > // avoid TokenMgrErrors because they are hard to recover from
     
    277277            ( ( c=condition(Context.LINK) | c=class_or_pseudoclass(Context.LINK) ) { conditions.add(c); } )*
    278278        |
    279             <CONTAINS> { type = Selector.ChildOrParentSelectorType.CONTAINS; }
     279            <ELEMENT_OF> { type = Selector.ChildOrParentSelectorType.ELEMENT_OF; }
    280280        )
    281281        { selLink = new LinkSelector(conditions); }
  • trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java

    r6607 r6609  
    22package org.openstreetmap.josm.gui.mappaint.mapcss;
    33
     4import java.util.Collection;
    45import java.util.Collections;
    56import java.util.List;
     
    910import org.openstreetmap.josm.data.osm.Node;
    1011import org.openstreetmap.josm.data.osm.OsmPrimitive;
     12import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
    1113import org.openstreetmap.josm.data.osm.Relation;
    1214import org.openstreetmap.josm.data.osm.RelationMember;
     
    1517import org.openstreetmap.josm.gui.mappaint.Environment;
    1618import org.openstreetmap.josm.gui.mappaint.Range;
     19import org.openstreetmap.josm.tools.CheckParameterUtil;
    1720import org.openstreetmap.josm.tools.Geometry;
    1821import org.openstreetmap.josm.tools.Pair;
     
    3639
    3740    public static enum ChildOrParentSelectorType {
    38         CHILD, PARENT, CONTAINS
     41        CHILD, PARENT, ELEMENT_OF
    3942    }
    4043
     
    149152        private class ContainsFinder extends AbstractVisitor {
    150153            private final Environment e;
    151             private final List<Node> nodes;
    152154
    153155            private ContainsFinder(Environment e) {
    154156                this.e = e;
    155                 if (e.osm instanceof Node) {
    156                     nodes = Collections.singletonList((Node) e.osm);
    157                 } else if (e.osm instanceof Way) {
    158                     nodes = ((Way) e.osm).getNodes();
    159                 } else {
    160                     throw new IllegalArgumentException("Relations not supported");
    161                 }
     157                CheckParameterUtil.ensureThat(!(e.osm instanceof Node), "Nodes not supported");
    162158            }
    163159
    164160            @Override
    165161            public void visit(Node n) {
     162                if (e.parent == null && right.matches(e.withPrimitive(n))) {
     163                    if (e.osm instanceof Way && Geometry.nodeInsidePolygon(n, ((Way) e.osm).getNodes())
     164                            || e.osm instanceof Relation && ((Relation) e.osm).isMultipolygon() && Geometry.isNodeInsideMultiPolygon(n, (Relation) e.osm, null)) {
     165                        e.parent = n;
     166                    }
     167                }
    166168            }
    167169
    168170            @Override
    169171            public void visit(Way w) {
    170                 if (e.parent == null && left.matches(e.withPrimitive(w))) {
    171                     if (nodes.size() == 1
    172                             ? Geometry.nodeInsidePolygon(nodes.get(0), w.getNodes())
    173                             : Geometry.PolygonIntersection.FIRST_INSIDE_SECOND.equals(Geometry.polygonIntersection(nodes, w.getNodes()))) {
     172                if (e.parent == null && right.matches(e.withPrimitive(w))) {
     173                    if (e.osm instanceof Way && Geometry.PolygonIntersection.FIRST_INSIDE_SECOND.equals(Geometry.polygonIntersection(w.getNodes(), ((Way) e.osm).getNodes()))
     174                            || e.osm instanceof Relation && ((Relation) e.osm).isMultipolygon() && Geometry.isPolygonInsideMultiPolygon(w.getNodes(), (Relation) e.osm, null)) {
    174175                        e.parent = w;
    175                         e.index = 0;
    176176                    }
    177177                }
     
    180180            @Override
    181181            public void visit(Relation r) {
    182                 if (e.parent == null && left.matches(e.withPrimitive(r))) {
    183                     if (r.isMultipolygon() && Geometry.isPolygonInsideMultiPolygon(nodes, r, null)) {
    184                         e.parent = r;
    185                         e.index = 0;
     182            }
     183
     184            public void visit(Collection<? extends OsmPrimitive> primitives) {
     185                for (OsmPrimitive p : primitives) {
     186                    if (e.parent != null) {
     187                        // abort if first match has been found
     188                        break;
     189                    } else if (!e.osm.equals(p)) {
     190                        p.accept(this);
    186191                    }
    187192                }
     
    191196        @Override
    192197        public boolean matches(Environment e) {
     198
    193199            if (!right.matches(e))
    194200                return false;
    195201
    196             if (ChildOrParentSelectorType.CONTAINS.equals(type)) {
    197                 final OsmPrimitive rightPrimitive = e.osm;
     202            if (ChildOrParentSelectorType.ELEMENT_OF.equals(type)) {
     203
     204                if (e.osm instanceof Node) {
     205                    // nodes cannot contain elements
     206                    return false;
     207                }
     208                e.child = e.osm;
     209
    198210                final ContainsFinder containsFinder = new ContainsFinder(e);
    199                 for (final OsmPrimitive p : rightPrimitive.getDataSet().allPrimitives()) {
    200                     if (rightPrimitive.equals(p)) {
    201                         continue;
    202                     }
    203                     p.accept(containsFinder);
    204                     if (e.parent != null) {
    205                         e.osm = rightPrimitive;
    206                         return true;
    207                     }
    208                 }
     211                if (right instanceof GeneralSelector) {
     212                    if (((GeneralSelector) right).matchesBase(OsmPrimitiveType.NODE)) {
     213                        containsFinder.visit(e.osm.getDataSet().searchNodes(e.osm.getBBox()));
     214                    }
     215                    if (((GeneralSelector) right).matchesBase(OsmPrimitiveType.WAY)) {
     216                        containsFinder.visit(e.osm.getDataSet().searchWays(e.osm.getBBox()));
     217                    }
     218                } else {
     219                    // use slow test
     220                    containsFinder.visit(e.osm.getDataSet().allPrimitives());
     221                }
     222
     223                return e.parent != null;
     224
    209225            } else if (ChildOrParentSelectorType.CHILD.equals(type)) {
    210226                MatchingReferrerFinder collector = new MatchingReferrerFinder(e);
     
    357373        }
    358374
    359         public boolean matchesBase(Environment e){
    360             if (e.osm instanceof Node) {
     375        public boolean matchesBase(OsmPrimitiveType type) {
     376            if (OsmPrimitiveType.NODE.equals(type)) {
    361377                return base.equals("node") || base.equals("*");
    362             } else if (e.osm instanceof Way) {
     378            } else if (OsmPrimitiveType.WAY.equals(type)) {
    363379                return base.equals("way") || base.equals("area") || base.equals("*");
    364             } else if (e.osm instanceof Relation) {
    365                 if (base.equals("area")) {
    366                     return ((Relation) e.osm).isMultipolygon();
    367                 } else if (base.equals("relation")) {
    368                     return true;
    369                 } else if (base.equals("canvas")) {
    370                     return e.osm.get("#canvas") != null;
    371                 }
     380            } else if (OsmPrimitiveType.RELATION.equals(type)) {
     381                return base.equals("area") || base.equals("relation") || base.equals("canvas");
    372382            }
    373383            return false;
     384        }
     385
     386        public boolean matchesBase(OsmPrimitive p) {
     387            if (!matchesBase(p.getType())) {
     388                return false;
     389            } else {
     390                if (p instanceof Relation) {
     391                    if (base.equals("area")) {
     392                        return ((Relation) p).isMultipolygon();
     393                    } else if (base.equals("canvas")) {
     394                        return p.get("#canvas") != null;
     395                    }
     396                }
     397                return true;
     398            }
     399        }
     400
     401        public boolean matchesBase(Environment e) {
     402            return matchesBase(e.osm);
    374403        }
    375404
Note: See TracChangeset for help on using the changeset viewer.