Changeset 8237 in josm for trunk


Ignore:
Timestamp:
2015-04-19T22:21:21+02:00 (4 years ago)
Author:
simon04
Message:

see #10529 - MapCSS: add :unclosed_multipolygon pseudo-class and >:open_end selector to go from relations to their open end nodes

For example, relation:unclosed_multipolygon >:open_end node matches open end nodes of unclosed multipolygon relations.

Location:
trunk/src/org/openstreetmap/josm
Files:
4 edited

Legend:

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

    r8126 r8237  
    286286        public Collection<Long> getWayIds() {
    287287            return wayIds;
     288        }
     289
     290        public List<Node> getNodes() {
     291            return nodes;
    288292        }
    289293
     
    355359    private final List<Way> innerWays = new ArrayList<>();
    356360    private final List<Way> outerWays = new ArrayList<>();
    357     private final List<PolyData> innerPolygons = new ArrayList<>();
    358     private final List<PolyData> outerPolygons = new ArrayList<>();
    359361    private final List<PolyData> combinedPolygons = new ArrayList<>();
     362    private final List<Node> openEnds = new ArrayList<>();
    360363
    361364    private boolean incomplete;
     
    391394        }
    392395
     396        final List<PolyData> innerPolygons = new ArrayList<>();
     397        final List<PolyData> outerPolygons = new ArrayList<>();
    393398        createPolygons(innerWays, innerPolygons);
    394399        createPolygons(outerWays, outerPolygons);
    395400        if (!outerPolygons.isEmpty()) {
    396             addInnerToOuters();
     401            addInnerToOuters(innerPolygons, outerPolygons);
    397402        }
    398403    }
     
    414419        for (JoinedWay jw: joinWays(waysToJoin)) {
    415420            result.add(new PolyData(jw));
     421            if (!jw.isClosed()) {
     422                openEnds.add(jw.getNodes().get(0));
     423                openEnds.add(jw.getNodes().get(jw.getNodes().size() - 1));
     424            }
    416425        }
    417426    }
     
    545554    }
    546555
    547     private final void addInnerToOuters()  {
     556    private final void addInnerToOuters(List<PolyData> innerPolygons, List<PolyData> outerPolygons)  {
    548557
    549558        if (innerPolygons.isEmpty()) {
     
    568577            }
    569578        }
    570 
    571         // Clear inner and outer polygons to reduce memory footprint
    572         innerPolygons.clear();
    573         outerPolygons.clear();
    574579    }
    575580
     
    593598        return combinedPolygons;
    594599    }
     600
     601    public List<PolyData> getInnerPolygons() {
     602        final List<PolyData> innerPolygons = new ArrayList<>();
     603        createPolygons(innerWays, innerPolygons);
     604        return innerPolygons;
     605    }
     606
     607    public List<PolyData> getOuterPolygons() {
     608        final List<PolyData> outerPolygons = new ArrayList<>();
     609        createPolygons(outerWays, outerPolygons);
     610        return outerPolygons;
     611    }
     612
     613    /**
     614     * Returns the start and end node of non-closed rings.
     615     * @return the start and end node of non-closed rings.
     616     */
     617    public List<Node> getOpenEnds() {
     618        return openEnds;
     619    }
    595620}
  • trunk/src/org/openstreetmap/josm/data/validation/tests/MultipolygonTest.java

    r8126 r8237  
    2424import org.openstreetmap.josm.data.osm.Way;
    2525import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon;
    26 import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon.JoinedWay;
    2726import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon.PolyData.Intersection;
    2827import org.openstreetmap.josm.data.osm.visitor.paint.relations.MultipolygonCache;
     
    5958    private static volatile ElemStyles styles;
    6059
    61     private final List<List<Node>> nonClosedWays = new ArrayList<>();
    6260    private final Set<String> keysCheckedByAnotherTest = new HashSet<>();
    6361
     
    9391    }
    9492
    95     private List<List<Node>> joinWays(Collection<Way> ways) {
    96         List<List<Node>> result = new ArrayList<>();
    97         List<Way> waysToJoin = new ArrayList<>();
    98         for (Way way : ways) {
    99             if (way.isClosed()) {
    100                 result.add(way.getNodes());
    101             } else {
    102                 waysToJoin.add(way);
    103             }
    104         }
    105 
    106         for (JoinedWay jw : Multipolygon.joinWays(waysToJoin)) {
    107             if (!jw.isClosed()) {
    108                 nonClosedWays.add(jw.getNodes());
    109             } else {
    110                 result.add(jw.getNodes());
    111             }
    112         }
    113         return result;
    114     }
    115 
    11693    private GeneralPath createPath(List<Node> nodes) {
    11794        GeneralPath result = new GeneralPath();
     
    124101    }
    125102
    126     private List<GeneralPath> createPolygons(List<List<Node>> joinedWays) {
     103    private List<GeneralPath> createPolygons(List<Multipolygon.PolyData> joinedWays) {
    127104        List<GeneralPath> result = new ArrayList<>();
    128         for (List<Node> way : joinedWays) {
    129             result.add(createPath(way));
     105        for (Multipolygon.PolyData way : joinedWays) {
     106            result.add(createPath(way.getNodes()));
    130107        }
    131108        return result;
     
    165142    @Override
    166143    public void visit(Relation r) {
    167         nonClosedWays.clear();
    168144        if (r.isMultipolygon()) {
    169145            checkMembersAndRoles(r);
     
    205181            }
    206182
    207             List<List<Node>> innerWays = joinWays(polygon.getInnerWays()); // Side effect - sets nonClosedWays
    208             List<List<Node>> outerWays = joinWays(polygon.getOuterWays());
    209183            if (styles != null && !"boundary".equals(r.get("type"))) {
    210184                AreaElemStyle area = ElemStyles.getAreaElemStyle(r, false);
     
    260234            }
    261235
    262             List<Node> openNodes = new LinkedList<>();
    263             for (List<Node> w : nonClosedWays) {
    264                 if (w.size()<1) continue;
    265                 openNodes.add(w.get(0));
    266                 openNodes.add(w.get(w.size() - 1));
    267             }
     236            List<Node> openNodes = polygon.getOpenEnds();
    268237            if (!openNodes.isEmpty()) {
    269238                List<OsmPrimitive> primitives = new LinkedList<>();
     
    276245
    277246            // For painting is used Polygon class which works with ints only. For validation we need more precision
    278             List<GeneralPath> outerPolygons = createPolygons(outerWays);
    279             for (List<Node> pdInner : innerWays) {
     247            List<GeneralPath> outerPolygons = createPolygons(polygon.getOuterPolygons());
     248            for (Multipolygon.PolyData pdInner : polygon.getInnerPolygons()) {
    280249                boolean outside = true;
    281250                boolean crossing = false;
    282                 List<Node> outerWay = null;
    283                 for (int i=0; i<outerWays.size(); i++) {
     251                Multipolygon.PolyData outerWay = null;
     252                for (int i = 0; i < polygon.getOuterPolygons().size(); i++) {
    284253                    GeneralPath outer = outerPolygons.get(i);
    285                     Intersection intersection = getPolygonIntersection(outer, pdInner);
     254                    Intersection intersection = getPolygonIntersection(outer, pdInner.getNodes());
    286255                    outside = outside & intersection == Intersection.OUTSIDE;
    287256                    if (intersection == Intersection.CROSSING) {
    288257                        crossing = true;
    289                         outerWay = outerWays.get(i);
     258                        outerWay = polygon.getOuterPolygons().get(i);
    290259                    }
    291260                }
    292261                if (outside || crossing) {
    293262                    List<List<Node>> highlights = new ArrayList<>();
    294                     highlights.add(pdInner);
     263                    highlights.add(pdInner.getNodes());
    295264                    if (outside) {
    296265                        addError(r, new TestError(this, Severity.WARNING, tr("Multipolygon inner way is outside"), INNER_WAY_OUTSIDE, Collections.singletonList(r), highlights));
    297                     } else if (crossing) {
    298                         highlights.add(outerWay);
     266                    } else {
     267                        highlights.add(outerWay.getNodes());
    299268                        addError(r, new TestError(this, Severity.WARNING, tr("Intersection between multipolygon ways"), CROSSING_WAYS, Collections.singletonList(r), highlights));
    300269                    }
  • trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Condition.java

    r8206 r8237  
    99import java.util.regex.Pattern;
    1010
     11import org.openstreetmap.josm.Main;
    1112import org.openstreetmap.josm.data.osm.Node;
    1213import org.openstreetmap.josm.data.osm.OsmPrimitive;
     
    1415import org.openstreetmap.josm.data.osm.Tag;
    1516import org.openstreetmap.josm.data.osm.Way;
     17import org.openstreetmap.josm.data.osm.visitor.paint.relations.MultipolygonCache;
    1618import org.openstreetmap.josm.gui.mappaint.Cascade;
    1719import org.openstreetmap.josm.gui.mappaint.ElemStyles;
     
    410412            case "righthandtraffic":
    411413                return ExpressionFactory.Functions.is_right_hand_traffic(e);
     414            case "unclosed_multipolygon":
     415                return e.osm instanceof Relation && ((Relation) e.osm).isMultipolygon() &&
     416                        !MultipolygonCache.getInstance().get(Main.map.mapView, (Relation) e.osm).getOpenEnds().isEmpty();
     417            case "open_end":
     418                // handling at org.openstreetmap.josm.gui.mappaint.mapcss.Selector.ChildOrParentSelector.MultipolygonOpenEndFinder
     419                return true;
    412420            }
    413421            return false;
  • trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java

    r8236 r8237  
    1616import org.openstreetmap.josm.data.osm.Way;
    1717import org.openstreetmap.josm.data.osm.visitor.AbstractVisitor;
     18import org.openstreetmap.josm.data.osm.visitor.paint.relations.MultipolygonCache;
    1819import org.openstreetmap.josm.gui.mappaint.Environment;
    1920import org.openstreetmap.josm.gui.mappaint.Range;
     
    219220        }
    220221
     222        private class MultipolygonOpenEndFinder extends AbstractFinder {
     223
     224            @Override
     225            public void visit(Way w) {
     226                w.visitReferrers(innerVisitor);
     227            }
     228
     229            public MultipolygonOpenEndFinder(Environment e) {
     230                super(e);
     231            }
     232
     233            private final AbstractVisitor innerVisitor = new AbstractFinder(e) {
     234                @Override
     235                public void visit(Relation r) {
     236                    if (left.matches(e.withPrimitive(r))) {
     237                        final List<Node> openEnds = MultipolygonCache.getInstance().get(Main.map.mapView, r).getOpenEnds();
     238                        final int openEndIndex = openEnds.indexOf((Node) e.osm);
     239                        if (openEndIndex >= 0) {
     240                            e.parent = r;
     241                            e.index = openEndIndex;
     242                            e.count = openEnds.size();
     243                        }
     244                    }
     245                }
     246            };
     247
     248        }
     249
    221250        private final class CrossingFinder extends AbstractFinder {
    222251            private CrossingFinder(Environment e) {
     
    337366                        }
    338367                    }
     368                }
     369            } else if (ChildOrParentSelectorType.CHILD.equals(type)
     370                    && link.conds != null && !link.conds.isEmpty()
     371                    && link.conds.get(0) instanceof Condition.PseudoClassCondition
     372                    && "open_end".equals(((Condition.PseudoClassCondition) link.conds.get(0)).id)) {
     373                if (e.osm instanceof Node) {
     374                    e.osm.visitReferrers(new MultipolygonOpenEndFinder(e));
     375                    return e.parent != null;
    339376                }
    340377            } else if (ChildOrParentSelectorType.CHILD.equals(type)) {
Note: See TracChangeset for help on using the changeset viewer.