Ignore:
Timestamp:
2010-03-08T09:25:09+01:00 (14 years ago)
Author:
jttt
Message:

Fixed #4661 Intersection between multipolygon ways, but which ones?

Location:
applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/TestError.java

    r18092 r20365  
    239239    }
    240240
     241    @SuppressWarnings("unchecked")
    241242    public void visitHighlighted(ValidatorVisitor v) {
    242243        for (Object o : highlighted) {
     
    245246            else if (o instanceof WaySegment)
    246247                v.visit((WaySegment) o);
     248            else if (o instanceof List<?>) {
     249                v.visit((List<Node>)o);
     250            }
    247251        }
    248252    }
     
    288292        }
    289293
    290         /**
    291          * Draws a line around the segment
    292          *
    293          * @param s The segment
    294          * @param color The color
    295          */
    296         public void drawSegment(Node n1, Node n2, Color color) {
    297             Point p1 = mv.getPoint(n1);
    298             Point p2 = mv.getPoint(n2);
     294        public void drawSegment(Point p1, Point p2, Color color) {
    299295            g.setColor(color);
    300296
     
    322318
    323319        /**
     320         * Draws a line around the segment
     321         *
     322         * @param s The segment
     323         * @param color The color
     324         */
     325        public void drawSegment(Node n1, Node n2, Color color) {
     326            drawSegment(mv.getPoint(n1), mv.getPoint(n2), color);
     327        }
     328
     329        /**
    324330         * Draw a small rectangle.
    325331         * White if selected (as always) or red otherwise.
     
    333339
    334340        public void visit(Way w) {
    335             Node lastN = null;
    336             for (Node n : w.getNodes()) {
    337                 if (lastN == null) {
    338                     lastN = n;
    339                     continue;
    340                 }
    341                 if (isSegmentVisible(lastN, n)) {
    342                     drawSegment(lastN, n, severity.getColor());
    343                 }
    344                 lastN = n;
    345             }
     341            visit(w.getNodes());
    346342        }
    347343
     
    389385            return true;
    390386        }
     387
     388        public void visit(List<Node> nodes) {
     389            Node lastN = null;
     390            for (Node n : nodes) {
     391                if (lastN == null) {
     392                    lastN = n;
     393                    continue;
     394                }
     395                if (n.isDrawable() && isSegmentVisible(lastN, n)) {
     396                    drawSegment(lastN, n, severity.getColor());
     397                }
     398                lastN = n;
     399            }
     400        }
    391401    }
    392402
  • applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/ValidatorDialog.java

    r19335 r20365  
    1818import java.util.HashSet;
    1919import java.util.LinkedList;
     20import java.util.List;
    2021import java.util.Set;
    2122
     
    3536import org.openstreetmap.josm.data.SelectionChangedListener;
    3637import org.openstreetmap.josm.data.osm.DataSet;
     38import org.openstreetmap.josm.data.osm.Node;
    3739import org.openstreetmap.josm.data.osm.OsmPrimitive;
    3840import org.openstreetmap.josm.data.osm.WaySegment;
     
    432434            visit(ws.way.getNodes().get(ws.lowerIndex));
    433435            visit(ws.way.getNodes().get(ws.lowerIndex + 1));
     436        }
     437
     438        public void visit(List<Node> nodes) {
     439            for (Node n: nodes) {
     440                visit(n);
     441            }
    434442        }
    435443    }
  • applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/ValidatorVisitor.java

    r13497 r20365  
    11package org.openstreetmap.josm.plugins.validator;
    22
     3import java.util.List;
     4
     5import org.openstreetmap.josm.data.osm.Node;
    36import org.openstreetmap.josm.data.osm.OsmPrimitive;
    47import org.openstreetmap.josm.data.osm.WaySegment;
     
    69public interface ValidatorVisitor {
    710    void visit(OsmPrimitive p);
    8 
    911    void visit(WaySegment ws);
     12    void visit(List<Node> nodes);
    1013}
  • applications/editors/josm/plugins/validator/src/org/openstreetmap/josm/plugins/validator/tests/MultipolygonTest.java

    r19335 r20365  
    33import static org.openstreetmap.josm.tools.I18n.tr;
    44
     5import java.awt.geom.GeneralPath;
     6import java.util.ArrayList;
     7import java.util.Collection;
     8import java.util.Collections;
     9import java.util.List;
     10
    511import org.openstreetmap.josm.Main;
     12import org.openstreetmap.josm.data.osm.Node;
    613import org.openstreetmap.josm.data.osm.Relation;
    714import org.openstreetmap.josm.data.osm.RelationMember;
     15import org.openstreetmap.josm.data.osm.Way;
    816import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon;
    9 import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon.PolyData;
     17import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon.JoinedWay;
    1018import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon.PolyData.Intersection;
    1119import org.openstreetmap.josm.plugins.validator.Severity;
     
    2230    protected static final int CROSSING_WAYS = 1606;
    2331
     32    private final List<List<Node>> nonClosedWays = new ArrayList<List<Node>>();
     33
    2434    public MultipolygonTest() {
    2535        super(tr("Multipolygon"),
     
    2737    }
    2838
     39    private List<List<Node>> joinWays(Collection<Way> ways) {
     40        List<List<Node>> result = new ArrayList<List<Node>>();
     41        List<Way> waysToJoin = new ArrayList<Way>();
     42        for (Way way: ways) {
     43            if (way.isClosed()) {
     44                result.add(way.getNodes());
     45            } else {
     46                waysToJoin.add(way);
     47            }
     48        }
     49
     50        for (JoinedWay jw: Multipolygon.joinWays(waysToJoin)) {
     51            if (!jw.isClosed()) {
     52                nonClosedWays.add(jw.getNodes());
     53            }
     54            result.add(jw.getNodes());
     55        }
     56        return result;
     57    }
     58
     59    private GeneralPath createPath(List<Node> nodes) {
     60        GeneralPath result = new GeneralPath();
     61        result.moveTo((float)nodes.get(0).getCoor().lat(), (float)nodes.get(0).getCoor().lon());
     62        for (int i=1; i<nodes.size(); i++) {
     63            Node n = nodes.get(i);
     64            result.lineTo((float)n.getCoor().lat(), (float)n.getCoor().lon());
     65        }
     66        return result;
     67    }
     68
     69    private List<GeneralPath> createPolygons(List<List<Node>> joinedWays) {
     70        List<GeneralPath> result = new ArrayList<GeneralPath>();
     71        for (List<Node> way: joinedWays) {
     72            if (way.size() >= 3) {
     73                result.add(createPath(way));
     74            }
     75        }
     76        return result;
     77    }
     78
     79    private Intersection getPolygonIntersection(GeneralPath outer, List<Node> inner) {
     80        boolean inside = false;
     81        boolean outside = false;
     82
     83        for (Node n: inner) {
     84            boolean contains = outer.contains(n.getCoor().lat(), n.getCoor().lon());
     85            inside = inside | contains;
     86            outside = outside | !contains;
     87            if (inside & outside) {
     88                return Intersection.CROSSING;
     89            }
     90        }
     91
     92        return inside?Intersection.INSIDE:Intersection.OUTSIDE;
     93    }
     94
    2995    @Override
    3096    public void visit(Relation r) {
     97        nonClosedWays.clear();
    3198        if ("multipolygon".equals(r.get("type"))) {
    3299            checkMembersAndRoles(r);
     
    34101            Multipolygon polygon = new Multipolygon(Main.map.mapView);
    35102            polygon.load(r);
    36 
    37             if (polygon.hasNonClosedWays()) {
    38                 errors.add( new TestError(this, Severity.WARNING, tr("Multipolygon is not closed"), NON_CLOSED_WAY,  r));
    39             }
    40103
    41104            if (polygon.getOuterWays().isEmpty()) {
     
    49112            }
    50113
    51             for (PolyData pdInner: polygon.getInnerPolygons()) {
    52                 PolyData pdOuter = polygon.findOuterPolygon(pdInner, polygon.getOuterPolygons());
    53                 if (pdOuter == null) {
    54                     errors.add(new TestError(this, Severity.WARNING, tr("Multipolygon inner way is outside."), INNER_WAY_OUTSIDE,  r));
    55                 } else if (pdOuter.contains(pdInner.poly) == Intersection.CROSSING) {
    56                     errors.add(new TestError(this, Severity.WARNING, tr("Intersection between multipolygon ways"), CROSSING_WAYS, r));
     114            List<List<Node>> innerWays = joinWays(polygon.getInnerWays()); // Side effect - sets nonClosedWays
     115            List<List<Node>> outerWays = joinWays(polygon.getOuterWays());
     116
     117            if (!nonClosedWays.isEmpty()) {
     118                errors.add( new TestError(this, Severity.WARNING, tr("Multipolygon is not closed"), NON_CLOSED_WAY,  Collections.singletonList(r), nonClosedWays));
     119            }
     120
     121            // For painting is used Polygon class which works with ints only. For validation we need more precision
     122            List<GeneralPath> outerPolygons = createPolygons(outerWays);
     123            for (List<Node> pdInner: innerWays) {
     124                boolean outside = true;
     125                boolean crossing = false;
     126                List<Node> outerWay = null;
     127                for (int i=0; i<outerWays.size(); i++) {
     128                    GeneralPath outer = outerPolygons.get(i);
     129                    Intersection intersection = getPolygonIntersection(outer, pdInner);
     130                    outside = outside & intersection == Intersection.OUTSIDE;
     131                    if (intersection == Intersection.CROSSING) {
     132                        crossing = true;
     133                        outerWay = outerWays.get(i);
     134                    }
     135                }
     136                if (outside | crossing) {
     137                    List<List<Node>> highlights = new ArrayList<List<Node>>();
     138                    highlights.add(pdInner);
     139                    if (outside) {
     140                        errors.add(new TestError(this, Severity.WARNING, tr("Multipolygon inner way is outside."), INNER_WAY_OUTSIDE, Collections.singletonList(r), highlights));
     141                    } else if (crossing) {
     142                        highlights.add(outerWay);
     143                        errors.add(new TestError(this, Severity.WARNING, tr("Intersection between multipolygon ways"), CROSSING_WAYS, Collections.singletonList(r), highlights));
     144                    }
    57145                }
    58146            }
Note: See TracChangeset for help on using the changeset viewer.