UNPKG

osmtogeojson

Version:
2,083 lines (2,061 loc) 108 kB
if (typeof require !== "undefined") { var expect = require("expect.js"); var DOMParser = require("@xmldom/xmldom").DOMParser; var osmtogeojson = require("../"); } describe("osm (xml)", function () { it('blank osm', function() { var xml = "<osm></osm>"; xml = (new DOMParser()).parseFromString(xml, 'text/xml'); expect(osmtogeojson(xml, {flatProperties: false})).to.eql({ type: 'FeatureCollection', features: [] }); }); it('node', function() { var xml, geojson; xml = "<osm><node id='1' lat='1.234' lon='4.321' /></osm>"; xml = (new DOMParser()).parseFromString(xml, 'text/xml'); geojson = { type: "FeatureCollection", features: [ { type: "Feature", id: "node/1", properties: { type: "node", id: 1, tags: {}, relations: [], meta: {} }, geometry: { type: "Point", coordinates: [4.321, 1.234] } } ] }; expect(osmtogeojson(xml, {flatProperties: false})).to.eql(geojson); }); it('way', function() { var xml, geojson; xml = "<osm><way id='1'><nd ref='2' /><nd ref='3' /><nd ref='4' /></way><node id='2' lat='0.0' lon='1.0' /><node id='3' lat='0.0' lon='1.1' /><node id='4' lat='0.1' lon='1.2' /></osm>"; xml = (new DOMParser()).parseFromString(xml, 'text/xml'); geojson = { type: "FeatureCollection", features: [ { type: "Feature", id: "way/1", properties: { type: "way", id: 1, tags: {}, relations: [], meta: {} }, geometry: { type: "LineString", coordinates: [ [1.0,0.0], [1.1,0.0], [1.2,0.1], ] } } ] }; expect(osmtogeojson(xml, {flatProperties: false})).to.eql(geojson); }); it('relation', function() { var xml, geojson; xml = "<osm><relation id='1'><tag k='type' v='multipolygon' /><member type='way' ref='2' role='outer' /><member type='way' ref='3' role='inner' /></relation><way id='2'><tag k='area' v='yes' /><nd ref='4' /><nd ref='5' /><nd ref='6' /><nd ref='7' /><nd ref='4' /></way><way id='3'><nd ref='8' /><nd ref='9' /><nd ref='10' /><nd ref='8' /></way><node id='4' lat='-1.0' lon='-1.0' /><node id='5' lat='-1.0' lon='1.0' /><node id='6' lat='1.0' lon='1.0' /><node id='7' lat='1.0' lon='-1.0' /><node id='8' lat='-0.5' lon='0.0' /><node id='9' lat='0.5' lon='0.0' /><node id='10' lat='0.0' lon='0.5' /></osm>"; xml = (new DOMParser()).parseFromString(xml, 'text/xml'); geojson = { type: "FeatureCollection", features: [ { type: "Feature", id: "way/2", properties: { type: "way", id: 2, tags: {"area":"yes"}, relations: [ { rel: 1, role: "outer", reltags: {"type":"multipolygon"} } ], meta: {} }, geometry: { type: "Polygon", coordinates: [[ [-1.0,-1.0], [ 1.0,-1.0], [ 1.0, 1.0], [-1.0, 1.0], [-1.0,-1.0], ],[ [0.0,-0.5], [0.0, 0.5], [0.5, 0.0], [0.0,-0.5] ]] } } ] }; expect(osmtogeojson(xml, {flatProperties: false})).to.eql(geojson); }); }); describe("osm (json)", function () { // check overpass*2geoJSON methods it("node", function () { var json, geojson; json = { elements: [ { type: "node", id: 1, lat: 1.234, lon: 4.321 } ] }; geojson = { type: "FeatureCollection", features: [ { type: "Feature", id: "node/1", properties: { type: "node", id: 1, tags: {}, relations: [], meta: {} }, geometry: { type: "Point", coordinates: [4.321, 1.234] } } ] }; var result = osmtogeojson(json, {flatProperties: false}); expect(result).to.eql(geojson); }); it("way", function () { var json, geojson; json = { elements: [ { type: "way", id: 1, nodes: [2,3,4] }, { type: "node", id: 2, lat: 0.0, lon: 1.0 }, { type: "node", id: 3, lat: 0.0, lon: 1.1 }, { type: "node", id: 4, lat: 0.1, lon: 1.2 } ] }; geojson = { type: "FeatureCollection", features: [ { type: "Feature", id: "way/1", properties: { type: "way", id: 1, tags: {}, relations: [], meta: {} }, geometry: { type: "LineString", coordinates: [ [1.0,0.0], [1.1,0.0], [1.2,0.1], ] } } ] }; var result = osmtogeojson(json, {flatProperties: false}); expect(result).to.eql(geojson); }); it("polygon", function () { var json, geojson; json = { elements: [ { type: "way", id: 1, nodes: [2,3,4,5,2], tags: {area: "yes"} }, { type: "node", id: 2, lat: 0.0, lon: 0.0 }, { type: "node", id: 3, lat: 0.0, lon: 1.0 }, { type: "node", id: 4, lat: 1.0, lon: 1.0 }, { type: "node", id: 5, lat: 1.0, lon: 0.0 } ] }; geojson = { type: "FeatureCollection", features: [ { type: "Feature", id: "way/1", properties: { type: "way", id: 1, tags: {area: "yes"}, relations: [], meta: {} }, geometry: { type: "Polygon", coordinates: [[ [0.0,0.0], [1.0,0.0], [1.0,1.0], [0.0,1.0], [0.0,0.0], ]] } } ] }; var result = osmtogeojson(json, {flatProperties: false}); expect(result).to.eql(geojson); }); it("simple multipolygon", function () { var json, geojson; // valid simple multipolygon json = { elements: [ { type: "relation", id: 1, tags: {"type":"multipolygon"}, members: [ { type: "way", ref: 2, role: "outer" }, { type: "way", ref: 3, role: "inner" } ] }, { type: "way", id: 2, nodes: [4,5,6,7,4], tags: {"area":"yes"}, }, { type: "way", id: 3, nodes: [8,9,10,8] }, { type: "node", id: 4, lat: -1.0, lon: -1.0 }, { type: "node", id: 5, lat: -1.0, lon: 1.0 }, { type: "node", id: 6, lat: 1.0, lon: 1.0 }, { type: "node", id: 7, lat: 1.0, lon: -1.0 }, { type: "node", id: 8, lat: -0.5, lon: 0.0 }, { type: "node", id: 9, lat: 0.5, lon: 0.0 }, { type: "node", id: 10, lat: 0.0, lon: 0.5 } ] }; geojson = { type: "FeatureCollection", features: [ { type: "Feature", id: "way/2", properties: { type: "way", id: 2, tags: {"area":"yes"}, relations: [ { rel: 1, role: "outer", reltags: {"type":"multipolygon"} } ], meta: {} }, geometry: { type: "Polygon", coordinates: [[ [-1.0,-1.0], [ 1.0,-1.0], [ 1.0, 1.0], [-1.0, 1.0], [-1.0,-1.0], ],[ [0.0,-0.5], [0.0, 0.5], [0.5, 0.0], [0.0,-0.5] ]] } } ] }; var result = osmtogeojson(json, {flatProperties: false}); expect(result).to.eql(geojson); // invalid simple multipolygon (no outer way) json = { elements: [ { type: "relation", id: 1, tags: {"type":"multipolygon"}, members: [ { type: "way", ref: 2, role: "outer" }, { type: "way", ref: 3, role: "inner" } ] } ] }; geojson = { type: "FeatureCollection", features: [ ] }; result = osmtogeojson(json, {flatProperties: false}); expect(result).to.eql(geojson); }); it("multipolygon", function () { var json, geojson; // valid multipolygon json = { elements: [ { type: "relation", id: 1, tags: {"type":"multipolygon", "building":"yes"}, members: [ { type: "way", ref: 2, role: "outer" }, { type: "way", ref: 3, role: "inner" }, { type: "way", ref: 4, role: "inner" }, { type: "way", ref: 5, role: "outer" } ] }, { type: "way", id: 2, nodes: [4,5,6,7,4], tags: {"building":"yes"} }, { type: "way", id: 3, nodes: [8,9,10,8], tags: {"area":"yes"} }, { type: "way", id: 4, nodes: [11,12,13,11], tags: {"barrier":"fence"} }, { type: "way", id: 5, nodes: [14,15,16,14], tags: {"building":"yes", "area":"yes"} }, { type: "node", id: 4, lat: -1.0, lon: -1.0 }, { type: "node", id: 5, lat: -1.0, lon: 1.0 }, { type: "node", id: 6, lat: 1.0, lon: 1.0 }, { type: "node", id: 7, lat: 1.0, lon: -1.0 }, { type: "node", id: 8, lat: -0.5, lon: 0.0 }, { type: "node", id: 9, lat: 0.5, lon: 0.0 }, { type: "node", id: 10, lat: 0.0, lon: 0.5 }, { type: "node", id: 11, lat: 0.1, lon: -0.1 }, { type: "node", id: 12, lat: -0.1, lon: -0.1 }, { type: "node", id: 13, lat: 0.0, lon: -0.2 }, { type: "node", id: 14, lat: 0.1, lon: -1.1 }, { type: "node", id: 15, lat: -0.1, lon: -1.1 }, { type: "node", id: 16, lat: 0.0, lon: -1.2 } ] }; geojson = { type: "FeatureCollection", features: [ { type: "Feature", id: "relation/1", properties: { type: "relation", id: 1, tags: {"type":"multipolygon","building":"yes"}, relations: [], meta: {} }, geometry: { type: "MultiPolygon", coordinates: [[[ [-1.1, 0.1], [-1.1,-0.1], [-1.2, 0.0], [-1.1, 0.1] ].reverse()], [[ [-1.0,-1.0], [ 1.0,-1.0], [ 1.0, 1.0], [-1.0, 1.0], [-1.0,-1.0], ],[ [-0.1, 0.1], [-0.1,-0.1], [-0.2, 0.0], [-0.1, 0.1] ],[ [0.0,-0.5], [0.0, 0.5], [0.5, 0.0], [0.0,-0.5] ]]] } }, { type: "Feature", id: "way/3", properties: { type: "way", id: 3, tags: {"area":"yes"}, relations: [ { rel: 1, role: "inner", reltags: {"type":"multipolygon","building":"yes"} } ], meta: {}, }, geometry: { type: "Polygon", coordinates: [[ [0.0,-0.5], [0.0, 0.5], [0.5, 0.0], [0.0,-0.5] ].reverse()] } }, { type: "Feature", id: "way/5", properties: { type: "way", id: 5, tags: {"building":"yes", "area":"yes"}, relations: [ { rel: 1, role: "outer", reltags: {"type":"multipolygon","building":"yes"} } ], meta: {}, }, geometry: { type: "Polygon", coordinates: [[ [-1.1, 0.1], [-1.1,-0.1], [-1.2, 0.0], [-1.1, 0.1] ].reverse()] } }, { type: "Feature", id: "way/4", properties: { type: "way", id: 4, tags: {"barrier":"fence"}, relations: [ { rel: 1, role: "inner", reltags: {"type":"multipolygon","building":"yes"} } ], meta: {}, }, geometry: { type: "LineString", coordinates: [ [-0.1, 0.1], [-0.1,-0.1], [-0.2, 0.0], [-0.1, 0.1] ] } } ] }; var result = osmtogeojson(json, {flatProperties: false}); expect(result).to.eql(geojson); // handle role-less members as outer ways json.elements[0].members[3].role = ""; geojson.features[2].properties.relations[0].role = ""; result = osmtogeojson(json, {flatProperties: false}); expect(result).to.eql(geojson); }); it("route relation", function () { var json, geojson; // valid route relation json = { elements: [ { type: "relation", id: 1, tags: {"type":"route"}, members: [ { type: "way", ref: 2, role: "forward" }, { type: "way", ref: 3, role: "backward" }, { type: "way", ref: 4, role: "forward" } ] }, { type: "way", id: 2, nodes: [4,5] }, { type: "way", id: 3, nodes: [5,6] }, { type: "way", id: 4, nodes: [7,8] }, { type: "node", id: 4, lat: -1.0, lon: -1.0 }, { type: "node", id: 5, lat: 0.0, lon: 0.0 }, { type: "node", id: 6, lat: 1.0, lon: 1.0 }, { type: "node", id: 7, lat: 10.0, lon: 10.0 }, { type: "node", id: 8, lat: 20.0, lon: 20.0 } ] }; geojson = { type: "FeatureCollection", features: [ { type: "Feature", id: "relation/1", properties: { type: "relation", id: 1, tags: {"type":"route"}, relations: [], meta: {} }, geometry: { type: "MultiLineString", coordinates: [[ [-1.0,-1.0], [ 0.0, 0.0], [ 1.0, 1.0] ],[ [10.0,10.0], [20.0,20.0] ]] } } ] }; var result = osmtogeojson(json, {flatProperties: false}); function _sorter(a,b) { return a.length - b.length; } result.features[0].geometry.coordinates.sort(_sorter); geojson.features[0].geometry.coordinates.sort(_sorter); expect(result).to.eql(geojson); }); // tags & pois it("tags: ways and nodes / pois", function () { var json, geojson; json = { elements: [ { type: "way", id: 1, nodes: [2,3,4], tags: {"foo":"bar"} }, { type: "node", id: 2, lat: 0.0, lon: 1.0 }, { type: "node", id: 3, lat: 0.0, lon: 1.1, tags: {"asd":"fasd"} }, { type: "node", id: 4, lat: 0.1, lon: 1.2, tags: {"created_by":"me"} }, { type: "node", id: 5, lat: 0.0, lon: 0.0 } ] }; geojson = { type: "FeatureCollection", features: [ { type: "Feature", id: "way/1", properties: { type: "way", id: 1, tags: {"foo":"bar"}, relations: [], meta: {} }, geometry: { type: "LineString", coordinates: [ [1.0,0.0], [1.1,0.0], [1.2,0.1], ] } }, { type: "Feature", id: "node/3", properties: { type: "node", id: 3, tags: {"asd":"fasd"}, relations: [], meta: {} }, geometry: { type: "Point", coordinates: [1.1,0.0] } }, { type: "Feature", id: "node/5", properties: { type: "node", id: 5, tags: {}, relations: [], meta: {} }, geometry: { type: "Point", coordinates: [0.0,0.0] } } ] }; var result = osmtogeojson(json, {flatProperties: false}); expect(result).to.eql(geojson); }); // invalid one-node-ways it("one-node-ways", function () { var json, result; json = { elements: [ { type: "way", id: 1, nodes: [2], tags: {"foo":"bar"} }, { type: "node", id: 2, lat: 0.0, lon: 0.0 } ] }; result = osmtogeojson(json, {flatProperties: false}); expect(result.features).to.have.length(0); }); // invalid empty multipolygon it("invalid multipolygon: empty", function () { var json, result; // empty multipolygon json = { elements: [ { type: "relation", id: 1, tags: {"type":"multipolygon"} } ] }; result = osmtogeojson(json, {flatProperties: false}); expect(result.features).to.have.length(0); }); // invalid multipolygon with missing members it("invalid multipolygon: missing members", function () { var json, result; // empty multipolygon json = { elements: [ { type: "relation", id: 1, tags: {"type":"multipolygon"}, members: [{ type: "way", ref: 1, role: "outer" }] } ] }; result = osmtogeojson(json, {flatProperties: false}); expect(result.features).to.have.length(0); }); // invalid multipolygon with empty members it("invalid multipolygon: empty members", function () { var json, result; // empty multipolygon json = { elements: [ { type: "relation", id: 1, tags: {"type":"multipolygon"}, members: [{ type: "way", ref: 1, role: "outer" }] }, { type: "way", id: 1 } ] }; result = osmtogeojson(json, {flatProperties: false}); expect(result.features).to.have.length(0); }); // invalid empty route it("invalid route: empty", function () { var json, result; // empty multipolygon json = { elements: [ { type: "relation", id: 1, tags: {"type":"route"} } ] }; result = osmtogeojson(json, {flatProperties: false}); expect(result.features).to.have.length(0); }); // invalid route with missing members it("invalid route: missing members", function () { var json, result; // empty multipolygon json = { elements: [ { type: "relation", id: 1, tags: {"type":"route"}, members: [{ type: "way", ref: 1, role: "forward" }] } ] }; result = osmtogeojson(json, {flatProperties: false}); expect(result.features).to.have.length(0); }); // invalid route with empty members it("invalid route: empty members", function () { var json, result; // empty multipolygon json = { elements: [ { type: "relation", id: 1, tags: {"type":"route"}, members: [{ type: "way", ref: 1, role: "forward" }] }, { type: "way", id: 1 } ] }; result = osmtogeojson(json, {flatProperties: false}); expect(result.features).to.have.length(0); }); // relations it("relations and id-spaces", function () { var json, geojson; json = { elements: [ { type: "way", id: 1, tags: {"foo":"bar"}, nodes: [1,2,3] }, { type: "way", id: 2, nodes: [3,1] }, { type: "node", id: 1, lat: 1.0, lon: 1.0 }, { type: "node", id: 2, lat: 2.0, lon: 2.0 }, { type: "node", id: 3, lat: 1.0, lon: 2.0 }, { type: "relation", id: 1, tags: {"foo":"bar"}, members: [ { type: "way", ref: 1, role: "asd" }, { type: "node", ref: 1, role: "fasd" }, { type: "relation", ref: 2, role: "" } ] }, { type: "relation", id: 2, tags: {"type":"multipolygon"}, members: [ { type: "way", ref: 1, role: "outer" }, { type: "way", ref: 2, role: "outer" } ] } ] }; geojson = { type: "FeatureCollection", features: [ { type: "Feature", id: "relation/2", properties: { type: "relation", id: 2, tags: {"type":"multipolygon"}, relations: [ { rel: 1, role: "", reltags: {"foo":"bar"} } ], meta: {} }, geometry: { type: "Polygon", coordinates: [[ [2.0,1.0], [1.0,1.0], [2.0,2.0], [2.0,1.0] ].reverse()] } }, { type: "Feature", id: "way/1", properties: { type: "way", id: 1, tags: {"foo":"bar"}, relations: [ { rel: 1, role: "asd", reltags: {"foo":"bar"} }, { rel: 2, role: "outer", reltags: {"type":"multipolygon"} } ], meta: {} }, geometry: { type: "LineString", coordinates: [ [1.0,1.0], [2.0,2.0], [2.0,1.0] ] } }, { type: "Feature", id: "node/1", properties: { type: "node", id: 1, tags: {}, relations: [ { rel: 1, role: "fasd", reltags: {"foo":"bar"} } ], meta: {} }, geometry: { type: "Point", coordinates: [1.0,1.0] } } ] }; var result = osmtogeojson(json, {flatProperties: false}); expect(result).to.eql(geojson); }); // meta info // todo +lines, +polygons it("meta data", function () { var json, geojson, result; // node with meta data json = { elements: [ { type: "node", id: 1, lat: 1.234, lon: 4.321, timestamp: "2013-01-13T22:56:07Z", version: 7, changeset: 1234, user: "johndoe", uid: 666 } ] }; geojson = { type: "FeatureCollection", features: [ { type: "Feature", id: "node/1", properties: { type: "node", id: 1, tags: {}, relations: [], meta: { timestamp: "2013-01-13T22:56:07Z", version: 7, changeset: 1234, user: "johndoe", uid: 666 } }, geometry: { type: "Point", coordinates: [4.321, 1.234] } } ] }; result = osmtogeojson(json, {flatProperties: false}); expect(result).to.eql(geojson); // ways and relsvar json, geojson; json = { elements: [ { type: "node", id: 1, lat: 1.234, lon: 4.321, tags: {"amenity": "yes"}, user: "johndoe", }, { type: "way", id: 1, tags: {"highway": "road"}, user: "johndoe", nodes: [1,1,1,1] }, { type: "relation", id: 1, tags: {"type": "multipolygon"}, user: "johndoe", members: [{type:"way",ref:1,role:"outer"},{type:"way",ref:1,role:"outer"}] }, { type: "way", id: 2, tags: {"highway": "road"}, user: "johndoe", nodes: [1,1,1,1] }, { type: "relation", id: 2, tags: {"type": "multipolygon"}, user: "johndoe", members: [{type:"way",ref:2,role:"outer"}] } ] }; result = osmtogeojson(json, {flatProperties: false}); expect(result.features).to.have.length(4); expect(result.features[0].properties.meta).to.have.property("user"); expect(result.features[1].properties.meta).to.have.property("user"); expect(result.features[2].properties.meta).to.have.property("user"); expect(result.features[3].properties.meta).to.have.property("user"); }); // multipolygon detection corner case // see https://github.com/tyrasd/osmtogeojson/issues/7 it("multipolygon: outer way tagging", function () { var json; json = { elements: [ { type: "relation", id: 1, tags: {"type":"multipolygon", "amenity":"xxx"}, members: [ { type: "way", ref: 2, role: "outer" }, { type: "way", ref: 3, role: "inner" } ] }, { type: "way", id: 2, nodes: [4,5,6,7,4], tags: {"amenity":"yyy"} }, { type: "way", id: 3, nodes: [8,9,10,8] }, { type: "node", id: 4, lat: -1.0, lon: -1.0 }, { type: "node", id: 5, lat: -1.0, lon: 1.0 }, { type: "node", id: 6, lat: 1.0, lon: 1.0 }, { type: "node", id: 7, lat: 1.0, lon: -1.0 }, { type: "node", id: 8, lat: -0.5, lon: 0.0 }, { type: "node", id: 9, lat: 0.5, lon: 0.0 }, { type: "node", id: 10, lat: 0.0, lon: 0.5 } ] }; var result = osmtogeojson(json, {flatProperties: false}); expect(result.features).to.have.length(2); expect(result.features[0].properties.id).to.eql(1); expect(result.features[1].properties.id).to.eql(2); }); // non-matching inner and outer rings it("multipolygon: non-matching inner and outer rings", function() { // complex multipolygon json = { elements: [ { type: "relation", tags: {"type": "multipolygon"}, id: 1, members: [ { type: "way", ref: 2, role: "outer" }, { type: "way", ref: -1, role: "outer" }, { type: "way", ref: 3, role: "inner" } ] }, { type: "way", id: 2, nodes: [4,5,6,7,4] }, { type: "node", id: 4, lat: 0.0, lon: 0.0 }, { type: "node", id: 5, lat: 1.0, lon: 0.0 }, { type: "node", id: 6, lat: 1.0, lon: 1.0 }, { type: "node", id: 7, lat: 0.0, lon: 1.0 }, { type: "way", id: 3, nodes: [8,9,10,8] }, { type: "node", id: 8, lat: 3.0, lon: 3.0 }, { type: "node", id: 9, lat: 4.0, lon: 3.0 }, { type: "node", id: 10, lat: 3.0, lon: 4.0 } ] }; result = osmtogeojson(json, {flatProperties: false}); expect(result.features).to.have.length(1); expect(result.features[0].properties.id).to.equal(1); expect(result.features[0].geometry.type).to.equal("Polygon"); expect(result.features[0].geometry.coordinates).to.have.length(1); // simple multipolygon json = { elements: [ { type: "relation", tags: {"type": "multipolygon"}, id: 1, members: [ { type: "way", ref: 2, role: "outer" }, { type: "way", ref: 3, role: "inner" } ] }, { type: "way", id: 2, nodes: [4,5,6,7,4] }, { type: "node", id: 4, lat: 0.0, lon: 0.0 }, { type: "node", id: 5, lat: 1.0, lon: 0.0 }, { type: "node", id: 6, lat: 1.0, lon: 1.0 }, { type: "node", id: 7, lat: 0.0, lon: 1.0 }, { type: "way", id: 3, nodes: [8,9,10,8] }, { type: "node", id: 8, lat: 3.0, lon: 3.0 }, { type: "node", id: 9, lat: 4.0, lon: 3.0 }, { type: "node", id: 10, lat: 3.0, lon: 4.0 } ] }; result = osmtogeojson(json, {flatProperties: false}); expect(result.features).to.have.length(1); expect(result.features[0].properties.id).to.equal(2); expect(result.features[0].geometry.type).to.equal("Polygon"); expect(result.features[0].geometry.coordinates).to.have.length(1); }); // non-trivial ring building (way order and direction) it("multipolygon: non-trivial ring building", function() { // way order json = { elements: [ { type: "relation", tags: {"type": "multipolygon"}, id: 1, members: [ { type: "way", ref: 1, role: "outer" }, { type: "way", ref: 3, role: "outer" }, { type: "way", ref: 2, role: "outer" } ] }, { type: "way", id: 1, nodes: [1,2] }, { type: "way", id: 2, nodes: [2,3] }, { type: "way", id: 3, nodes: [3,1] }, { type: "node", id: 1, lat: 1.0, lon: 0.0 }, { type: "node", id: 2, lat: 2.0, lon: 0.0 }, { type: "node", id: 3, lat: 3.0, lon: 0.0 } ] }; result = osmtogeojson(json, {flatProperties: false}); expect(result.features).to.have.length(1); expect(result.features[0].properties.id).to.equal(1); expect(result.features[0].geometry.type).to.equal("Polygon"); expect(result.features[0].geometry.coordinates).to.have.length(1); expect(result.features[0].geometry.coordinates[0]).to.have.length(4); // way directions json = { elements: [ { type: "relation", tags: {"type": "multipolygon"}, id: 1, members: [ { type: "way", ref: 1, role: "outer" }, { type: "way", ref: 2, role: "outer" }, { type: "way", ref: 3, role: "outer" }, { type: "way", ref: 4, role: "outer" }, { type: "way", ref: 5, role: "outer" }, { type: "way", ref: 6, role: "outer" } ] }, { type: "way", id: 1, nodes: [1,2] }, { type: "way", id: 2, nodes: [2,3] }, { type: "way", id: 3, nodes: [4,3] }, { type: "way", id: 4, nodes: [5,4] }, { type: "way", id: 5, nodes: [5,6] }, { type: "way", id: 6, nodes: [1,6] }, { type: "node", id: 1, lat: 1.0, lon: 0.0 }, { type: "node", id: 2, lat: 2.0, lon: 0.0 }, { type: "node", id: 3, lat: 3.0, lon: 0.0 }, { type: "node", id: 4, lat: 4.0, lon: 0.0 }, { type: "node", id: 5, lat: 5.0, lon: 0.0 }, { type: "node", id: 6, lat: 6.0, lon: 0.0 } ] }; result = osmtogeojson(json, {flatProperties: false}); expect(result.features).to.have.length(1); expect(result.features[0].properties.id).to.equal(1); expect(result.features[0].geometry.type).to.equal("Polygon"); expect(result.features[0].geometry.coordinates).to.have.length(1); expect(result.features[0].geometry.coordinates[0]).to.have.length(7); }); // unclosed rings it("multipolygon: unclosed ring", function() { // non-matching ways, unclosed rings json = { elements: [ { type: "relation", tags: {"type": "multipolygon"}, id: 1, members: [ { type: "way", ref: 1, role: "outer" }, { type: "way", ref: 2, role: "outer" } ] }, { type: "way", id: 1, nodes: [1,2,3,4] }, { type: "way", id: 2, nodes: [3,2] }, { type: "node", id: 1, lat: 1.0, lon: 0.0 }, { type: "node", id: 2, lat: 2.0, lon: 0.0 }, { type: "node", id: 3, lat: 3.0, lon: 0.0 }, { type: "node", id: 4, lat: 4.0, lon: 0.0 } ] }; result = osmtogeojson(json, {flatProperties: false}); expect(result.features).to.have.length(1); expect(result.features[0].properties.id).to.equal(1); expect(result.features[0].geometry.type).to.equal("Polygon"); expect(result.features[0].geometry.coordinates).to.have.length(1); expect(result.features[0].geometry.coordinates[0]).to.have.length(4); expect(result.features[0].properties.tainted).to.not.equal(true); // matching ways, but unclosed ring json = { elements: [ { type: "relation", tags: {"type": "multipolygon"}, id: 1, members: [ { type: "way", ref: 1, role: "outer" }, { type: "way", ref: 2, role: "outer" } ] }, { type: "way", id: 1, nodes: [1,2] }, { type: "way", id: 2, nodes: [2,3,4] }, { type: "node", id: 1, lat: 1.0, lon: 0.0 }, { type: "node", id: 2, lat: 2.0, lon: 0.0 }, { type: "node", id: 3, lat: 3.0, lon: 0.0 }, { type: "node", id: 4, lat: 4.0, lon: 0.0 } ] }; result = osmtogeojson(json, {flatProperties: false}); expect(result.features).to.have.length(1); expect(result.features[0].properties.id).to.equal(1); expect(result.features[0].geometry.type).to.equal("Polygon"); expect(result.features[0].geometry.coordinates).to.have.length(1); expect(result.features[0].geometry.coordinates[0]).to.have.length(4); expect(result.features[0].properties.tainted).to.not.equal(true); }); // overpass area it("overpass area", function () { var json, geojson_properties; json = { elements: [ { type: "area", id: 1, } ] }; var result = osmtogeojson(json, {flatProperties: false}); expect(result.features).to.have.length(0); }); }); describe("defaults", function() { // interesting objects it("interesting objects", function () { var json, result; json = { elements: [ { type: "way", id: 1, nodes: [1,2] }, { type: "node", id: 1, tags: {"created_by": "foo"}, lat: 1.0, lon: 0.0 }, { type: "node", id: 2, tags: {"interesting": "yes"}, lat: 2.0, lon: 0.0 } ] }; var result = osmtogeojson(json, {flatProperties: false}); expect(result.features).to.have.length(2); expect(result.features[0].geometry.type).to.equal("LineString"); expect(result.features[1].geometry.type).to.equal("Point"); expect(result.features[1].properties.id).to.equal(2); }); // interesting objects it("interesting objects: relation members", function() { // complex example containing a generic relation, several ways as well as // tagged, uninteresting and untagged nodes // see https://github.com/openstreetmap/openstreetmap-website/pull/283 var xml; xml = '<osm version="0.6" generator="OpenStreetMap server" copyright="OpenStreetMap and contributors" attribution="https://www.openstreetmap.org/copyright" license="https://opendatacommons.org/licenses/odbl/1-0/">'+ '<relation id="4294968148" visible="true" timestamp="2013-05-14T10:33:05Z" version="1" changeset="23123" user="tyrTester06" uid="1178">'+ '<member type="way" ref="4295032195" role="line"/>'+ '<member type="node" ref="4295668179" role="point"/>'+ '<member type="node" ref="4295668178" role=""/>'+ '<member type="way" ref="4295032194" role=""/>'+ '<member type="way" ref="4295032193" role=""/>'+ '<member type="node" ref="4295668174" role="foo"/>'+ '<member type="node" ref="4295668175" role="bar"/>'+ '<tag k="type" v="fancy"/>'+ '</relation>'+ '<way id="4295032195" visible="true" timestamp="2013-05-14T10:33:05Z" version="1" changeset="23123" user="tyrTester06" uid="1178">'+ '<nd ref="4295668174"/>'+ '<nd ref="4295668172"/>'+ '<nd ref="4295668171"/>'+ '<nd ref="4295668170"/>'+ '<nd ref="4295668173"/>'+ '<nd ref="4295668175"/>'+ '<tag k="highway" v="residential"/>'+ '</way>'+ '<way id="4295032194" visible="true" timestamp="2013-05-14T10:33:05Z" version="1" changeset="23123" user="tyrTester06" uid="1178">'+ '<nd ref="4295668177"/>'+ '<nd ref="4295668178"/>'+ '<nd ref="4295668180"/>'+ '<tag k="highway" v="service"/>'+ '</way>'+ '<way id="4295032193" visible="true" timestamp="2013-05-14T10:33:04Z" version="1" changeset="23123" user="tyrTester06" uid="1178">'+ '<nd ref="4295668181"/>'+ '<nd ref="4295668178"/>'+ '<nd ref="4295668176"/>'+ '<tag k="highway" v="service"/>'+ '</way>'+ '<node id="4295668172" version="1" changeset="23123" lat="46.4910906" lon="11.2735763" user="tyrTester06" uid="1178" visible="true" timestamp="2013-05-14T10:33:04Z">'+ '<tag k="highway" v="crossing"/>'+ '</node>'+ '<node id="4295668173" version="1" changeset="23123" lat="46.4911004" lon="11.2759498" user="tyrTester06" uid="1178" visible="true" timestamp="2013-05-14T10:33:04Z">'+ '<tag k="created_by" v="foo"/>'+ '</node>'+ '<node id="4295668170" version="1" changeset="23123" lat="46.4909732" lon="11.2753813" user="tyrTester06" uid="1178" visible="true" timestamp="2013-05-14T10:33:04Z"/>'+ '<node id="4295668171" version="1" changeset="23123" lat="46.4909781" lon="11.2743295" user="tyrTester06" uid="1178" visible="true" timestamp="2013-05-14T10:33:04Z"/>'+ '<node id="4295668174" version="1" changeset="23123" lat="46.4914820" lon="11.2731001" user="tyrTester06" uid="1178" visible="true" timestamp="2013-05-14T10:33:04Z"/>'+ '<node id="4295668175" version="1" changeset="23123" lat="46.4915603" lon="11.2765254" user="tyrTester06" uid="1178" visible="true" timestamp="2013-05-14T10:33:04Z"/>'+ '<node id="4295668176" version="1" changeset="23123" lat="46.4919468" lon="11.2756726" user="tyrTester06" uid="1178" visible="true" timestamp="2013-05-14T10:33:04Z"/>'+ '<node id="4295668177" version="1" changeset="23123" lat="46.4919664" lon="11.2753031" user="tyrTester06" uid="1178" visible="true" timestamp="2013-05-14T10:33:04Z"/>'+ '<node id="4295668178" version="1" changeset="23123" lat="46.4921083" lon="11.2755021" user="tyrTester06" uid="1178" visible="true" timestamp="2013-05-14T10:33:04Z"/>'+ '<node id="4295668179" version="1" changeset="23123" lat="46.4921327" lon="11.2742229" user="tyrTester06" uid="1178" visible="true" timestamp="2013-05-14T10:33:04Z"/>'+ '<node id="4295668180" version="1" changeset="23123" lat="46.4922893" lon="11.2757152" user="tyrTester06" uid="1178" visible="true" timestamp="2013-05-14T10:33:04Z"/>'+ '<node id="4295668181" version="1" changeset="23123" lat="46.4923235" lon="11.2752747" user="tyrTester06" uid="1178" visible="true" timestamp="2013-05-14T10:33:04Z"/>'+ '</osm>' xml = (new DOMParser()).parseFromString(xml, 'text/xml'); var result = osmtogeojson(xml, {flatProperties: false}); expect(result.features).to.have.length(8); }); // polygon detection // see: https://wiki.openstreetmap.org/wiki/Overpass_turbo/Polygon_Features it("polygon detection", function () { var json, result; // basic tags: area=yes json = { elements: [ { type: "way", id: 1, tags: {"foo":"bar", "area": "yes"}, nodes: [1,2,3,1] }, { type: "way", id: 2, tags: {"area": "yes"}, nodes: [1,2,3] }, { type: "node", id: 1, lat: 1.0, lon: 0.0 }, { type: "node", id: 2, lat: 2.0, lon: 0.0 }, { type: "node", id: 3, lat: 0.0, lon: 3.0 } ] }; result = osmtogeojson(json, {flatProperties: false}); expect(result.features).to.have.length(2); expect(result.features[0].geometry.type).to.equal("Polygon"); expect(result.features[1].geometry.type).to.equal("LineString"); // basic tags: area=no json = { elements: [ { type: "way", id: 1, tags: { "area": "no", "building": "yes" }, nodes: [1,2,3,1] }, { type: "node", id: 1, lat: 1.0, lon: 0.0 }, { type: "node", id: 2, lat: 2.0, lon: 0.0 }, { type: "node", id: 3, lat: 0.0, lon: 3.0 } ] }; result = osmtogeojson(json, {flatProperties: false}); expect(result.features).to.have.length(1); expect(result.features[0].geometry.type).to.equal("LineString"); }); }); describe("options", function () { // flattened properties output mode it("flattened properties", function () { var json, geojson_properties; json = { elements: [ { type: "node", id: 1, tags: {"foo": "bar"}, user: "johndoe", lat: 1.234, lon: 4.321 } ] }; geojson_properties= { id: "node/1", foo: "bar", user: "johndoe" }; var result = osmtogeojson(json, {flatProperties: true}); expect(result.features[0].properties).to.eql(geojson_properties); // check default result