Created
August 6, 2013 21:34
-
-
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
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
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)); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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