Ticket #10391: 0005-new-selectors-v2.patch

File 0005-new-selectors-v2.patch, 10.6 KB (added by GerdP, 5 years ago)
  • src/org/openstreetmap/josm/data/validation/tests/MapCSSTagChecker.java

     
    866866            env.clearSelectorMatchingInformation();
    867867            if (partialSelection && r.selector instanceof Selector.ChildOrParentSelector) {
    868868                ChildOrParentSelector sel = (Selector.ChildOrParentSelector) r.selector;
    869                 if (sel.type == ChildOrParentSelectorType.ELEMENT_OF && p.getDataSet() != null) {
     869                boolean needEnclosing = sel.type == ChildOrParentSelectorType.ELEMENT_OF
     870                        || sel.type == ChildOrParentSelectorType.SUBSET_OR_EQUAL
     871                        || sel.type == ChildOrParentSelectorType.NOT_SUBSET_OR_EQUAL;
     872                if (needEnclosing && p.getDataSet() != null) {
    870873                    List<OsmPrimitive> toCheck = new ArrayList<>();
    871874                    toCheck.addAll(p.getDataSet().searchWays(p.getBBox()));
    872875                    toCheck.addAll(p.getDataSet().searchRelations(p.getBBox()));
  • src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSParser.jj

     
    217217|   < FULLSTOP: "." >
    218218|   < DEG: "°" >
    219219|   < ELEMENT_OF: "∈" >
     220|   < SUBSET_OR_EQUAL: "⊆" >
     221|   < NOT_SUBSET_OR_EQUAL: "⊈" >
     222|   < SUPERSET_OR_EQUAL: "⊇" >
     223|   < NOT_SUPERSET_OR_EQUAL: "⊉" >
    220224|   < CROSSING: "⧉" >
    221225|   < PERCENT: "%" >
    222226|   < COMMENT_START: "/*" > : COMMENT
     
    692696            |
    693697                <ELEMENT_OF> { type = Selector.ChildOrParentSelectorType.ELEMENT_OF; }
    694698            |
     699                <SUBSET_OR_EQUAL> { type = Selector.ChildOrParentSelectorType.SUBSET_OR_EQUAL; }
     700            |
     701                <NOT_SUBSET_OR_EQUAL> { type = Selector.ChildOrParentSelectorType.NOT_SUBSET_OR_EQUAL; }
     702            |
     703                <SUPERSET_OR_EQUAL> { type = Selector.ChildOrParentSelectorType.SUPERSET_OR_EQUAL; }
     704            |
     705                <NOT_SUPERSET_OR_EQUAL> { type = Selector.ChildOrParentSelectorType.NOT_SUPERSET_OR_EQUAL; }
     706            |
    695707                <CROSSING> { type = Selector.ChildOrParentSelectorType.CROSSING; }
    696708            )
    697709            w()
  • src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java

     
    117117     * @see ChildOrParentSelector
    118118     */
    119119    enum ChildOrParentSelectorType {
    120         CHILD, PARENT, ELEMENT_OF, CROSSING, SIBLING
     120        CHILD, PARENT, ELEMENT_OF, SUBSET_OR_EQUAL, NOT_SUBSET_OR_EQUAL, SUPERSET_OR_EQUAL, NOT_SUPERSET_OR_EQUAL, CROSSING, SIBLING,
    121121    }
    122122
    123123    /**
     
    312312            }
    313313        }
    314314
     315        /**
     316         * Finds elements which are inside the right element, collects those in {@code children}
     317         * If e.osm is a node it finds nodes with with equal position.
     318         */
    315319        private class ContainsFinder extends AbstractFinder {
    316320            protected List<IPrimitive> toCheck;
    317321
    318322            protected ContainsFinder(Environment e) {
    319323                super(e);
    320                 CheckParameterUtil.ensureThat(!(e.osm instanceof INode), "Nodes not supported");
    321324            }
    322325
    323326            @Override
     
    336339                if (toCheck == null || toCheck.isEmpty())
    337340                    return;
    338341
    339                 if (e.osm instanceof IWay) {
     342                if (e.osm instanceof INode) {
     343                    for (IPrimitive p : toCheck) {
     344                        if (p instanceof INode && ((INode) p).getCoor().equals(((INode) e.osm).getCoor()))
     345                            addToChildren(e, p);
     346                    }
     347                } else if (e.osm instanceof IWay) {
    340348                    for (IPrimitive p : Geometry.filterInsidePolygon(toCheck, (IWay<?>) e.osm)) {
    341349                        addToChildren(e, p);
    342350                    }
     
    348356            }
    349357        }
    350358
     359        /**
     360         * Finds elements which are inside the left element, or in other words, it finds elements enclosing e.osm.
     361         * The found enclosing elements are collected in {@code e.children}.
     362         */
     363        private class InsideOrEqualFinder extends AbstractFinder {
     364
     365            protected InsideOrEqualFinder(Environment e) {
     366                super(e);
     367            }
     368
     369            @Override
     370            public void visit(INode n) {
     371                // rather special case: nodes with equal coordinates
     372                if (e.osm instanceof INode && n.getCoor().equals(((INode) e.osm).getCoor())
     373                        && left.matches(new Environment(n).withParent(e.osm))) {
     374                    addToChildren(e, n);
     375                }
     376            }
     377
     378            @Override
     379            public void visit(IWay<?> w) {
     380                if (left.matches(new Environment(w).withParent(e.osm))
     381                        && w.getBBox().bounds(e.osm.getBBox())
     382                        && !Geometry.filterInsidePolygon(Collections.singletonList(e.osm), w).isEmpty()) {
     383                    addToChildren(e, w);
     384                }
     385            }
     386
     387            @Override
     388            public void visit(IRelation<?> r) {
     389                if (r instanceof Relation && r.isMultipolygon() && r.getBBox().bounds(e.osm.getBBox())
     390                        && left.matches(new Environment(r).withParent(e.osm))
     391                        && !Geometry.filterInsideMultipolygon(Collections.singletonList(e.osm), (Relation) r).isEmpty()) {
     392                    addToChildren(e, r);
     393                }
     394            }
     395        }
     396
     397        private void visitBBox(Environment e, AbstractFinder finder) {
     398            boolean nodesOnly = finder instanceof ContainsFinder && e.osm instanceof INode;
     399            if (left instanceof OptimizedGeneralSelector) {
     400                if (((OptimizedGeneralSelector) left).matchesBase(OsmPrimitiveType.NODE)) {
     401                    finder.visit(e.osm.getDataSet().searchNodes(e.osm.getBBox()));
     402                }
     403                if (!nodesOnly) {
     404                    if (((OptimizedGeneralSelector) left).matchesBase(OsmPrimitiveType.WAY)) {
     405                        finder.visit(e.osm.getDataSet().searchWays(e.osm.getBBox()));
     406                    }
     407                    if (((OptimizedGeneralSelector) left).matchesBase(OsmPrimitiveType.RELATION)) {
     408                        finder.visit(e.osm.getDataSet().searchRelations(e.osm.getBBox()));
     409                    }
     410                }
     411            } else {
     412                finder.visit(e.osm.getDataSet().searchNodes(e.osm.getBBox()));
     413                if (!nodesOnly) {
     414                    finder.visit(e.osm.getDataSet().searchWays(e.osm.getBBox()));
     415                    finder.visit(e.osm.getDataSet().searchRelations(e.osm.getBBox()));
     416                }
     417            }
     418        }
     419
     420        private static boolean isArea(IPrimitive p) {
     421            return (p instanceof IWay && ((IWay<?>) p).isClosed() && ((IWay<?>) p).getNodesCount() >= 4)
     422                    || (p instanceof IRelation && p.isMultipolygon() && !p.isIncomplete());
     423        }
     424
    351425        @Override
    352426        public boolean matches(Environment e) {
    353427
     
    354428            if (!right.matches(e))
    355429                return false;
    356430
    357             if (ChildOrParentSelectorType.ELEMENT_OF == type) {
     431            if (ChildOrParentSelectorType.ELEMENT_OF == type || ChildOrParentSelectorType.SUBSET_OR_EQUAL == type
     432                    || ChildOrParentSelectorType.NOT_SUBSET_OR_EQUAL == type) {
    358433
    359                 if (e.osm instanceof INode || e.osm.getDataSet() == null) {
    360                     // nodes cannot contain elements
     434                if (e.osm.getDataSet() == null || (ChildOrParentSelectorType.ELEMENT_OF == type && e.osm instanceof INode)) {
     435                    // for ELEMENT_OF nodes cannot contain elements
    361436                    return false;
    362437                }
    363 
     438                if (!(e.osm instanceof INode) && !isArea(e.osm)) {
     439                    return false;
     440                }
    364441                ContainsFinder containsFinder = new ContainsFinder(e);
    365442                e.parent = e.osm;
    366443
    367                 if (left instanceof OptimizedGeneralSelector) {
    368                     if (((OptimizedGeneralSelector) left).matchesBase(OsmPrimitiveType.NODE)) {
    369                         containsFinder.visit(e.osm.getDataSet().searchNodes(e.osm.getBBox()));
    370                     }
    371                     if (((OptimizedGeneralSelector) left).matchesBase(OsmPrimitiveType.WAY)) {
    372                         containsFinder.visit(e.osm.getDataSet().searchWays(e.osm.getBBox()));
    373                     }
    374                     if (((OptimizedGeneralSelector) left).matchesBase(OsmPrimitiveType.RELATION)) {
    375                         containsFinder.visit(e.osm.getDataSet().searchRelations(e.osm.getBBox()));
    376                     }
    377                 } else {
    378                     // use slow test
    379                     containsFinder.visit(e.osm.getDataSet().allPrimitives());
     444                visitBBox(e, containsFinder);
     445                containsFinder.execGeometryTests();
     446                if (ChildOrParentSelectorType.ELEMENT_OF == type || ChildOrParentSelectorType.SUBSET_OR_EQUAL == type)
     447                    return e.children != null;
     448                return e.children == null;
     449            } else if (ChildOrParentSelectorType.SUPERSET_OR_EQUAL == type || ChildOrParentSelectorType.NOT_SUPERSET_OR_EQUAL == type) {
     450                if (e.osm.getDataSet() == null || (e.osm instanceof INode && ((INode) e.osm).getCoor() == null)) {
     451                    return false;
    380452                }
    381                 containsFinder.execGeometryTests();
    382                 return e.children != null;
     453                if (!(e.osm instanceof INode) && !isArea(e.osm)) {
     454                    return false;
     455                }
    383456
     457                InsideOrEqualFinder insideOrEqualFinder = new InsideOrEqualFinder(e);
     458                e.parent = e.osm;
     459
     460                visitBBox(e, insideOrEqualFinder);
     461                return ChildOrParentSelectorType.SUPERSET_OR_EQUAL == type ? e.children != null : e.children == null;
     462
    384463            } else if (ChildOrParentSelectorType.CROSSING == type && e.osm instanceof IWay) {
    385464                e.parent = e.osm;
    386465                if (right instanceof OptimizedGeneralSelector