Skip to content

Instantly share code, notes, and snippets.

@gmaclennan
Last active January 21, 2017 20:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gmaclennan/413669ae56a397822f3e4afb4de68e3b to your computer and use it in GitHub Desktop.
Save gmaclennan/413669ae56a397822f3e4afb4de68e3b to your computer and use it in GitHub Desktop.
Dissolve connected GeoJSON LineStrings
Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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