23

Below I have what I'd expect is a way to create a GeoJSON MultiPolygon object with one polygon in it which has two "holes".

When I use the service http://geojson.io/ to validate this object, it returns with an error each element in a position must be a number and it does not render, however if I remove the "holes" nest, removing one of them then it works.

I'm looking for a way to describe a MultiPolygon where the polygons can have multiple holes.

I'm not looking for a way in code to create a polygon with holes.

I'm looking for a way to use the GeoJSON spec to represent MultiPolygons with multiple holes.

enter image description here

{
  "type": "MultiPolygon",
  "coordinates": [
    [
      [
        [
          -73.98114904754641,
          40.7470284264813
        ],
        [
          -73.98314135177611,
          40.73416844413217
        ],
        [
          -74.00538969848634,
          40.734314779027144
        ],
        [
          -74.00479214294432,
          40.75027851544338
        ],
        [
          -73.98114904754641,
          40.7470284264813
        ]
      ],
      [
        [
          [
            -73.99818643920906,
            40.74550031602355
          ],
          [
            -74.00298643920905,
            40.74550031602355
          ],
          [
            -74.00058643920897,
            40.74810024102966
          ],
          [
            -73.99818643920906,
            40.74550031602355
          ]
        ],
        [
          [
            -73.98917421691903,
            40.73646098717515
          ],
          [
            -73.99397421691901,
            40.73646098717515
          ],
          [
            -73.99157421691893,
            40.739061265535696
          ],
          [
            -73.98917421691903,
            40.73646098717515
          ]
        ]
      ]
    ]
  ]
}
ThomasReggi
  • 55,053
  • 85
  • 237
  • 424
  • Have you seen [Google's example](https://developers.google.com/maps/documentation/javascript/examples/layer-data-polygon) (a GeoJson polygon with 2 holes)? – geocodezip Apr 27 '17 at 05:08
  • 4
    This example doesn't contain any geojson! It's just Google code. – ThomasReggi Apr 27 '17 at 05:36
  • 1
    @geocodezip I'm trying to create valid GeoJSON - JSON, not google code. – ThomasReggi Apr 27 '17 at 06:27
  • Well my guess is that you are using the MultiPolygon to create multiple Polygons, not holes, but the posted code isn't valid (I can't load it as is). – geocodezip Apr 27 '17 at 14:11
  • 1
    This is a good question because there's confusion here about what is a "MultiPolygon" vs. "Polygon" in geoJSON. see below for answers. – verdy_p Oct 07 '17 at 23:26

3 Answers3

44

This is how it works:

{
  "type": "MultiPolygon",
  "coordinates": [
    [
      {polygon},
      {hole},
      {hole},
      {hole}
    ]
  ]
}

Not like this:

{
  "type": "MultiPolygon",
  "coordinates": [
    [
      {polygon},
      [
        {hole},
        {hole},
        {hole}
      ]
    ]
  ]
}

Here's an example!

{
  "type": "MultiPolygon",
  "coordinates": [
    [
      [
        [
          -47.900390625,
          -14.944784875088372
        ],
        [
          -51.591796875,
          -19.91138351415555
        ],
        [
          -41.11083984375,
          -21.309846141087192
        ],
        [
          -43.39599609375,
          -15.390135715305204
        ],
        [
          -47.900390625,
          -14.944784875088372
        ]
      ],
      [
        [
          -46.6259765625,
          -17.14079039331664
        ],
        [
          -47.548828125,
          -16.804541076383455
        ],
        [
          -46.23046874999999,
          -16.699340234594537
        ],
        [
          -45.3515625,
          -19.31114335506464
        ],
        [
          -46.6259765625,
          -17.14079039331664
        ]
      ],
      [
        [
          -44.40673828125,
          -18.375379094031825
        ],
        [
          -44.4287109375,
          -20.097206227083888
        ],
        [
          -42.9345703125,
          -18.979025953255267
        ],
        [
          -43.52783203125,
          -17.602139123350838
        ],
        [
          -44.40673828125,
          -18.375379094031825
        ]
      ]
    ]
  ]
}
ThomasReggi
  • 55,053
  • 85
  • 237
  • 424
  • One thing to note is if a portion of the `{hole}` is outside of the first polygon, that part shows up, which may or may not be the intended result. Is there a way to not show if it's not contained in the first polygon? Using the above example, you could change `-20.097206227083888` to `-24.097206227083888` to see what I mean. – Taku Sep 15 '21 at 06:44
  • boundary rings that are overlapping an area that is not the full area of one of the rings are not supported in GeoJSON; you need to design the geometry with inner and outer rings; the GeoJSON "Polygon can contain only one outer ring and zero or more inner rings creating "holes"; the GeoJSON "MultiPolygon" is then used to group several GeoJSON "Polygon" objects that may overlap, creating an union and not new holes (the individual Poygons in the MultiPolygon should never overlap non empty areas), they may only insersect along edges connecting node points, or on isolated nodes. – verdy_p Feb 24 '23 at 16:38
  • The rules of MultiPolygons in OSM data are more relaxed (but then the conversion from OSM ro GeoJSON is not so trivial). Ideally, OSM data should be designed using stricter GeoJSON requirements. – verdy_p Feb 24 '23 at 16:44
  • Some tools using GeoJSON may still accept relaxed rules, but they will preprocess the geometry to generate a cleaned geometry where all rings are either inner or outer (and where some additional intersection nodes will be computed and added to the geometry). But the releaxed GeoJSON data will not be portable without such preprocessing. What happens to a GeoJSON MultiPolygon containing Polygons with overlapping subareas will be tool-dependant (most often layered areas with different opacity, or a simplified union removing duplicate subareas to fill them once, or rarely a hole). – verdy_p Feb 24 '23 at 16:53
18

For your example in fact it's not really a MultiPolygon (in the sense of geoJSON) but a simple Polygon (with a single outer ring and multiple inner rings for the holes). Note the difference with Multipolygons in OSM (which represents them as a relation containing ways, and whose first and last node should be merged to the same "node" element (something that does not exist in geoJSON where they are unified only by the fact that the two nodes have the same coordinates, but will in reality be automatically closed by an additional segment for "Polygon" and "MultiPolygon" types of GeoJSON)

Note that when you import a geoJSON in OSM editors (such as JOSM) they will be imported with separate nodes for the first and last node, even if they have the same coordinates - you need to use the JOSM validator to detect superposed nodes and merge them after the import in JOSM but before submission to OSM.

But in scripts or general use of geoJSON, all rings (arrays of coordinate pairs) in a "type":"Polygon" or members of a "type":"Polygon" are not required to include the same coordinates for the last node as the first node, because it is implicit (but it is still recommended to add this duplicate node for compatibility). Such closure of rings is implicit for "Polygon" and "MultiPolygon" (as they represent surfaces), but not for "Polyline" and "MultiPolyline" (as they represent curves) where you still need to include twice the same coordinates for the first and last node to get closed curves.

To represent an OSM "multipolygon" with multiple "outer" rings, you have to include several "[ {outer},{inner*} ]" in the main array of coordinates for the geoJSON "MultiPolygon" type, i.e.

{"type":"MultiPolygon", "coordinates":[
  [
    [[x0,y0], [x1,y1], ... [x0,y0]], /*outer1*/
    [[x0,y0], [x1,y1], ... [x0,y0]], /*inner1, optional*/
    [[x0,y0], [x1,y1], ... [x0,y0]], /*inner2, optional*/
  ],[
    [[x0,y0], [x1,y1], ... [x0,y0]], /*outer2*/
  ],...,[
    [[x0,y0], [x1,y1], ... [x0,y0]], /*outer3*/
  ],[
    [[x0,y0], [x1,y1], ... [x0,y0]], /*outer4*/
  ]
]}

So for your example, the solution is:

{"type":"Polygon", "coordinates":[
  [[x0,y0], [x1,y1], [x2,y2], [x3,y3], [x0,y0]], /*outer1 (quadrilateral)*/
  [[x4,y4], [x5,y5], [x6,y6], [x4,y4]],          /*inner1 (triangular hole)*/
  [[x7,y7], [x8,y8], [x9,y9], [x7,y7]]           /*inner2 (triangular hole)*/
]}

If you had several outer rings only (possibly overlapping to create an union of surfaces, but this is not recommended) it would need to be a MultiPolygon, and here you would get no "holes", only "overlaps" (this is what you tried to do in the top message above, and that's not what you expected to get):

{"type":"MultiPolygon", "coordinates":[
  [[[x0,y0], [x1,y1], [x2,y2], [x3,y3], [x0,y0]]], /*outer1*/
  [[[x4,y4], [x5,y5], [x6,y6], [x4,y4]]],          /*outer2*/
  [[[x7,y7], [x8,y8], [x9,y9], [x7,y7]]]           /*outer3*/
]}

Note there's one less level of [square braces] because we can use "Polygon" here instead of a Multipolygon that would contain only one member in your example.

verdy_p
  • 1,615
  • 1
  • 20
  • 14
-1

As far as I know, you can use SUBSTR(JSON_EXTRACT(ST_ASGEOJSON(WKT) function if converting from wkt to geography. That way you can represent in map. What I found in bigquery is seems like multipolygon with holes switch position for holes coordinates when u use ST_ASGEOJSON(). And check out this link: https://dev.socrata.com/docs/datatypes/multipolygon.html#,