Skip to content

Instantly share code, notes, and snippets.

@rclark
Created August 6, 2013 21:34
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rclark/6168912 to your computer and use it in GitHub Desktop.
Save rclark/6168912 to your computer and use it in GitHub Desktop.
JSTS to create polygons from a network of arbitrary, or "spaghetti" lines. This uses jsts.noding to "clean" or "planarize" the line network, which is crazy fast compared to the "Union" alternative here: https://gist.github.com/rclark/6123614
var jsts = require("jsts"),
u = require("underscore"),
fs = require("fs");
fs.readFile("/Users/ryan/Desktop/hv-lines.geojson", function (err, data) {
var geojson = JSON.parse(data),
writer = new jsts.io.GeoJSONWriter(),
polygonizer = new jsts.operation.polygonize.Polygonizer(),
noder = new jsts.noding.MCIndexNoder(),
intersector = new jsts.algorithm.RobustLineIntersector(),
intersectionFinder = new jsts.noding.IntersectionFinderAdder(intersector),
factory = new jsts.geom.GeometryFactory(),
jsUtil = require("javascript.util"),
util = jsUtil.util,
segments = new util.ArrayList(),
cleaned = null,
polygons = null,
output = {type: "FeatureCollection", features: []},
geoms = [],
i = null;
// List the lines as arrays of jsts.geom.Coordinates
geojson.features.forEach(function (feature) {
function line2coords(lineCoords) {
return u.map(lineCoords, function (coord) {
return new jsts.geom.Coordinate(coord[0], coord[1]);
});
}
if (feature.geometry.type === "MultiLineString") {
feature.geometry.coordinates.forEach(function (lineCoords) {
geoms.push(line2coords(lineCoords));
});
} else if (feature.geometry.type === "LineString") {
geoms.push(line2coords(feature.geometry.coordinates));
}
});
// List the lines as jsts.noding.NodedSegmentStrings
geoms.forEach(function (coordArray) {
segments.add(new jsts.noding.NodedSegmentString(coordArray));
});
// Run the Noder
noder.setSegmentIntersector(intersectionFinder);
noder.computeNodes(segments);
cleaned = noder.getNodedSubstrings();
// Extract LineStrings from the noder
i = cleaned.iterator();
while (i.hasNext()) {
var ns = i.next(),
coords = ns.getCoordinates(),
ls = factory.createLineString(coords);
polygonizer.add(ls);
}
// Output polygons
polygons = polygonizer.getPolygons();
polygons.array.forEach(function (poly) {
var f = {type: "Feature", properties: {}, geometry: writer.write(poly)};
output.features.push(f);
});
process.stdout.write(JSON.stringify(output));
});
@osro
Copy link

osro commented Apr 4, 2016

Hmm for some reason if I have shapes like this, this method returns only one polygon (outer ring)
http://bl.ocks.org/d/fd0203d849db8475632d8e55f2d48d10

If the "outer ring" is a rectangle the method works perfectly.
http://bl.ocks.org/d/cfb90664622a583921b76332789d22ff

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment