UNPKG

osm2geojson-lite

Version:

a lightweight yet faster osm (either in xml or in json formats) to geojson convertor - 4x faster than xmldom + osmtogeojson in most situations - implemented in pure JavaScript without any 3rd party dependency

206 lines (205 loc) 7.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Relation = void 0; const osm_object_1 = require("./osm-object"); const way_1 = require("./way"); const node_1 = require("./node"); const way_collection_1 = require("./way-collection"); const late_binder_1 = require("./late-binder"); const utils_1 = require("./utils"); class Relation extends osm_object_1.OsmObject { constructor(id, refElems) { super('relation', id, refElems); this.relations = []; this.nodes = []; this.bounds = undefined; this.ways = []; this.roles = []; } setBounds(bounds) { this.bounds = bounds; } addMember(member) { switch (member.type) { // super relation, need to do combination case 'relation': let binder = new late_binder_1.LateBinder(this.relations, (id) => { const relation = this.refElems.get(`relation/${id}`); if (relation) { relation.refCount++; return relation; } }, this, [member.ref]); this.relations.push(binder); this.refElems.addBinder(binder); break; case 'way': if (!member.role) { member.role = ''; } if (member.geometry) { const way = new way_1.Way(member.ref, this.refElems); way.setLatLngArray(member.geometry); way.refCount++; this.ways.push(way); this.roles.push(member.role); } else if (member.nodes) { const way = new way_1.Way(member.ref, this.refElems); for (const nid of member.nodes) { way.addNodeRef(nid); } way.refCount++; this.ways.push(way); this.roles.push(member.role); } else { let binder = new late_binder_1.LateBinder(this.ways, (nid) => { const way = this.refElems.get(`way/${nid}`); if (way) { way.refCount++; return way; } }, this, [member.ref]); this.ways.push(binder); this.roles.push(member.role); this.refElems.addBinder(binder); } break; case 'node': let node = null; if (member.lat && member.lon) { node = new node_1.Node(member.ref, this.refElems); node.setLatLng({ lon: member.lon, lat: member.lat }); if (member.tags) { node.addTags(member.tags); } for (const [k, v] of Object.entries(member)) { if (['id', 'type', 'lat', 'lon'].indexOf(k) < 0) { node.addProp(k, v); } } node.refCount++; this.nodes.push(node); } else { let binder = new late_binder_1.LateBinder(this.nodes, (id) => { const nn = this.refElems.get(`node/${id}`); if (nn) { nn.refCount++; return nn; } }, this, [member.ref]); this.nodes.push(binder); this.refElems.addBinder(binder); } break; } } constructStringGeometry(ws) { const strings = ws ? ws.mergeWays() : []; if (strings.length === 0) { return null; } return { type: 'MultiLineString', coordinates: strings, }; } constructPolygonGeometry(ows, iws) { const outerRings = ows ? ows.toRings('counterclockwise') : []; const innerRings = iws ? iws.toRings('clockwise') : []; if (outerRings.length > 0) { const compositPolyons = []; let ring; for (ring of outerRings) { compositPolyons.push([ring]); } // link inner polygons to outer containers ring = innerRings.shift(); while (ring) { for (const idx in outerRings) { if ((0, utils_1.pointInsidePolygon)((0, utils_1.first)(ring), outerRings[idx])) { compositPolyons[idx].push(ring); break; } } ring = innerRings.shift(); } // construct the Polygon/MultiPolygon geometry if (compositPolyons.length === 1) { return { type: 'Polygon', coordinates: compositPolyons[0], }; } return { type: 'MultiPolygon', coordinates: compositPolyons, }; } return null; } toFeatureArray() { const polygonFeatures = []; const stringFeatures = []; let pointFeatures = []; for (const relation of this.relations) { if (!relation) { continue; } for (let i = 0; i < relation.ways.length; i++) { const way = relation.ways[i]; this.ways.push(way); this.roles.push(relation.roles[i]); } } let templateFeature = { type: 'Feature', id: this.getCompositeId(), bbox: this.bounds, properties: this.getProps(), geometry: null }; if (!this.bounds) { delete templateFeature.bbox; } if (this.roles.some((r) => r === 'outer')) { const outerWayCollection = new way_collection_1.WayCollection(); const innerWayCollection = new way_collection_1.WayCollection(); for (let i = 0; i < this.ways.length; i++) { const way = this.ways[i]; const role = this.roles[i]; if (role === 'outer') { outerWayCollection.addWay(way); } else if (role === 'inner') { innerWayCollection.addWay(way); } } let feature = Object.assign({}, templateFeature); let geometry = this.constructPolygonGeometry(outerWayCollection, innerWayCollection); if (geometry) { feature.geometry = geometry; polygonFeatures.push(feature); } } else { const wayCollection = new way_collection_1.WayCollection(); for (let way of this.ways) { wayCollection.addWay(way); } let geometry = this.constructStringGeometry(wayCollection); if (geometry) { let feature = Object.assign({}, templateFeature); feature.geometry = geometry; stringFeatures.push(feature); } } for (let node of this.nodes) { pointFeatures = pointFeatures.concat(node.toFeatureArray()); } return [...polygonFeatures, ...stringFeatures, ...pointFeatures]; } } exports.Relation = Relation;