Esri / geometry-api-java

The Esri Geometry API for Java enables developers to write custom applications for analysis of spatial data. This API is used in the Esri GIS Tools for Hadoop and other 3rd-party data processing solutions.
Apache License 2.0
694 stars 260 forks source link

OGCGeometry union method does not behave as expected #280

Closed aaron-zonder-meer closed 3 years ago

aaron-zonder-meer commented 3 years ago

It seems that the union method on the OGCGeometry does not behave as expected. The first case is when a MultiPolygon with multiple inner rings is unioned with itself. The second case is when a MultiPolygon with multiple inner rings is unioned with a simple polygon (rectangle).

The set up is as follows:

version:

<dependency>
    <groupId>com.esri.geometry</groupId>
    <artifactId>esri-geometry-api</artifactId>
    <version>2.2.4</version>
</dependency>

example code snippet:

    public String unionSameShape() {
        OGCGeometry geom1 = createGeom2();
        OGCGeometry geom2 = createGeom2();

        return geom1.union(geom2).asGeoJson();
    }

    public String unionDifferentShapes() {
        OGCGeometry geom1 = createGeom1();
        OGCGeometry geom2 = createGeom2();

        return geom1.union(geom2).asGeoJson();
    }

    private OGCGeometry createGeom1() {
        return OGCGeometry.fromGeoJson(
                "{\"type\": \"Polygon\",\n" +
                        "        \"coordinates\": [\n" +
                        "          [\n" +
                        "            [\n" +
                        "              -15.599122,\n" +
                        "              -1.933227\n" +
                        "            ],\n" +
                        "            [\n" +
                        "              18.640097,\n" +
                        "              -1.933227\n" +
                        "            ],\n" +
                        "            [\n" +
                        "              18.640097,\n" +
                        "              2.504085\n" +
                        "            ],\n" +
                        "            [\n" +
                        "              -15.599122,\n" +
                        "              2.504085\n" +
                        "            ],\n" +
                        "            [\n" +
                        "              -15.599122,\n" +
                        "              -1.933227\n" +
                        "            ]\n" +
                        "          ]\n" +
                        "        ]\n" +
                        "      }");
    }

    private OGCGeometry createGeom2() {
        return OGCGeometry.fromGeoJson(
                "{\"type\": \"MultiPolygon\",\n" +
                        "        \"coordinates\": [\n" +
                        "          [\n" +
                        "            [\n" +
                        "              [\n" +
                        "                -10,\n" +
                        "                -10\n" +
                        "              ],\n" +
                        "              [\n" +
                        "                10,\n" +
                        "                -10\n" +
                        "              ],\n" +
                        "              [\n" +
                        "                10,\n" +
                        "                10\n" +
                        "              ],\n" +
                        "              [\n" +
                        "                -10,\n" +
                        "                10\n" +
                        "              ],\n" +
                        "              [\n" +
                        "                -10,\n" +
                        "                -10\n" +
                        "              ]\n" +
                        "            ],\n" +
                        "            [\n" +
                        "              [\n" +
                        "                -4,\n" +
                        "                -4\n" +
                        "              ],\n" +
                        "              [\n" +
                        "                -4,\n" +
                        "                4\n" +
                        "              ],\n" +
                        "              [\n" +
                        "                4,\n" +
                        "                4\n" +
                        "              ],\n" +
                        "              [\n" +
                        "                4,\n" +
                        "                -4\n" +
                        "              ],\n" +
                        "              [\n" +
                        "                -4,\n" +
                        "                -4\n" +
                        "              ]\n" +
                        "            ],\n" +
                        "            [\n" +
                        "              [\n" +
                        "                -5,\n" +
                        "                -5\n" +
                        "              ],\n" +
                        "              [\n" +
                        "                -5,\n" +
                        "                5\n" +
                        "              ],\n" +
                        "              [\n" +
                        "                5,\n" +
                        "                5\n" +
                        "              ],\n" +
                        "              [\n" +
                        "                5,\n" +
                        "                -5\n" +
                        "              ],\n" +
                        "              [\n" +
                        "                -5,\n" +
                        "                -5\n" +
                        "              ]\n" +
                        "            ],\n" +
                        "            [\n" +
                        "              [\n" +
                        "                -7,\n" +
                        "                -7\n" +
                        "              ],\n" +
                        "              [\n" +
                        "                -7,\n" +
                        "                7\n" +
                        "              ],\n" +
                        "              [\n" +
                        "                7,\n" +
                        "                7\n" +
                        "              ],\n" +
                        "              [\n" +
                        "                7,\n" +
                        "                -7\n" +
                        "              ],\n" +
                        "              [\n" +
                        "                -7,\n" +
                        "                -7\n" +
                        "              ]\n" +
                        "            ],\n" +
                        "            [\n" +
                        "              [\n" +
                        "                -6,\n" +
                        "                -6\n" +
                        "              ],\n" +
                        "              [\n" +
                        "                -6,\n" +
                        "                6\n" +
                        "              ],\n" +
                        "              [\n" +
                        "                6,\n" +
                        "                6\n" +
                        "              ],\n" +
                        "              [\n" +
                        "                6,\n" +
                        "                -6\n" +
                        "              ],\n" +
                        "              [\n" +
                        "                -6,\n" +
                        "                -6\n" +
                        "              ]\n" +
                        "            ]\n" +
                        "          ]\n" +
                        "        ]\n" +
                        "      },\n" +
                        "      \"id\": \"11c45056-3ee0-4e56-993e-22da21bbff69");
    }

Result union on same shape:

{
   "type":"MultiPolygon",
   "coordinates":[
      [
         [
            [
               -10,
               -10
            ],
            [
               10,
               -10
            ],
            [
               10,
               10
            ],
            [
               -10,
               10
            ],
            [
               -10,
               -10
            ]
         ],
         [
            [
               -7,
               -7
            ],
            [
               -7,
               7
            ],
            [
               7,
               7
            ],
            [
               7,
               -7
            ],
            [
               -7,
               -7
            ]
         ]
      ],
      [
         [
            [
               -6,
               -6
            ],
            [
               6,
               -6
            ],
            [
               6,
               6
            ],
            [
               -6,
               6
            ],
            [
               -6,
               -6
            ]
         ]
      ]
   ],
   "crs":null
}
Screenshot 2020-12-10 at 12 23 05

result of union with different shape:

{
   "type":"MultiPolygon",
   "coordinates":[
      [
         [
            [
               -10,
               -10
            ],
            [
               10,
               -10
            ],
            [
               10,
               -1.933227000000001
            ],
            [
               18.640097,
               -1.933227
            ],
            [
               18.640097,
               2.504085
            ],
            [
               10,
               2.5040849999999995
            ],
            [
               10,
               10
            ],
            [
               -10,
               10
            ],
            [
               -10,
               2.504085
            ],
            [
               -15.599122,
               2.504085
            ],
            [
               -15.599122,
               -1.933227
            ],
            [
               -10.000000000000002,
               -1.9332269999999994
            ],
            [
               -10,
               -10
            ]
         ],
         [
            [
               -7,
               -7
            ],
            [
               -7.000000000000001,
               -1.9332269999999996
            ],
            [
               -6,
               -1.9332269999999991
            ],
            [
               -6,
               2.5040849999999995
            ],
            [
               -7,
               2.5040849999999995
            ],
            [
               -7,
               7
            ],
            [
               7,
               7
            ],
            [
               7,
               2.504084999999999
            ],
            [
               6,
               2.504084999999999
            ],
            [
               6,
               -1.9332270000000005
            ],
            [
               7,
               -1.9332270000000005
            ],
            [
               7,
               -7
            ],
            [
               -7,
               -7
            ]
         ]
      ],
      [
         [
            [
               -6,
               -6
            ],
            [
               6,
               -6
            ],
            [
               6,
               -1.9332270000000005
            ],
            [
               5,
               -1.9332270000000005
            ],
            [
               5,
               2.504084999999999
            ],
            [
               6,
               2.504084999999999
            ],
            [
               6,
               6
            ],
            [
               -6,
               6
            ],
            [
               -6,
               2.5040849999999995
            ],
            [
               -5,
               2.5040849999999995
            ],
            [
               -5,
               -1.933226999999999
            ],
            [
               -6,
               -1.9332269999999991
            ],
            [
               -6,
               -6
            ]
         ]
      ]
   ],
   "crs":null
}
Screenshot 2020-12-10 at 12 23 47

original shapes:

input intersector
alocke commented 3 years ago

Hi Aaron, I will take a look.

stolstov commented 3 years ago

@aaron-zonder-meer I believe the problem here is because the second multipolygon seems to be invalid. It consists of a single Polygon that consists of 5 concentric rings. Instead, it should consist of 3 polygons, and the holes should be oriented according to the spec: See this https://tools.ietf.org/html/rfc7946#section-3.1.6 https://tools.ietf.org/html/rfc7946#section-3.1.7

Try using makeSimple on the second geometry before passing it to union.

aaron-zonder-meer commented 3 years ago

@stolstov Thank you very much for your quick response. Like you said, this geometry was not according to the spec, and not considered 'simple' in the framework. Your solution helped a great deal. As far as I'm concerned, this issue can be closed.