-
-
Save mcwhittemore/4a6b71a454e7255e3a2fea7c75835903 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"type": "Feature", | |
"properties": {}, | |
"geometry": { | |
"type": "Polygon", | |
"coordinates": [ | |
[ | |
[ | |
31.07826232910156, | |
-26.286643169805362 | |
], | |
[ | |
31.04598999023437, | |
-26.32542195842115 | |
], | |
[ | |
31.09508514404297, | |
-26.36018871948795 | |
], | |
[ | |
31.141433715820312, | |
-26.309111826816526 | |
], | |
[ | |
31.11671447753906, | |
-26.268480389348543 | |
], | |
[ | |
31.07826232910156, | |
-26.286643169805362 | |
] | |
] | |
] | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const Delaunator = require("delaunator"); | |
const area = require("./area.json"); | |
const turfCenter = require('@turf/center-of-mass').default; | |
const turfArea = require('@turf/area').default; | |
const seen = {}; | |
// Call smasher and, if it works, print out the new polygons as a FeatureCollection | |
const polys = smasher(area, 100); | |
const str = JSON.stringify({ | |
type: 'FeatureCollection', | |
features: polys.slice(0, 10) | |
}); | |
console.log(str); | |
// Tail recursive delaunator. Takes one polygon and returns a list of them | |
// maxArea is in square meters | |
function smasher(input, maxArea) { | |
const polys = smash(input); | |
const out = []; | |
while(polys.length > 0) { | |
const poly = polys.pop(); | |
const area = turfArea(poly); | |
if (area < maxArea) { | |
out.push(poly); | |
} | |
else { | |
smash(poly).forEach(p => polys.push(p)); | |
} | |
} | |
return out; | |
} | |
// find the mid point between two points | |
function mid(a, b) { | |
const dx = a[0] - b[0]; | |
const dy = a[1] - b[1]; | |
return [a[0] + dx/2, a[1] + dy/2] | |
} | |
// Break a polygon up into triangles by using | |
// the vertices and the midpoints of the lines | |
// which make up the provided polygon | |
function smash(poly) { | |
const coords = poly.geometry.coordinates[0]; | |
// This is here to catch the error being reported | |
// ideally we wouldn't need to do this check | |
const id = coords.join(';'); | |
if (seen[id] !== undefined) { | |
console.error(JSON.stringify(poly, null, 2)); | |
throw new Error('Repeat'); | |
} | |
seen[id] = 1; | |
const points = [] | |
// Loop over the coords but skip the last one | |
// to avoid duplicates in the point set | |
// for each coord add it to the list of points | |
// along with the mid point of the current coord | |
// and the next coord in the list | |
for(let i=0; i<coords.length-1; i++) { | |
const a = coords[i]; | |
const b = coords[i+1]; | |
const m = mid(a, b); | |
points.push(a); | |
points.push(m); | |
} | |
const delaunay = Delaunator.from(points); | |
const tris = delaunay.triangles; | |
const polys = []; | |
// Convert triangle array into GeoJSON polygons | |
for (let i = 0; i < tris.length; i += 3) { | |
polys.push({ | |
type: "Feature", | |
properties: {}, | |
geometry: { | |
type: "Polygon", | |
coordinates: [ | |
[ | |
points[tris[i]], | |
points[tris[i + 1]], | |
points[tris[i + 2]], | |
points[tris[i]], | |
], | |
], | |
}, | |
}); | |
} | |
return polys; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment