Last active
January 21, 2017 20:50
-
-
Save gmaclennan/413669ae56a397822f3e4afb4de68e3b to your computer and use it in GitHub Desktop.
Dissolve connected GeoJSON LineStrings
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 meta = require('@turf/meta') | |
var lineString = require('@turf/helpers').lineString | |
var roundTo = require('round-to') | |
module.exports = function dissolve (fc) { | |
var endPoints = {} | |
var index = [] | |
var dissolvedFeatures = [] | |
meta.featureEach(fc, indexPoints) | |
function indexPoints (f) { | |
if (f.geometry.type === 'MultiLineString') { | |
return f.geometry.coordinates.forEach(function (_) { | |
indexPoints(lineString(_, f.properties)) | |
}) | |
} | |
if (f.geometry.type !== 'LineString') return | |
index.push(f) | |
var id = index.length - 1 | |
var coords = getCoords(f) | |
var p1 = getId(coords[0]) | |
var p2 = getId(coords[coords.length - 1]) | |
// Closed loops and single-point lines should not be dissolved | |
if (p1 === p2) return | |
if (!endPoints[p1]) endPoints[p1] = [] | |
endPoints[p1].push(id) | |
if (!endPoints[p2]) endPoints[p2] = [] | |
endPoints[p2].push(id) | |
} | |
Object.keys(endPoints).forEach(function (pointId) { | |
var ids = endPoints[pointId] | |
if (ids.length !== 2) return | |
var merged = merge(index[ids[0]], index[ids[1]]) | |
if (!merged) return | |
index[ids[0]] = index[ids[1]] = merged | |
}) | |
for (var i = 0; i < index.length; i++) { | |
if (dissolvedFeatures.indexOf(index[i]) > -1) continue | |
dissolvedFeatures.push(index[i]) | |
} | |
return { | |
type: 'FeatureCollection', | |
features: dissolvedFeatures | |
} | |
} | |
function getId (coord, precision) { | |
if (!precision) return coord.join('/') | |
return roundTo(coord[0], precision) + '/' + roundTo(coord[1]) | |
} | |
function getCoords (f) { | |
return f.geometry.coordinates | |
} | |
function merge (f1, f2) { | |
var coords1 = getCoords(f1) | |
var coords2 = getCoords(f2) | |
var coords | |
var s1 = coords1[0] | |
var e1 = coords1[coords1.length - 1] | |
var s2 = coords2[0] | |
var e2 = coords2[coords2.length - 1] | |
// TODO: Lines that both start or end at the same point are randomly | |
// reversed to merge, leaving no guarantee on final line direction | |
if (coordsEq(e1, s2)) { | |
coords = coords1.concat(coords2.slice(1)) | |
} else if (coordsEq(e2, s1)) { | |
coords = coords2.concat(coords1.slice(1)) | |
} else if (coordsEq(e1, e2)) { | |
coords = coords1.concat(coords2.slice(0, -1).reverse()) | |
} else if (coordsEq(s1, s2)) { | |
coords = coords1.concat(coords2.slice(1).reverse()) | |
} else { | |
return null | |
} | |
var mergedProps = {} | |
// If props are equal or undefined in one of the input features, then include in merged props | |
for (var prop in f1.properties) { | |
if (f2.properties.hasOwnProperty(prop) && f1.properties[prop] !== f2.properties[prop]) continue | |
mergedProps[prop] = f1.properties[prop] | |
} | |
for (prop in f2.properties) { | |
if (f1.properties.hasOwnProperty(prop)) continue | |
mergedProps[prop] = f2.properties[prop] | |
} | |
return lineString(coords, mergedProps) | |
} | |
// Needs to check precision | |
function coordsEq (c1, c2) { | |
return c1[0] === c2[0] && c1[1] === c2[1] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment