UNPKG

osm2geojson-ultra

Version:

a faster & more complete OSM & Overpass (either in xml or in json formats) to geojson convertor - 4x faster than xmldom + osmtogeojson in most situations - implemented in TypeScript with txml for XML parsing

105 lines (104 loc) 4.01 kB
import { addToMap, coordsToKey, first, getFirstFromMap, isRing, last, removeFromMap, ringDirection, strArrayArrayToFloat, } from "./utils.js"; export class WayCollection extends Array { constructor() { super(); this.firstMap = {}; this.lastMap = {}; } addWay(way) { const w = way.toCoordsArray(); if (w.length > 0) { this.push(w); addToMap(this.firstMap, coordsToKey(first(w)), w); addToMap(this.lastMap, coordsToKey(last(w)), w); } } mergeWays() { const strings = []; let way = this.shift(); while (way) { removeFromMap(this.firstMap, coordsToKey(first(way)), way); removeFromMap(this.lastMap, coordsToKey(last(way)), way); let current = way; let next; do { let nextWay = this.getNextWay(current); next = nextWay.next; let mergeType = nextWay.mergeType; if (!next) { continue; } this.splice(this.indexOf(next), 1); removeFromMap(this.firstMap, coordsToKey(first(next)), next); removeFromMap(this.lastMap, coordsToKey(last(next)), next); switch (mergeType) { case 0 /* MergeType.EndStart */: current = current.concat(next.slice(1)); break; case 1 /* MergeType.EndEnd */: next.reverse(); current = current.concat(next.slice(1)); break; case 2 /* MergeType.StartStart */: current.reverse(); current = current.concat(next.slice(1)); break; case 3 /* MergeType.StartEnd */: current = next.concat(current.slice(1)); break; } } while (next); strings.push(strArrayArrayToFloat(current)); way = this.shift(); } return strings; } /** * Try to find the next way to add to the current way. * It first tries the next way in the array, and if this doesn't work, try any other way. */ getNextWay(current) { const lastKey = coordsToKey(last(current)); const firstKey = coordsToKey(first(current)); // Step 1: Prefer the next way in the array if it connects let next = this.length > 0 ? this[0] : null; if (next) { const nextFirstKey = coordsToKey(first(next)); const nextLastKey = coordsToKey(last(next)); if (lastKey === nextFirstKey) { return { next, mergeType: 0 /* MergeType.EndStart */ }; } if (lastKey === nextLastKey) { return { next, mergeType: 1 /* MergeType.EndEnd */ }; } if (firstKey === nextFirstKey) { return { next, mergeType: 2 /* MergeType.StartStart */ }; } if (firstKey === nextLastKey) { return { next, mergeType: 3 /* MergeType.StartEnd */ }; } } // Step 2: Fallback to map-based lookup if no sequential match next = getFirstFromMap(this.firstMap, lastKey); if (next) { return { next, mergeType: 0 /* MergeType.EndStart */ }; } next = getFirstFromMap(this.lastMap, lastKey); return { next, mergeType: 1 /* MergeType.EndEnd */ }; } toRings(direction) { const strings = this.mergeWays(); const rings = []; let str = strings.shift(); while (str) { if (isRing(str)) { if (ringDirection(str) !== direction) { str.reverse(); } rings.push(str); } str = strings.shift(); } return rings; } }