Ticket #10391: 0006-new-selectors.patch

File 0006-new-selectors.patch, 11.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.SUBSET_OR_EQUAL
     870                        || sel.type == ChildOrParentSelectorType.NOT_SUBSET_OR_EQUAL;
     871                if (needEnclosing && p.getDataSet() != null) {
    870872                    List<OsmPrimitive> toCheck = new ArrayList<>();
    871873                    toCheck.addAll(p.getDataSet().searchWays(p.getBBox()));
    872874                    toCheck.addAll(p.getDataSet().searchRelations(p.getBBox()));
  • src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSParser.jj

     
    216216|   < CARET: "^" >
    217217|   < FULLSTOP: "." >
    218218|   < DEG: "°" >
    219 |   < ELEMENT_OF: "∈" >
     219|   < SUBSET_OR_EQUAL: ["∈","⊆"] >
     220|   < NOT_SUBSET_OR_EQUAL: "⊈" >
     221|   < SUPERSET_OR_EQUAL: "⊇" >
     222|   < NOT_SUPERSET_OR_EQUAL: "⊉" >
    220223|   < CROSSING: "⧉" >
    221224|   < PERCENT: "%" >
    222225|   < COMMENT_START: "/*" > : COMMENT
     
    690693                )
    691694                ( ( c=condition(Context.LINK) | c=class_or_pseudoclass(Context.LINK) ) { conditions.add(c); } )*
    692695            |
    693                 <ELEMENT_OF> { type = Selector.ChildOrParentSelectorType.ELEMENT_OF; }
     696                <SUBSET_OR_EQUAL> { type = Selector.ChildOrParentSelectorType.SUBSET_OR_EQUAL; }
    694697            |
     698                <NOT_SUBSET_OR_EQUAL> { type = Selector.ChildOrParentSelectorType.NOT_SUBSET_OR_EQUAL; }
     699            |
     700                <SUPERSET_OR_EQUAL> { type = Selector.ChildOrParentSelectorType.SUPERSET_OR_EQUAL; }
     701            |
     702                <NOT_SUPERSET_OR_EQUAL> { type = Selector.ChildOrParentSelectorType.NOT_SUPERSET_OR_EQUAL; }
     703            |
    695704                <CROSSING> { type = Selector.ChildOrParentSelectorType.CROSSING; }
    696705            )
    697706            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, 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         */
    315318        private class ContainsFinder extends AbstractFinder {
    316319            protected List<IPrimitive> toCheck;
    317320
     
    348351            }
    349352        }
    350353
     354        /**
     355         * Finds elements which are inside the left element, or in other words, it finds elements enclosing e.osm.
     356         * The found enclosing elements are collected in {@code e.children}.
     357         */
     358        private class InsideOrEqualFinder extends AbstractFinder {
     359
     360            protected InsideOrEqualFinder(Environment e) {
     361                super(e);
     362            }
     363
     364            @Override
     365            public void visit(IWay<?> w) {
     366                if (left.matches(new Environment(w).withParent(e.osm))
     367                        && w.getBBox().bounds(e.osm.getBBox())
     368                        && !Geometry.filterInsidePolygon(Collections.singletonList(e.osm), w).isEmpty()) {
     369                    addToChildren(e, w);
     370                }
     371            }
     372
     373            @Override
     374            public void visit(IRelation<?> r) {
     375                if (r instanceof Relation && r.isMultipolygon() && r.getBBox().bounds(e.osm.getBBox())
     376                        && left.matches(new Environment(r).withParent(e.osm))
     377                        && !Geometry.filterInsideMultipolygon(Collections.singletonList(e.osm), (Relation) r).isEmpty()) {
     378                    addToChildren(e, r);
     379                }
     380            }
     381        }
     382
     383        private void visitBBox(Environment e, AbstractFinder finder) {
     384            boolean withNodes = finder instanceof ContainsFinder;
     385            if (left instanceof OptimizedGeneralSelector) {
     386                if (withNodes && ((OptimizedGeneralSelector) left).matchesBase(OsmPrimitiveType.NODE)) {
     387                    finder.visit(e.osm.getDataSet().searchNodes(e.osm.getBBox()));
     388                }
     389                if (((OptimizedGeneralSelector) left).matchesBase(OsmPrimitiveType.WAY)) {
     390                    finder.visit(e.osm.getDataSet().searchWays(e.osm.getBBox()));
     391                }
     392                if (((OptimizedGeneralSelector) left).matchesBase(OsmPrimitiveType.RELATION)) {
     393                    finder.visit(e.osm.getDataSet().searchRelations(e.osm.getBBox()));
     394                }
     395            } else {
     396                if (withNodes) {
     397                    finder.visit(e.osm.getDataSet().searchNodes(e.osm.getBBox()));
     398                }
     399                finder.visit(e.osm.getDataSet().searchWays(e.osm.getBBox()));
     400                finder.visit(e.osm.getDataSet().searchRelations(e.osm.getBBox()));
     401            }
     402        }
     403
     404        private static boolean isArea(IPrimitive p) {
     405            return (p instanceof IWay && ((IWay<?>) p).isClosed() && ((IWay<?>) p).getNodesCount() >= 4)
     406                    || (p instanceof IRelation && p.isMultipolygon() && !p.isIncomplete());
     407        }
     408
    351409        @Override
    352410        public boolean matches(Environment e) {
    353411
     
    354412            if (!right.matches(e))
    355413                return false;
    356414
    357             if (ChildOrParentSelectorType.ELEMENT_OF == type) {
     415            if (ChildOrParentSelectorType.SUBSET_OR_EQUAL == type || ChildOrParentSelectorType.NOT_SUBSET_OR_EQUAL == type) {
    358416
    359                 if (e.osm instanceof INode || e.osm.getDataSet() == null) {
    360                     // nodes cannot contain elements
    361                     return false;
     417                if (e.osm.getDataSet() == null || !isArea(e.osm)) {
     418                    // only areas can contain elements
     419                    return ChildOrParentSelectorType.NOT_SUBSET_OR_EQUAL == type;
    362420                }
    363 
    364421                ContainsFinder containsFinder = new ContainsFinder(e);
    365422                e.parent = e.osm;
    366423
    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());
    380                 }
     424                visitBBox(e, containsFinder);
    381425                containsFinder.execGeometryTests();
    382                 return e.children != null;
     426                return ChildOrParentSelectorType.SUBSET_OR_EQUAL == type ? e.children != null : e.children == null;
    383427
     428            } else if (ChildOrParentSelectorType.SUPERSET_OR_EQUAL == type || ChildOrParentSelectorType.NOT_SUPERSET_OR_EQUAL == type) {
     429
     430                if (e.osm.getDataSet() == null || (e.osm instanceof INode && ((INode) e.osm).getCoor() == null)
     431                        || (!(e.osm instanceof INode) && !isArea(e.osm))) {
     432                    return ChildOrParentSelectorType.NOT_SUPERSET_OR_EQUAL == type;
     433                }
     434
     435                InsideOrEqualFinder insideOrEqualFinder = new InsideOrEqualFinder(e);
     436                e.parent = e.osm;
     437
     438                visitBBox(e, insideOrEqualFinder);
     439                return ChildOrParentSelectorType.SUPERSET_OR_EQUAL == type ? e.children != null : e.children == null;
     440
    384441            } else if (ChildOrParentSelectorType.CROSSING == type && e.osm instanceof IWay) {
    385442                e.parent = e.osm;
    386443                if (right instanceof OptimizedGeneralSelector
  • test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/ChildOrParentSelectorTest.java

     
    186186        assertTrue(selector.matches(e));
    187187    }
    188188
     189    /**
     190     * Test inside/contains selectors (spatial test)
     191     */
    189192    @Test
    190193    public void testContains() throws Exception {
    191194        ds = OsmReader.parseDataSet(Files.newInputStream(Paths.get("data_nodist/amenity-in-amenity.osm")), null);
    192195        ChildOrParentSelector css = parse("node[tag(\"amenity\") = parent_tag(\"amenity\")] ∈ *[amenity] {}");
     196        assertFalse(css.matches(new Environment(ds.getPrimitiveById(123, OsmPrimitiveType.NODE))));
    193197        assertTrue(css.matches(new Environment(ds.getPrimitiveById(123, OsmPrimitiveType.WAY))));
    194198        assertTrue(css.matches(new Environment(ds.getPrimitiveById(123, OsmPrimitiveType.RELATION))));
     199        css = parse("node[tag(\"amenity\") = parent_tag(\"amenity\")] ⊆  *[amenity] {}");
     200        assertFalse(css.matches(new Environment(ds.getPrimitiveById(123, OsmPrimitiveType.NODE))));
     201        assertTrue(css.matches(new Environment(ds.getPrimitiveById(123, OsmPrimitiveType.WAY))));
     202        assertTrue(css.matches(new Environment(ds.getPrimitiveById(123, OsmPrimitiveType.RELATION))));
     203        css = parse("node[tag(\"amenity\") = parent_tag(\"amenity\")] ⊈  *[amenity] {}");
     204        assertTrue(css.matches(new Environment(ds.getPrimitiveById(123, OsmPrimitiveType.NODE))));
     205        assertFalse(css.matches(new Environment(ds.getPrimitiveById(123, OsmPrimitiveType.WAY))));
     206        assertFalse(css.matches(new Environment(ds.getPrimitiveById(123, OsmPrimitiveType.RELATION))));
     207        css = parse("*[tag(\"amenity\") = parent_tag(\"amenity\")] ⊇  *[amenity] {}");
     208        assertTrue(css.matches(new Environment(ds.getPrimitiveById(123, OsmPrimitiveType.NODE))));
     209        assertTrue(css.matches(new Environment(ds.getPrimitiveById(123, OsmPrimitiveType.WAY))));
     210        assertFalse(css.matches(new Environment(ds.getPrimitiveById(123, OsmPrimitiveType.RELATION))));
     211        css = parse("*[tag(\"amenity\") = parent_tag(\"amenity\")] ⊉  *[amenity] {}");
     212        assertFalse(css.matches(new Environment(ds.getPrimitiveById(123, OsmPrimitiveType.NODE))));
     213        assertFalse(css.matches(new Environment(ds.getPrimitiveById(123, OsmPrimitiveType.WAY))));
     214        assertTrue(css.matches(new Environment(ds.getPrimitiveById(123, OsmPrimitiveType.RELATION))));
    195215    }
    196216}