4

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

Shaswat Rungta
  • 3,635
  • 2
  • 19
  • 26
  • Do the polygons you wish to envelop share edges? If not, a convex hull is your primary option (as described in the other answer). If your polygons share edges, there are potential solutions that can assemble the outer polygon (and internal rings) based on the edges that are not shared (and therefore the outer limit of the combined polygon). – Andrew Reid Sep 14 '17 at 23:12

3 Answers3

8

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/leaflet@1.2.0/dist/leaflet.css" />
  </head>
  <body>
    <div id="leaflet"></div>
    <script type="application/javascript" src="//unpkg.com/leaflet@1.2.0/dist/leaflet.js"></script>
    <script type="application/javascript" src="//npmcdn.com/@turf/turf/turf.min.js"></script>
</script>
  </body>
</html>
iH8
  • 27,722
  • 4
  • 67
  • 76
  • 2
    But convex hull misses the inner points. If you consider an L shaped corner.. The top two points will be chosen If you see this image https://raw.githubusercontent.com/AndriiHeonia/hull/master/readme-imgs/1.png i dont want those empty spaces. The border has to run along the edges. – Shaswat Rungta Sep 06 '17 at 04:30
0

@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.

Cokorda Raka
  • 4,375
  • 6
  • 36
  • 54
0

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.

Cokorda Raka
  • 4,375
  • 6
  • 36
  • 54