Outer envelope to a group of polygons

2.3k views Asked by At

I have a GeoJson file which has multiple polygons. Something like this.

enter image description here

I use Leaflet to render this GeoJson in a website.
I want to draw an outline around the polygoins that envelopes all the polygons. Something like this. enter image description here

Format of GeoJSOn i am using :

{
"features": [
  {
    "geometry": {
      "coordinates": [
        [
          [
            1074.426,
            -1136.986
          ],
          [
            1088.241,
            -1123.171
          ]
        ]
      ],
      "type": "Polygon"
    },
    "properties": {
      "number": "2009",
      "type": "",
      "spaceid": null,
      "alias": null,
      "roomkey": "5/2009"
    },
    "type": "Feature"
  }
],
"bbox": [
  2445.578,
  2445.578
],
"crs": {
  "properties": {
    "name": "urn:ogc:def:crs:OGC:1.3:CRS84"
  },
  "type": "name"
},
"type": "FeatureCollection"

}

Any pointers will be helpful :) Thanks

3

There are 3 answers

1
iH8 On

Your looking for the "convex hull":

In mathematics, the convex hull or convex envelope of a set X of points in the Euclidean plane or in a Euclidean space (or, more generally, in an affine space over the reals) is the smallest convex set that contains X.

Reference: https://en.wikipedia.org/wiki/Convex_hull

You can do that with Turf.js convex method:

Takes a Feature or a FeatureCollection and returns a convex hull Polygon.

Reference: http://turfjs.org/docs/#convex

Example:

var map = new L.Map('leaflet', {center: [0, 0], zoom: 0});

var collection = turf.featureCollection([
    turf.polygon([[[-80,-80],[-40,-80],[-40,-40],[-80,-40],[-80,-80]]]),
    turf.polygon([[[80,80],[40,80],[40,40],[80,40],[80,80]]])
]);

new L.GeoJSON(collection, {color: 'red'}).addTo(map);

var polygon = turf.convex(collection);

new L.GeoJSON(polygon, {color: 'black', 'fill': false }).addTo(map);
body {
    margin: 0;
}

html, body, #leaflet {
    height: 100%;
}
<!DOCTYPE html>
<html>
  <head>
    <title>Leaflet 1.2.0</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link type="text/css" rel="stylesheet" href="//unpkg.com/[email protected]/dist/leaflet.css" />
  </head>
  <body>
    <div id="leaflet"></div>
    <script type="application/javascript" src="//unpkg.com/[email protected]/dist/leaflet.js"></script>
    <script type="application/javascript" src="//npmcdn.com/@turf/turf/turf.min.js"></script>
</script>
  </body>
</html>

0
Cokorda Raka On

@Shaswat, you are right about convex hull missing inner point. So I tried with turf.union:

const turf = require('@turf/turf')

const originGeojson = require('./SECCIONES_13_geo.json')

const totalUnion = originGeojson.features.reduce((union, feature, index) => {
  if (!union) {
    return turf.polygon(feature.geometry.coordinates)
  }

  try {
    return turf.union(union, turf.polygon(feature.geometry.coordinates))
  } catch (err) {
    return union
  }
})

console.log(JSON.stringify(totalUnion))

But it produces somethin like this, lots of holes inside.

enter image description here

The code itself is not correct, for the catch block, which is just a way to get through the entire list. The error in the catch is:

Error: Each LinearRing of a Polygon must have 4 or more Positions.

I'd really appreciate if someone can share the correct way to resolve this.

0
Cokorda Raka On

I managed to do that, but using TopoJSON. I post a video here.

First I tried using the "union" function in tuffjs. But it is extremely slow (I have a very detailed geojson).

So I switched to topojson. First you need to convert your geojson to topojson. Then use the "merge" function in topojson-client library. The merge returns multipolygon, but it is way simpler than the original geometries.

Then you need to do additional processings in the code, to remove some polygon that falls within other polygons.