Changeset 15021 in josm for trunk


Ignore:
Timestamp:
2019-04-26T16:45:26+02:00 (5 years ago)
Author:
GerdP
Message:

fix #17652: Method Geometry.isPolygonInsideMultiPolygon returns wrong result

  • don't allow polygon to cross the outer way
  • performance improvement: only check if inner is inside outer when polygon is inside inner. Matters for complex mp with many inners.
  • add unit test which shows error #17652 with old code
Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/tools/Geometry.java

    r15008 r15021  
    1212import java.util.Collections;
    1313import java.util.Comparator;
    14 import java.util.EnumSet;
    1514import java.util.LinkedHashSet;
    1615import java.util.List;
     
    10031002            if (nodes.size() == 1
    10041003                    ? nodeInsidePolygon(nodes.get(0), out.getNodes())
    1005                     : EnumSet.of(PolygonIntersection.FIRST_INSIDE_SECOND, PolygonIntersection.CROSSING).contains(
    1006                             polygonIntersection(nodes, out.getNodes()))) {
     1004                    : PolygonIntersection.FIRST_INSIDE_SECOND == polygonIntersection(nodes, out.getNodes())) {
    10071005                boolean insideInner = false;
    10081006                // If inside an outer, check it is not inside an inner
    10091007                for (JoinedPolygon in : outerInner.b) {
    1010                     if (polygonIntersection(in.getNodes(), out.getNodes()) == PolygonIntersection.FIRST_INSIDE_SECOND
    1011                             && (nodes.size() == 1
    1012                             ? nodeInsidePolygon(nodes.get(0), in.getNodes())
    1013                             : polygonIntersection(nodes, in.getNodes()) == PolygonIntersection.FIRST_INSIDE_SECOND)) {
     1008                    if (nodes.size() == 1 ? nodeInsidePolygon(nodes.get(0), in.getNodes())
     1009                            : polygonIntersection(nodes, in.getNodes()) == PolygonIntersection.FIRST_INSIDE_SECOND
     1010                                    && polygonIntersection(in.getNodes(),
     1011                                            out.getNodes()) == PolygonIntersection.FIRST_INSIDE_SECOND) {
    10141012                        insideInner = true;
    10151013                        break;
  • trunk/test/unit/org/openstreetmap/josm/tools/GeometryTest.java

    r15008 r15021  
    33
    44import static org.junit.Assert.assertEquals;
     5import static org.junit.Assert.assertFalse;
    56import static org.junit.Assert.assertNotEquals;
     7import static org.junit.Assert.assertTrue;
    68
    79import java.io.FileInputStream;
     
    1820import org.openstreetmap.josm.data.osm.Node;
    1921import org.openstreetmap.josm.data.osm.Relation;
     22import org.openstreetmap.josm.data.osm.RelationMember;
    2023import org.openstreetmap.josm.data.osm.Way;
    2124import org.openstreetmap.josm.data.osm.search.SearchCompiler;
     
    221224        assertEquals(Geometry.PolygonIntersection.OUTSIDE, Geometry.polygonIntersection(poly1, poly2));
    222225    }
     226
     227    /**
     228     * Test of {@link Geometry#isPolygonInsideMultiPolygon}
     229     * See #17652. Triangle crosses outer way of multipolygon.
     230     */
     231    @Test
     232    public void testIsPolygonInsideMultiPolygon() {
     233        Node node1 = new Node(new LatLon(1.01, 1.0));
     234        Node node2 = new Node(new LatLon(1.01, 1.1));
     235        Node node3 = new Node(new LatLon(1.02, 1.05));
     236        Way w1 = new Way();
     237        w1.setNodes(Arrays.asList(node1, node2, node3, node1));
     238        w1.put("building", "yes");
     239
     240        Node node4 = new Node(new LatLon(1.0, 1.09));
     241        Node node5 = new Node(new LatLon(1.0, 1.12));
     242        Node node6 = new Node(new LatLon(1.1, 1.12));
     243        Node node7 = new Node(new LatLon(1.1, 1.09));
     244        Way outer = new Way();
     245        outer.setNodes(Arrays.asList(node4, node5, node6, node7, node4));
     246        Node node8 = new Node(new LatLon(1.04, 1.1));
     247        Node node9 = new Node(new LatLon(1.04, 1.11));
     248        Node node10 = new Node(new LatLon(1.06, 1.105));
     249        Way inner = new Way();
     250        inner.setNodes(Arrays.asList(node8, node9, node10, node8));
     251        Relation mp = new Relation();
     252        mp.addMember(new RelationMember("outer",outer));
     253        mp.addMember(new RelationMember("inner",inner));
     254        mp.put("type", "multipolygon");
     255        assertFalse(Geometry.isPolygonInsideMultiPolygon(w1.getNodes(), mp, null));
     256
     257        node4.setCoor(new LatLon(1.006, 0.99));
     258        // now w1 is inside
     259        assertTrue(Geometry.isPolygonInsideMultiPolygon(w1.getNodes(), mp, null));
     260    }
    223261}
Note: See TracChangeset for help on using the changeset viewer.