osmtogeojson
Advanced tools
Comparing version 1.4.0 to 2.0.0
@@ -0,1 +1,9 @@ | ||
2.0.0 | ||
----- | ||
* simpler API (module exports as a plain function), old `.toGeojson` still available as a fallback | ||
* output (multi)polygons with consistent winding orders | ||
* improve handling of simple multipolygons | ||
* use browserify for browser library (comes bundeled with dependencies) | ||
* some minor speed improvements | ||
1.4.0 | ||
@@ -2,0 +10,0 @@ ----- |
@@ -1,683 +0,1 @@ | ||
if (typeof require !== "undefined") { | ||
_ = require("lodash"); | ||
} | ||
var osmtogeojson = {}; | ||
osmtogeojson.toGeojson = function( data, options ) { | ||
options = _.merge( | ||
{ | ||
flatProperties: false, | ||
uninterestingTags: { | ||
"source": true, | ||
"source_ref": true, | ||
"source:ref": true, | ||
"history": true, | ||
"attribution": true, | ||
"created_by": true, | ||
"tiger:county": true, | ||
"tiger:tlid": true, | ||
"tiger:upload_uuid": true | ||
}, | ||
polygonFeatures: { | ||
"building": true, | ||
"highway": { | ||
"included_values": { | ||
"services": true, | ||
"rest_area": true, | ||
"escape": true | ||
} | ||
}, | ||
"natural": { | ||
"excluded_values": { | ||
"coastline": true, | ||
"ridge": true, | ||
"arete": true, | ||
"tree_row": true | ||
} | ||
}, | ||
"landuse": true, | ||
"waterway": { | ||
"included_values": { | ||
"riverbank": true, | ||
"dock": true, | ||
"boatyard": true, | ||
"dam": true | ||
} | ||
}, | ||
"amenity": true, | ||
"leisure": true, | ||
"barrier": { | ||
"included_values": { | ||
"city_wall": true, | ||
"ditch": true, | ||
"hedge": true, | ||
"retaining_wall": true, | ||
"wall": true, | ||
"spikes": true | ||
} | ||
}, | ||
"railway": { | ||
"included_values": { | ||
"station": true, | ||
"turntable": true, | ||
"roundhouse": true, | ||
"platform": true | ||
} | ||
}, | ||
"area": true, | ||
"boundary": true, | ||
"man_made": { | ||
"excluded_values": { | ||
"cutline": true, | ||
"embankment": true, | ||
"pipeline": true | ||
} | ||
}, | ||
"power": { | ||
"included_values": { | ||
"generator": true, | ||
"station": true, | ||
"sub_station": true, | ||
"transformer": true | ||
} | ||
}, | ||
"place": true, | ||
"shop": true, | ||
"aeroway": { | ||
"excluded_values": { | ||
"taxiway": true | ||
} | ||
}, | ||
"tourism": true, | ||
"historic": true, | ||
"public_transport": true, | ||
"office": true, | ||
"building:part": true, | ||
"military": true, | ||
"ruins": true, | ||
"area:highway": true, | ||
"craft": true | ||
} | ||
}, | ||
options | ||
); | ||
var result; | ||
if ( ((typeof XMLDocument !== "undefined") && data instanceof XMLDocument || | ||
(typeof XMLDocument === "undefined") && data.childNodes) ) | ||
result = _osmXML2geoJSON(data); | ||
else | ||
result = _overpassJSON2geoJSON(data); | ||
return result; | ||
function _overpassJSON2geoJSON(json) { | ||
// sort elements | ||
var nodes = new Array(); | ||
var ways = new Array(); | ||
var rels = new Array(); | ||
// create copies of individual json objects to make sure the original data doesn't get altered | ||
// todo: cloning is slow: see if this can be done differently! | ||
for (var i=0;i<json.elements.length;i++) { | ||
switch (json.elements[i].type) { | ||
case "node": | ||
var node = _.clone(json.elements[i]); | ||
// todo: this clone could be avoided if we didn't store relations directly within the raw data | ||
// see https://github.com/tyrasd/osmtogeojson/blob/gh-pages/osmtogeojson.js#L298-L302 | ||
nodes.push(node); | ||
break; | ||
case "way": | ||
var way = _.clone(json.elements[i]); | ||
way.nodes = _.clone(way.nodes); | ||
ways.push(way); | ||
break; | ||
case "relation": | ||
var rel = _.clone(json.elements[i]); | ||
rel.members = _.clone(rel.members); | ||
rels.push(rel); | ||
break; | ||
default: | ||
// type=area (from coord-query) is an example for this case. | ||
} | ||
} | ||
return _convert2geoJSON(nodes,ways,rels); | ||
} | ||
function _osmXML2geoJSON(xml) { | ||
// helper function | ||
function copy_attribute( x, o, attr ) { | ||
if (x.hasAttribute(attr)) | ||
o[attr] = x.getAttribute(attr); | ||
} | ||
// sort elements | ||
var nodes = new Array(); | ||
var ways = new Array(); | ||
var rels = new Array(); | ||
// nodes | ||
_.each( xml.getElementsByTagName('node'), function( node, i ) { | ||
var tags = {}; | ||
_.each( node.getElementsByTagName('tag'), function( tag ) { | ||
tags[tag.getAttribute('k')] = tag.getAttribute('v'); | ||
}); | ||
nodes[i] = { | ||
'type': 'node' | ||
}; | ||
copy_attribute( node, nodes[i], 'id' ); | ||
copy_attribute( node, nodes[i], 'lat' ); | ||
copy_attribute( node, nodes[i], 'lon' ); | ||
copy_attribute( node, nodes[i], 'version' ); | ||
copy_attribute( node, nodes[i], 'timestamp' ); | ||
copy_attribute( node, nodes[i], 'changeset' ); | ||
copy_attribute( node, nodes[i], 'uid' ); | ||
copy_attribute( node, nodes[i], 'user' ); | ||
if (!_.isEmpty(tags)) | ||
nodes[i].tags = tags; | ||
}); | ||
// ways | ||
_.each( xml.getElementsByTagName('way'), function( way, i ) { | ||
var tags = {}; | ||
var wnodes = []; | ||
_.each( way.getElementsByTagName('tag'), function( tag ) { | ||
tags[tag.getAttribute('k')] = tag.getAttribute('v'); | ||
}); | ||
_.each( way.getElementsByTagName('nd'), function( nd, i ) { | ||
wnodes[i] = nd.getAttribute('ref'); | ||
}); | ||
ways[i] = { | ||
"type": "way" | ||
}; | ||
copy_attribute( way, ways[i], 'id' ); | ||
copy_attribute( way, ways[i], 'version' ); | ||
copy_attribute( way, ways[i], 'timestamp' ); | ||
copy_attribute( way, ways[i], 'changeset' ); | ||
copy_attribute( way, ways[i], 'uid' ); | ||
copy_attribute( way, ways[i], 'user' ); | ||
if (wnodes.length > 0) | ||
ways[i].nodes = wnodes; | ||
if (!_.isEmpty(tags)) | ||
ways[i].tags = tags; | ||
}); | ||
// relations | ||
_.each( xml.getElementsByTagName('relation'), function( relation, i ) { | ||
var tags = {}; | ||
var members = []; | ||
_.each( relation.getElementsByTagName('tag'), function( tag ) { | ||
tags[tag.getAttribute('k')] = tag.getAttribute('v'); | ||
}); | ||
_.each( relation.getElementsByTagName('member'), function( member, i ) { | ||
members[i] = {}; | ||
copy_attribute( member, members[i], 'ref' ); | ||
copy_attribute( member, members[i], 'role' ); | ||
copy_attribute( member, members[i], 'type' ); | ||
}); | ||
rels[i] = { | ||
"type": "relation" | ||
} | ||
copy_attribute( relation, rels[i], 'id' ); | ||
copy_attribute( relation, rels[i], 'version' ); | ||
copy_attribute( relation, rels[i], 'timestamp' ); | ||
copy_attribute( relation, rels[i], 'changeset' ); | ||
copy_attribute( relation, rels[i], 'uid' ); | ||
copy_attribute( relation, rels[i], 'user' ); | ||
if (members.length > 0) | ||
rels[i].members = members; | ||
if (!_.isEmpty(tags)) | ||
rels[i].tags = tags; | ||
}); | ||
return _convert2geoJSON(nodes,ways,rels); | ||
} | ||
function _convert2geoJSON(nodes,ways,rels) { | ||
// helper function that checks if there are any tags other than "created_by", "source", etc. or any tag provided in ignore_tags | ||
function has_interesting_tags(t, ignore_tags) { | ||
if (typeof ignore_tags !== "object") | ||
ignore_tags={}; | ||
if (typeof options.uninterestingTags === "function") | ||
return !options.uninterestingTags(t, ignore_tags); | ||
for (var k in t) | ||
if (!(options.uninterestingTags[k]===true) && | ||
!(ignore_tags[k]===true || ignore_tags[k]===t[k])) | ||
return true; | ||
return false; | ||
}; | ||
// some data processing (e.g. filter nodes only used for ways) | ||
var nodeids = new Object(); | ||
for (var i=0;i<nodes.length;i++) { | ||
if (nodes[i].lat === undefined) | ||
continue; // ignore nodes without coordinates (e.g. returned by an ids_only query) | ||
nodeids[nodes[i].id] = nodes[i]; | ||
} | ||
var poinids = new Object(); | ||
for (var i=0;i<nodes.length;i++) { | ||
if (typeof nodes[i].tags != 'undefined' && | ||
has_interesting_tags(nodes[i].tags)) // this checks if the node has any tags other than "created_by" | ||
poinids[nodes[i].id] = true; | ||
} | ||
for (var i=0;i<rels.length;i++) { | ||
if (!_.isArray(rels[i].members)) | ||
continue; // ignore relations without members (e.g. returned by an ids_only query) | ||
for (var j=0;j<rels[i].members.length;j++) { | ||
if (rels[i].members[j].type == "node") | ||
poinids[rels[i].members[j].ref] = true; | ||
} | ||
} | ||
var wayids = new Object(); | ||
var waynids = new Object(); | ||
for (var i=0;i<ways.length;i++) { | ||
if (!_.isArray(ways[i].nodes)) | ||
continue; // ignore ways without nodes (e.g. returned by an ids_only query) | ||
wayids[ways[i].id] = ways[i]; | ||
for (var j=0;j<ways[i].nodes.length;j++) { | ||
waynids[ways[i].nodes[j]] = true; | ||
ways[i].nodes[j] = nodeids[ways[i].nodes[j]]; | ||
} | ||
} | ||
var pois = new Array(); | ||
for (var i=0;i<nodes.length;i++) { | ||
if ((!waynids[nodes[i].id]) || | ||
(poinids[nodes[i].id])) | ||
pois.push(nodes[i]); | ||
} | ||
var relids = new Array(); | ||
for (var i=0;i<rels.length;i++) { | ||
if (!_.isArray(rels[i].members)) | ||
continue; // ignore relations without members (e.g. returned by an ids_only query) | ||
relids[rels[i].id] = rels[i]; | ||
} | ||
for (var i=0;i<rels.length;i++) { | ||
if (!_.isArray(rels[i].members)) | ||
continue; // ignore relations without members (e.g. returned by an ids_only query) | ||
for (var j=0;j<rels[i].members.length;j++) { | ||
var m; | ||
switch (rels[i].members[j].type) { | ||
case "node": | ||
m = nodeids[rels[i].members[j].ref]; | ||
break; | ||
case "way": | ||
m = wayids[rels[i].members[j].ref]; | ||
break; | ||
case "relation": | ||
m = relids[rels[i].members[j].ref]; | ||
break; | ||
} | ||
if (m) { // typeof m != "undefined" | ||
if (typeof m.relations == "undefined") | ||
m.relations = new Array(); | ||
m.relations.push({ | ||
"role" : rels[i].members[j].role, | ||
"rel" : rels[i].id, | ||
"reltags" : rels[i].tags, | ||
}); | ||
} | ||
} | ||
} | ||
// construct geojson | ||
var geojson; | ||
var geojsonnodes = { | ||
"type" : "FeatureCollection", | ||
"features" : new Array()}; | ||
for (i=0;i<pois.length;i++) { | ||
if (typeof pois[i].lon == "undefined" || typeof pois[i].lat == "undefined") | ||
continue; // lon and lat are required for showing a point | ||
geojsonnodes.features.push({ | ||
"type" : "Feature", | ||
"id" : "node/"+pois[i].id, | ||
"properties" : { | ||
"type" : "node", | ||
"id" : pois[i].id, | ||
"tags" : pois[i].tags || {}, | ||
"relations" : pois[i].relations || [], | ||
"meta": function(o){var res={}; for(k in o) if(o[k] != undefined) res[k]=o[k]; return res;}({"timestamp": pois[i].timestamp, "version": pois[i].version, "changeset": pois[i].changeset, "user": pois[i].user, "uid": pois[i].uid}), | ||
}, | ||
"geometry" : { | ||
"type" : "Point", | ||
"coordinates" : [+pois[i].lon, +pois[i].lat], | ||
} | ||
}); | ||
} | ||
var geojsonlines = { | ||
"type" : "FeatureCollection", | ||
"features" : new Array()}; | ||
var geojsonpolygons = { | ||
"type" : "FeatureCollection", | ||
"features" : new Array()}; | ||
// process multipolygons | ||
for (var i=0;i<rels.length;i++) { | ||
if ((typeof rels[i].tags != "undefined") && | ||
(rels[i].tags["type"] == "multipolygon" || rels[i].tags["type"] == "boundary")) { | ||
if (!_.isArray(rels[i].members)) | ||
continue; // ignore relations without members (e.g. returned by an ids_only query) | ||
var outer_count = 0; | ||
for (var j=0;j<rels[i].members.length;j++) | ||
if (rels[i].members[j].role == "outer") | ||
outer_count++; | ||
_.each(rels[i].members, function(m) { | ||
if (wayids[m.ref]) { | ||
// this even works in the following corner case: | ||
// a multipolygon amenity=xxx with outer line tagged amenity=yyy | ||
// see https://github.com/tyrasd/osmtogeojson/issues/7 | ||
if (m.role==="outer" && !has_interesting_tags(wayids[m.ref].tags,rels[i].tags)) | ||
wayids[m.ref].is_multipolygon_outline = true; | ||
if (m.role==="inner" && !has_interesting_tags(wayids[m.ref].tags)) | ||
wayids[m.ref].is_multipolygon_outline = true; | ||
} | ||
}); | ||
if (outer_count == 0) | ||
continue; // ignore multipolygons without outer ways | ||
var simple_mp = false; | ||
if (outer_count == 1 && !has_interesting_tags(rels[i].tags, {"type":true})) | ||
simple_mp = true; | ||
if (!simple_mp) { | ||
var is_tainted = false; | ||
// prepare mp members | ||
var members; | ||
members = _.filter(rels[i].members, function(m) {return m.type === "way";}); | ||
members = _.map(members, function(m) { | ||
var way = wayids[m.ref]; | ||
if (way === undefined) { // check for missing ways | ||
is_tainted = true; | ||
return; | ||
} | ||
return { // TODO: this is slow! :( | ||
id: m.ref, | ||
role: m.role || "outer", | ||
way: way, | ||
nodes: _.filter(way.nodes, function(n) { | ||
if (n !== undefined) | ||
return true; | ||
is_tainted = true; | ||
return false; | ||
}) | ||
}; | ||
}); | ||
members = _.compact(members); | ||
// construct outer and inner rings | ||
var outers, inners; | ||
function join(ways) { | ||
var _first = function(arr) {return arr[0]}; | ||
var _last = function(arr) {return arr[arr.length-1]}; | ||
// stolen from iD/relation.js | ||
var joined = [], current, first, last, i, how, what; | ||
while (ways.length) { | ||
current = ways.pop().nodes.slice(); | ||
joined.push(current); | ||
while (ways.length && _first(current) !== _last(current)) { | ||
first = _first(current); | ||
last = _last(current); | ||
for (i = 0; i < ways.length; i++) { | ||
what = ways[i].nodes; | ||
if (last === _first(what)) { | ||
how = current.push; | ||
what = what.slice(1); | ||
break; | ||
} else if (last === _last(what)) { | ||
how = current.push; | ||
what = what.slice(0, -1).reverse(); | ||
break; | ||
} else if (first == _last(what)) { | ||
how = current.unshift; | ||
what = what.slice(0, -1); | ||
break; | ||
} else if (first == _first(what)) { | ||
how = current.unshift; | ||
what = what.slice(1).reverse(); | ||
break; | ||
} else { | ||
what = how = null; | ||
} | ||
} | ||
if (!what) | ||
break; // Invalid geometry (dangling way, unclosed ring) | ||
ways.splice(i, 1); | ||
how.apply(current, what); | ||
} | ||
} | ||
return joined; | ||
} | ||
outers = join(_.filter(members, function(m) {return m.role==="outer";})); | ||
inners = join(_.filter(members, function(m) {return m.role==="inner";})); | ||
// sort rings | ||
var mp; | ||
function findOuter(inner) { | ||
var polygonIntersectsPolygon = function(outer, inner) { | ||
for (var i=0; i<inner.length; i++) | ||
if (pointInPolygon(inner[i], outer)) | ||
return true; | ||
return false; | ||
} | ||
var mapCoordinates = function(from) { | ||
return _.map(from, function(n) { | ||
return [+n.lat,+n.lon]; | ||
}); | ||
} | ||
// stolen from iD/geo.js, | ||
// based on https://github.com/substack/point-in-polygon, | ||
// ray-casting algorithm based on http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html | ||
var pointInPolygon = function(point, polygon) { | ||
var x = point[0], y = point[1], inside = false; | ||
for (var i = 0, j = polygon.length - 1; i < polygon.length; j = i++) { | ||
var xi = polygon[i][0], yi = polygon[i][1]; | ||
var xj = polygon[j][0], yj = polygon[j][1]; | ||
var intersect = ((yi > y) != (yj > y)) && | ||
(x < (xj - xi) * (y - yi) / (yj - yi) + xi); | ||
if (intersect) inside = !inside; | ||
} | ||
return inside; | ||
}; | ||
// stolen from iD/relation.js | ||
var o, outer; | ||
// todo: all this coordinate mapping makes this unneccesarily slow. | ||
// see the "todo: this is slow! :(" above. | ||
inner = mapCoordinates(inner); | ||
/*for (o = 0; o < outers.length; o++) { | ||
outer = mapCoordinates(outers[o]); | ||
if (polygonContainsPolygon(outer, inner)) | ||
return o; | ||
}*/ | ||
for (o = 0; o < outers.length; o++) { | ||
outer = mapCoordinates(outers[o]); | ||
if (polygonIntersectsPolygon(outer, inner)) | ||
return o; | ||
} | ||
} | ||
mp = _.map(outers, function(o) {return [o];}); | ||
for (var j=0; j<inners.length; j++) { | ||
var o = findOuter(inners[j]); | ||
if (o !== undefined) | ||
mp[o].push(inners[j]); | ||
else | ||
// so, no outer ring for this inner ring is found. | ||
// We're going to ignore holes in empty space. | ||
; | ||
} | ||
// sanitize mp-coordinates (remove empty clusters or rings, {lat,lon,...} to [lon,lat] | ||
var mp_coords = []; | ||
mp_coords = _.compact(_.map(mp, function(cluster) { | ||
var cl = _.compact(_.map(cluster, function(ring) { | ||
if (ring.length < 4) // todo: is this correct: ring.length < 4 ? | ||
return; | ||
return _.compact(_.map(ring, function(node) { | ||
return [+node.lon,+node.lat]; | ||
})); | ||
})); | ||
if (cl.length == 0) | ||
return; | ||
return cl; | ||
})); | ||
if (mp_coords.length == 0) | ||
continue; // ignore multipolygons without coordinates | ||
// mp parsed, now construct the geoJSON | ||
var feature = { | ||
"type" : "Feature", | ||
"id" : "relation/"+rels[i].id, | ||
"properties" : { | ||
"type" : "relation", | ||
"id" : rels[i].id, | ||
"tags" : rels[i].tags || {}, | ||
"relations" : rels[i].relations || [], | ||
"meta": function(o){var res={}; for(k in o) if(o[k] != undefined) res[k]=o[k]; return res;}({"timestamp": rels[i].timestamp, "version": rels[i].version, "changeset": rels[i].changeset, "user": rels[i].user, "uid": rels[i].uid}), | ||
}, | ||
"geometry" : { | ||
"type" : "MultiPolygon", | ||
"coordinates" : mp_coords, | ||
} | ||
} | ||
if (is_tainted) | ||
feature.properties["tainted"] = true; | ||
geojsonpolygons.features.push(feature); | ||
} else { | ||
// simple multipolygon | ||
rels[i].tainted = false; | ||
var outer_coords = new Array(); | ||
var inner_coords = new Array(); | ||
var outer_way = undefined; | ||
for (var j=0;j<rels[i].members.length;j++) { | ||
if ((rels[i].members[j].type == "way") && | ||
_.contains(["outer","inner"], rels[i].members[j].role)) { | ||
var w = wayids[rels[i].members[j].ref]; | ||
if (typeof w == "undefined") { | ||
rels[i].tainted = true; | ||
continue; | ||
} | ||
var coords = new Array(); | ||
for (var k=0;k<w.nodes.length;k++) { | ||
if (typeof w.nodes[k] == "object") | ||
coords.push([+w.nodes[k].lon, +w.nodes[k].lat]); | ||
else | ||
rels[i].tainted = true; | ||
} | ||
if (rels[i].members[j].role == "outer") { | ||
outer_coords.push(coords); | ||
outer_way = w; | ||
outer_way.is_multipolygon_outline = true; | ||
} else if (rels[i].members[j].role == "inner") { | ||
inner_coords.push(coords); | ||
} | ||
} | ||
} | ||
if (typeof outer_way == "undefined") | ||
continue; // abort if outer way object is not present | ||
if (outer_coords[0].length == 0) | ||
continue; // abort if coordinates of outer way is not present | ||
way_type = "Polygon"; | ||
var feature = { | ||
"type" : "Feature", | ||
"id" : "way/"+outer_way.id, | ||
"properties" : { | ||
"type" : "way", | ||
"id" : outer_way.id, | ||
"tags" : outer_way.tags || {}, | ||
"relations" : outer_way.relations || [], | ||
"meta": function(o){var res={}; for(k in o) if(o[k] != undefined) res[k]=o[k]; return res;}({"timestamp": outer_way.timestamp, "version": outer_way.version, "changeset": outer_way.changeset, "user": outer_way.user, "uid": outer_way.uid}), | ||
}, | ||
"geometry" : { | ||
"type" : way_type, | ||
"coordinates" : ([].concat(outer_coords,inner_coords)), | ||
} | ||
} | ||
if (rels[i].tainted) | ||
feature.properties["tainted"] = true; | ||
geojsonpolygons.features.push(feature); | ||
} | ||
} | ||
} | ||
// process lines and polygons | ||
for (var i=0;i<ways.length;i++) { | ||
if (!_.isArray(ways[i].nodes)) | ||
continue; // ignore ways without nodes (e.g. returned by an ids_only query) | ||
if (ways[i].is_multipolygon_outline) | ||
continue; // ignore ways which are already rendered as (part of) a multipolygon | ||
ways[i].tainted = false; | ||
ways[i].hidden = false; | ||
coords = new Array(); | ||
for (j=0;j<ways[i].nodes.length;j++) { | ||
if (typeof ways[i].nodes[j] == "object") | ||
coords.push([+ways[i].nodes[j].lon, +ways[i].nodes[j].lat]); | ||
else | ||
ways[i].tainted = true; | ||
} | ||
if (coords.length <= 1) // invalid way geometry | ||
continue; | ||
var way_type = "LineString"; // default | ||
if (typeof ways[i].nodes[0] != "undefined" && // way has its nodes loaded | ||
ways[i].nodes[0] === ways[i].nodes[ways[i].nodes.length-1] && // ... and forms a closed ring | ||
typeof ways[i].tags != "undefined" && // ... and has tags | ||
_isPolygonFeature(ways[i].tags) // ... and tags say it is a polygon | ||
) { | ||
way_type = "Polygon"; | ||
coords = [coords]; | ||
} | ||
var feature = { | ||
"type" : "Feature", | ||
"id" : "way/"+ways[i].id, | ||
"properties" : { | ||
"type" : "way", | ||
"id" : ways[i].id, | ||
"tags" : ways[i].tags || {}, | ||
"relations" : ways[i].relations || [], | ||
"meta": function(o){var res={}; for(k in o) if(o[k] != undefined) res[k]=o[k]; return res;}({"timestamp": ways[i].timestamp, "version": ways[i].version, "changeset": ways[i].changeset, "user": ways[i].user, "uid": ways[i].uid}), | ||
}, | ||
"geometry" : { | ||
"type" : way_type, | ||
"coordinates" : coords, | ||
} | ||
} | ||
if (ways[i].tainted) | ||
feature.properties["tainted"] = true; | ||
if (way_type == "LineString") | ||
geojsonlines.features.push(feature); | ||
else | ||
geojsonpolygons.features.push(feature); | ||
} | ||
geojson = { | ||
"type": "FeatureCollection", | ||
"features": [] | ||
}; | ||
geojson.features = geojson.features.concat(geojsonpolygons.features); | ||
geojson.features = geojson.features.concat(geojsonlines.features); | ||
geojson.features = geojson.features.concat(geojsonnodes.features); | ||
// optionally, flatten properties | ||
if (options.flatProperties) { | ||
_.each(geojson.features, function(f) { | ||
f.properties = _.merge( | ||
f.properties.meta, | ||
f.properties.tags, | ||
{id: f.properties.type+"/"+f.properties.id} | ||
); | ||
}); | ||
} | ||
return geojson; | ||
} | ||
function _isPolygonFeature( tags ) { | ||
var polygonFeatures = options.polygonFeatures; | ||
if (typeof polygonFeatures === "function") | ||
return polygonFeatures(tags); | ||
// explicitely tagged non-areas | ||
if ( tags['area'] === 'no' ) | ||
return false; | ||
// assuming that a typical OSM way has in average less tags than | ||
// the polygonFeatures list, this way around should be faster | ||
for ( var key in tags ) { | ||
var val = tags[key]; | ||
var pfk = polygonFeatures[key]; | ||
// continue with next if tag is unknown or not "categorizing" | ||
if ( typeof pfk === 'undefined' ) | ||
continue; | ||
// continue with next if tag is explicitely un-set ("building=no") | ||
if ( val === 'no' ) | ||
continue; | ||
// check polygon features for: general acceptance, included or excluded values | ||
if ( pfk === true ) | ||
return true; | ||
if ( pfk.included_values && pfk.included_values[val] === true ) | ||
return true; | ||
if ( pfk.excluded_values && pfk.excluded_values[val] !== true ) | ||
return true; | ||
} | ||
// if no tags matched, this ain't no area. | ||
return false; | ||
} | ||
}; | ||
if (typeof module !== 'undefined') module.exports = osmtogeojson; | ||
!function(e){"object"==typeof exports?module.exports=e():"function"==typeof define&&define.amd?define(e):"undefined"!=typeof window?window.osmtogeojson=e():"undefined"!=typeof global?global.osmtogeojson=e():"undefined"!=typeof self&&(self.osmtogeojson=e())}(function(){return function e(n,t,r){function o(i,u){if(!t[i]){if(!n[i]){var s="function"==typeof require&&require;if(!u&&s)return s(i,!0);if(a)return a(i,!0);throw new Error("Cannot find module '"+i+"'")}var l=t[i]={exports:{}};n[i][0].call(l.exports,function(e){var t=n[i][1][e];return o(t?t:e)},l,l.exports,e,n,t,r)}return t[i].exports}for(var a="function"==typeof require&&require,i=0;i<r.length;i++)o(r[i]);return o}({1:[function(e,n){var t=e("./lodash.custom.js"),r=e("geojson-rewind"),o=e("./polygon_features.json"),a={};a=function(e,n){function a(e){for(var n=new Array,r=new Array,o=new Array,a=0;a<e.elements.length;a++)switch(e.elements[a].type){case"node":var i=e.elements[a];n.push(i);break;case"way":var s=t.clone(e.elements[a]);s.nodes=t.clone(s.nodes),r.push(s);break;case"relation":var l=t.clone(e.elements[a]);l.members=t.clone(l.members),o.push(l)}return u(n,r,o)}function i(e){function n(e,n,t){e.hasAttribute(t)&&(n[t]=e.getAttribute(t))}var r=new Array,o=new Array,a=new Array;return t.each(e.getElementsByTagName("node"),function(e,o){var a={};t.each(e.getElementsByTagName("tag"),function(e){a[e.getAttribute("k")]=e.getAttribute("v")}),r[o]={type:"node"},n(e,r[o],"id"),n(e,r[o],"lat"),n(e,r[o],"lon"),n(e,r[o],"version"),n(e,r[o],"timestamp"),n(e,r[o],"changeset"),n(e,r[o],"uid"),n(e,r[o],"user"),t.isEmpty(a)||(r[o].tags=a)}),t.each(e.getElementsByTagName("way"),function(e,r){var a={},i=[];t.each(e.getElementsByTagName("tag"),function(e){a[e.getAttribute("k")]=e.getAttribute("v")}),t.each(e.getElementsByTagName("nd"),function(e,n){i[n]=e.getAttribute("ref")}),o[r]={type:"way"},n(e,o[r],"id"),n(e,o[r],"version"),n(e,o[r],"timestamp"),n(e,o[r],"changeset"),n(e,o[r],"uid"),n(e,o[r],"user"),i.length>0&&(o[r].nodes=i),t.isEmpty(a)||(o[r].tags=a)}),t.each(e.getElementsByTagName("relation"),function(e,r){var o={},i=[];t.each(e.getElementsByTagName("tag"),function(e){o[e.getAttribute("k")]=e.getAttribute("v")}),t.each(e.getElementsByTagName("member"),function(e,t){i[t]={},n(e,i[t],"ref"),n(e,i[t],"role"),n(e,i[t],"type")}),a[r]={type:"relation"},n(e,a[r],"id"),n(e,a[r],"version"),n(e,a[r],"timestamp"),n(e,a[r],"changeset"),n(e,a[r],"uid"),n(e,a[r],"user"),i.length>0&&(a[r].members=i),t.isEmpty(o)||(a[r].tags=o)}),u(r,o,a)}function u(e,o,a){function i(e,t){if("object"!=typeof t&&(t={}),"function"==typeof n.uninterestingTags)return!n.uninterestingTags(e,t);for(var r in e)if(n.uninterestingTags[r]!==!0&&t[r]!==!0&&t[r]!==e[r])return!0;return!1}function u(e){var n={timestamp:e.timestamp,version:e.version,changeset:e.changeset,user:e.user,uid:e.uid};for(k in n)void 0===n[k]&&delete n[k];return n}function l(e,n){function r(e){for(var n,t,r,o,a,i,u=function(e){return e[0]},s=function(e){return e[e.length-1]},l=[];e.length;)for(n=e.pop().nodes.slice(),l.push(n);e.length&&u(n)!==s(n);){for(t=u(n),r=s(n),o=0;o<e.length;o++){if(i=e[o].nodes,r===u(i)){a=n.push,i=i.slice(1);break}if(r===s(i)){a=n.push,i=i.slice(0,-1).reverse();break}if(t==s(i)){a=n.unshift,i=i.slice(0,-1);break}if(t==u(i)){a=n.unshift,i=i.slice(1).reverse();break}i=a=null}if(!i)break;e.splice(o,1),a.apply(n,i)}return l}function o(e){var n,t,r=function(e,n){for(var t=0;t<n.length;t++)if(a(n[t],e))return!0;return!1},o=function(e){return e.map(function(e){return[+e.lat,+e.lon]})},a=function(e,n){for(var t=e[0],r=e[1],o=!1,a=0,i=n.length-1;a<n.length;i=a++){var u=n[a][0],s=n[a][1],l=n[i][0],f=n[i][1],c=s>r!=f>r&&(l-u)*(r-s)/(f-s)+u>t;c&&(o=!o)}return o};for(e=o(e),n=0;n<s.length;n++)if(t=o(s[n]),r(t,e))return n}var a,i=!1;a=n.members.filter(function(e){return"way"===e.type}),a=a.map(function(e){var n=d[e.ref];return void 0===n?(i=!0,void 0):{id:e.ref,role:e.role||"outer",way:n,nodes:n.nodes.filter(function(e){return void 0!==e?!0:(i=!0,!1)})}}),a=t.compact(a);var s,l;s=r(a.filter(function(e){return"outer"===e.role})),l=r(a.filter(function(e){return"inner"===e.role}));var f;f=s.map(function(e){return[e]});for(var c=0;c<l.length;c++){var p=o(l[c]);void 0!==p&&f[p].push(l[c])}var g=[];if(g=t.compact(f.map(function(e){var n=t.compact(e.map(function(e){return e.length<4?void 0:t.compact(e.map(function(e){return[+e.lon,+e.lat]}))}));if(0!=n.length)return n})),0==g.length)return!1;var y="MultiPolygon";1===g.length&&(y="Polygon",g=g[0]);var m={type:"Feature",id:e.type+"/"+e.id,properties:{type:e.type,id:e.id,tags:e.tags||{},relations:b[e.type][e.id]||[],meta:u(e)},geometry:{type:y,coordinates:g}};return i&&(m.properties.tainted=!0),m}for(var f=new Object,c=0;c<e.length;c++)void 0!==e[c].lat&&(f[e[c].id]=e[c]);for(var p=new Object,c=0;c<e.length;c++)"undefined"!=typeof e[c].tags&&i(e[c].tags)&&(p[e[c].id]=!0);for(var c=0;c<a.length;c++)if(t.isArray(a[c].members))for(var g=0;g<a[c].members.length;g++)"node"==a[c].members[g].type&&(p[a[c].members[g].ref]=!0);for(var d=new Object,y=new Object,c=0;c<o.length;c++)if(t.isArray(o[c].nodes)){d[o[c].id]=o[c];for(var g=0;g<o[c].nodes.length;g++)y[o[c].nodes[g]]=!0,o[c].nodes[g]=f[o[c].nodes[g]]}for(var m=new Array,c=0;c<e.length;c++)(!y[e[c].id]||p[e[c].id])&&m.push(e[c]);for(var h=new Array,c=0;c<a.length;c++)t.isArray(a[c].members)&&(h[a[c].id]=a[c]);for(var b={node:{},way:{},relation:{}},c=0;c<a.length;c++)if(t.isArray(a[c].members))for(var g=0;g<a[c].members.length;g++){var v;switch(a[c].members[g].type){case"node":v=f[a[c].members[g].ref];break;case"way":v=d[a[c].members[g].ref];break;case"relation":v=h[a[c].members[g].ref]}if(v){var w=a[c].members[g].type,x=a[c].members[g].ref;"undefined"==typeof b[w][x]&&(b[w][x]=[]),b[w][x].push({role:a[c].members[g].role,rel:a[c].id,reltags:a[c].tags})}}var j,A={type:"FeatureCollection",features:new Array};for(c=0;c<m.length;c++)"undefined"!=typeof m[c].lon&&"undefined"!=typeof m[c].lat&&A.features.push({type:"Feature",id:"node/"+m[c].id,properties:{type:"node",id:m[c].id,tags:m[c].tags||{},relations:b.node[m[c].id]||[],meta:u(m[c])},geometry:{type:"Point",coordinates:[+m[c].lon,+m[c].lat]}});for(var P={type:"FeatureCollection",features:new Array},_={type:"FeatureCollection",features:new Array},c=0;c<a.length;c++)if("undefined"!=typeof a[c].tags&&("multipolygon"==a[c].tags.type||"boundary"==a[c].tags.type)){if(!t.isArray(a[c].members))continue;for(var E=0,g=0;g<a[c].members.length;g++)"outer"==a[c].members[g].role&&E++;if(a[c].members.forEach(function(e){d[e.ref]&&("outer"!==e.role||i(d[e.ref].tags,a[c].tags)||(d[e.ref].is_multipolygon_outline=!0),"inner"!==e.role||i(d[e.ref].tags)||(d[e.ref].is_multipolygon_outline=!0))}),0==E)continue;var O=!1;1!=E||i(a[c].tags,{type:!0})||(O=!0);var S=null;if(O){var C=a[c].members.filter(function(e){return"outer"===e.role})[0];if(C=d[C.ref],void 0===C)continue;C.is_multipolygon_outline=!0,S=l(C,a[c])}else S=l(a[c],a[c]);if(S===!1)continue;_.features.push(S)}for(var c=0;c<o.length;c++)if(t.isArray(o[c].nodes)&&!o[c].is_multipolygon_outline){for(o[c].tainted=!1,o[c].hidden=!1,coords=new Array,g=0;g<o[c].nodes.length;g++)"object"==typeof o[c].nodes[g]?coords.push([+o[c].nodes[g].lon,+o[c].nodes[g].lat]):o[c].tainted=!0;if(!(coords.length<=1)){var T="LineString";"undefined"!=typeof o[c].nodes[0]&&o[c].nodes[0]===o[c].nodes[o[c].nodes.length-1]&&"undefined"!=typeof o[c].tags&&s(o[c].tags)&&(T="Polygon",coords=[coords]);var S={type:"Feature",id:"way/"+o[c].id,properties:{type:"way",id:o[c].id,tags:o[c].tags||{},relations:b.way[o[c].id]||[],meta:u(o[c])},geometry:{type:T,coordinates:coords}};o[c].tainted&&(S.properties.tainted=!0),"LineString"==T?P.features.push(S):_.features.push(S)}}return j={type:"FeatureCollection",features:[]},j.features=j.features.concat(_.features),j.features=j.features.concat(P.features),j.features=j.features.concat(A.features),n.flatProperties&&j.features.forEach(function(e){e.properties=t.merge(e.properties.meta,e.properties.tags,{id:e.properties.type+"/"+e.properties.id})}),j=r(j,!0)}function s(e){var t=n.polygonFeatures;if("function"==typeof t)return t(e);if("no"===e.area)return!1;for(var r in e){var o=e[r],a=t[r];if("undefined"!=typeof a&&"no"!==o){if(a===!0)return!0;if(a.included_values&&a.included_values[o]===!0)return!0;if(a.excluded_values&&a.excluded_values[o]!==!0)return!0}}return!1}n=t.merge({flatProperties:!1,uninterestingTags:{source:!0,source_ref:!0,"source:ref":!0,history:!0,attribution:!0,created_by:!0,"tiger:county":!0,"tiger:tlid":!0,"tiger:upload_uuid":!0},polygonFeatures:o},n);var l;return l="undefined"!=typeof XMLDocument&&e instanceof XMLDocument||"undefined"==typeof XMLDocument&&e.childNodes?i(e):a(e)},a.toGeojson=a,n.exports=a},{"./lodash.custom.js":2,"./polygon_features.json":6,"geojson-rewind":3}],2:[function(e,n,t){var r="undefined"!=typeof self?self:"undefined"!=typeof window?window:{};(function(){function e(){return T.pop()||[]}function o(e){return"function"!=typeof e.toString&&"string"==typeof(e+"")}function a(e){e.length=0,T.length<N&&T.push(e)}function i(e,n,t){n||(n=0),"undefined"==typeof t&&(t=e?e.length:0);for(var r=-1,o=t-n||0,a=Array(0>o?0:o);++r<o;)a[r]=e[n+r];return a}function u(){}function s(e){function n(){if(r){var e=i(r);gn.apply(e,arguments)}if(this instanceof n){var a=f(t.prototype),u=t.apply(a,e||arguments);return j(u)?u:a}return t.apply(o,e||arguments)}var t=e[0],r=e[2],o=e[4];return Pn(n,e),n}function l(n,t,r,u,s){if(r){var f=r(n);if("undefined"!=typeof f)return f}var c=j(n);if(!c)return n;var p=sn.call(n);if(!z[p]||!jn.nodeClass&&o(n))return n;var g=wn[p];switch(p){case H:case q:return new g(+n);case X:case W:return new g(n);case V:return f=g(n.source,F.exec(n)),f.lastIndex=n.lastIndex,f}var d=kn(n);if(t){var y=!u;u||(u=e()),s||(s=e());for(var m=u.length;m--;)if(u[m]==n)return s[m];f=d?g(n.length):{}}else f=d?i(n):Ln({},n);return d&&(pn.call(n,"index")&&(f.index=n.index),pn.call(n,"input")&&(f.input=n.input)),t?(u.push(n),s.push(f),(d?Tn:Fn)(n,function(e,n){f[n]=l(e,t,r,u,s)}),y&&(a(u),a(s)),f):f}function f(e){return j(e)?hn(e):{}}function c(e,n,t){if("function"!=typeof e)return S;if("undefined"==typeof n||!("prototype"in e))return e;var r=e.__bindData__;if("undefined"==typeof r&&(jn.funcNames&&(r=!e.name),r=r||!jn.funcDecomp,!r)){var o=fn.call(e);jn.funcNames||(r=!I.test(o)),r||(r=D.test(o),Pn(e,r))}if(r===!1||r!==!0&&1&r[1])return e;switch(t){case 1:return function(t){return e.call(n,t)};case 2:return function(t,r){return e.call(n,t,r)};case 3:return function(t,r,o){return e.call(n,t,r,o)};case 4:return function(t,r,o,a){return e.call(n,t,r,o,a)}}return O(e,n)}function p(e){function n(){var e=l?u:this;if(o){var m=i(o);gn.apply(m,arguments)}if((a||g)&&(m||(m=i(arguments)),a&&gn.apply(m,a),g&&m.length<s))return r|=16,p([t,d?r:-4&r,m,null,u,s]);if(m||(m=arguments),c&&(t=e[y]),this instanceof n){e=f(t.prototype);var h=t.apply(e,m);return j(h)?h:e}return t.apply(e,m)}var t=e[0],r=e[1],o=e[2],a=e[3],u=e[4],s=e[5],l=1&r,c=2&r,g=4&r,d=8&r,y=t;return Pn(n,e),n}function g(e,n,t,r,o){(kn(n)?_:Fn)(n,function(n,a){var i,u,s=n,l=e[a];if(n&&((u=kn(n))||In(n))){for(var f=r.length;f--;)if(i=r[f]==n){l=o[f];break}if(!i){var c;t&&(s=t(l,n),(c="undefined"!=typeof s)&&(l=s)),c||(l=u?kn(l)?l:[]:In(l)?l:{}),r.push(n),o.push(l),c||g(l,n,t,r,o)}}else t&&(s=t(l,n),"undefined"==typeof s&&(s=n)),"undefined"!=typeof s&&(l=s);e[a]=l})}function d(e,n,t,r,o,a){var u=1&n,l=2&n,f=4&n,c=16&n,g=32&n;if(!l&&!x(e))throw new TypeError;c&&!t.length&&(n&=-17,c=t=!1),g&&!r.length&&(n&=-33,g=r=!1);var y=e&&e.__bindData__;if(y&&y!==!0)return y=i(y),y[2]&&(y[2]=i(y[2])),y[3]&&(y[3]=i(y[3])),!u||1&y[1]||(y[4]=o),!u&&1&y[1]&&(n|=8),!f||4&y[1]||(y[5]=a),c&&gn.apply(y[2]||(y[2]=[]),t),g&&yn.apply(y[3]||(y[3]=[]),r),y[1]|=n,d.apply(null,y);var m=1==n||17===n?s:p;return m([e,n,t,r,o,a])}function y(){K.shadowedProps=M,K.array=K.bottom=K.loop=K.top="",K.init="iterable",K.useHas=!0;for(var e,n=0;e=arguments[n];n++)for(var t in e)K[t]=e[t];var r=K.args;K.firstArg=/^[^,]+/.exec(r)[0];var o=Function("baseCreateCallback, errorClass, errorProto, hasOwnProperty, indicatorObject, isArguments, isArray, isString, keys, objectProto, objectTypes, nonEnumProps, stringClass, stringProto, toString","return function("+r+") {\n"+An(K)+"\n}");return o(c,U,on,pn,L,b,kn,A,K.keys,an,Q,xn,W,un,sn)}function m(e){return"function"==typeof e&&ln.test(e)}function h(e){var n,t;return!e||sn.call(e)!=G||(n=e.constructor,x(n)&&!(n instanceof n))||!jn.argsClass&&b(e)||!jn.nodeClass&&o(e)?!1:jn.ownLast?(Nn(e,function(e,n,r){return t=pn.call(r,n),!1}),t!==!1):(Nn(e,function(e,n){t=n}),"undefined"==typeof t||pn.call(e,t))}function b(e){return e&&"object"==typeof e&&"number"==typeof e.length&&sn.call(e)==B||!1}function v(e,n,t,r){return"boolean"!=typeof n&&null!=n&&(r=t,t=n,n=!1),l(e,n,"function"==typeof t&&c(t,r,1))}function w(e){var n=!0;if(!e)return n;var t=sn.call(e),r=e.length;return t==R||t==W||(jn.argsClass?t==B:b(e))||t==G&&"number"==typeof r&&x(e.splice)?!r:(Fn(e,function(){return n=!1}),n)}function x(e){return"function"==typeof e}function j(e){return!(!e||!Q[typeof e])}function A(e){return"string"==typeof e||e&&"object"==typeof e&&sn.call(e)==W||!1}function P(n){var t=arguments,r=2;if(!j(n))return n;if("number"!=typeof t[2]&&(r=t.length),r>3&&"function"==typeof t[r-2])var o=c(t[--r-1],t[r--],2);else r>2&&"function"==typeof t[r-1]&&(o=t[--r]);for(var u=i(arguments,1,r),s=-1,l=e(),f=e();++s<r;)g(n,u[s],o,l,f);return a(l),a(f),n}function _(e,n,t){if(n&&"undefined"==typeof t&&kn(e))for(var r=-1,o=e.length;++r<o&&n(e[r],r,e)!==!1;);else Tn(e,n,t);return e}function E(e){for(var n=-1,t=e?e.length:0,r=[];++n<t;){var o=e[n];o&&r.push(o)}return r}function O(e,n){return arguments.length>2?d(e,17,i(arguments,2),null,n):d(e,1,null,null,n)}function S(e){return e}function C(){}var T=[],L={},N=40,F=/\w*$/,I=/^\s*function[ \n\r\t]+\w/,D=/\bthis\b/,M=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"],B="[object Arguments]",R="[object Array]",H="[object Boolean]",q="[object Date]",U="[object Error]",$="[object Function]",X="[object Number]",G="[object Object]",V="[object RegExp]",W="[object String]",z={};z[$]=!1,z[B]=z[R]=z[H]=z[q]=z[X]=z[G]=z[V]=z[W]=!0;var J={configurable:!1,enumerable:!1,value:null,writable:!1},K={args:"",array:null,bottom:"",firstArg:"",init:"",keys:null,loop:"",shadowedProps:null,support:null,top:"",useHas:!1},Q={"boolean":!1,"function":!0,object:!0,number:!1,string:!1,undefined:!1},Y=Q[typeof window]&&window||this,Z=Q[typeof t]&&t&&!t.nodeType&&t,en=Q[typeof n]&&n&&!n.nodeType&&n,nn=en&&en.exports===Z&&Z,tn=Q[typeof r]&&r;!tn||tn.global!==tn&&tn.window!==tn||(Y=tn);var rn=[],on=Error.prototype,an=Object.prototype,un=String.prototype,sn=an.toString,ln=RegExp("^"+String(sn).replace(/[.*+?^${}()|[\]\\]/g,"\\$&").replace(/toString| for [^\]]+/g,".*?")+"$"),fn=Function.prototype.toString,cn=m(cn=Object.getPrototypeOf)&&cn,pn=an.hasOwnProperty,gn=rn.push,dn=an.propertyIsEnumerable,yn=rn.unshift,mn=function(){try{var e={},n=m(n=Object.defineProperty)&&n,t=n(e,e,e)&&n}catch(r){}return t}(),hn=m(hn=Object.create)&&hn,bn=m(bn=Array.isArray)&&bn,vn=m(vn=Object.keys)&&vn,wn={};wn[R]=Array,wn[H]=Boolean,wn[q]=Date,wn[$]=Function,wn[G]=Object,wn[X]=Number,wn[V]=RegExp,wn[W]=String;var xn={};xn[R]=xn[q]=xn[X]={constructor:!0,toLocaleString:!0,toString:!0,valueOf:!0},xn[H]=xn[W]={constructor:!0,toString:!0,valueOf:!0},xn[U]=xn[$]=xn[V]={constructor:!0,toString:!0},xn[G]={constructor:!0},function(){for(var e=M.length;e--;){var n=M[e];for(var t in xn)pn.call(xn,t)&&!pn.call(xn[t],n)&&(xn[t][n]=!1)}}();var jn=u.support={};!function(){var e=function(){this.x=1},n={0:1,length:1},t=[];e.prototype={valueOf:1,y:1};for(var r in new e)t.push(r);for(r in arguments);jn.argsClass=sn.call(arguments)==B,jn.argsObject=arguments.constructor==Object&&!(arguments instanceof Array),jn.enumErrorProps=dn.call(on,"message")||dn.call(on,"name"),jn.enumPrototypes=dn.call(e,"prototype"),jn.funcDecomp=!m(Y.WinRTError)&&D.test(function(){return this}),jn.funcNames="string"==typeof Function.name,jn.nonEnumArgs=0!=r,jn.nonEnumShadows=!/valueOf/.test(t),jn.ownLast="x"!=t[0],jn.spliceObjects=(rn.splice.call(n,0,1),!n[0]),jn.unindexedChars="xx"!="x"[0]+Object("x")[0];try{jn.nodeClass=!(sn.call(document)==G&&!({toString:0}+""))}catch(o){jn.nodeClass=!0}}(1);var An=function(e){var n="var index, iterable = "+e.firstArg+", result = "+e.init+";\nif (!iterable) return result;\n"+e.top+";";e.array?(n+="\nvar length = iterable.length; index = -1;\nif ("+e.array+") { ",jn.unindexedChars&&(n+="\n if (isString(iterable)) {\n iterable = iterable.split('')\n } "),n+="\n while (++index < length) {\n "+e.loop+";\n }\n}\nelse { "):jn.nonEnumArgs&&(n+="\n var length = iterable.length; index = -1;\n if (length && isArguments(iterable)) {\n while (++index < length) {\n index += '';\n "+e.loop+";\n }\n } else { "),jn.enumPrototypes&&(n+="\n var skipProto = typeof iterable == 'function';\n "),jn.enumErrorProps&&(n+="\n var skipErrorProps = iterable === errorProto || iterable instanceof Error;\n ");var t=[];if(jn.enumPrototypes&&t.push('!(skipProto && index == "prototype")'),jn.enumErrorProps&&t.push('!(skipErrorProps && (index == "message" || index == "name"))'),e.useHas&&e.keys)n+="\n var ownIndex = -1,\n ownProps = objectTypes[typeof iterable] && keys(iterable),\n length = ownProps ? ownProps.length : 0;\n\n while (++ownIndex < length) {\n index = ownProps[ownIndex];\n",t.length&&(n+=" if ("+t.join(" && ")+") {\n "),n+=e.loop+"; ",t.length&&(n+="\n }"),n+="\n } ";else if(n+="\n for (index in iterable) {\n",e.useHas&&t.push("hasOwnProperty.call(iterable, index)"),t.length&&(n+=" if ("+t.join(" && ")+") {\n "),n+=e.loop+"; ",t.length&&(n+="\n }"),n+="\n } ",jn.nonEnumShadows){for(n+="\n\n if (iterable !== objectProto) {\n var ctor = iterable.constructor,\n isProto = iterable === (ctor && ctor.prototype),\n className = iterable === stringProto ? stringClass : iterable === errorProto ? errorClass : toString.call(iterable),\n nonEnum = nonEnumProps[className];\n ",k=0;7>k;k++)n+="\n index = '"+e.shadowedProps[k]+"';\n if ((!(isProto && nonEnum[index]) && hasOwnProperty.call(iterable, index))",e.useHas||(n+=" || (!nonEnum[index] && iterable[index] !== objectProto[index])"),n+=") {\n "+e.loop+";\n } ";n+="\n } "}return(e.array||jn.nonEnumArgs)&&(n+="\n}"),n+=e.bottom+";\nreturn result"};hn||(f=function(){function e(){}return function(n){if(j(n)){e.prototype=n;var t=new e;e.prototype=null}return t||Y.Object()}}());var Pn=mn?function(e,n){J.value=n,mn(e,"__bindData__",J)}:C;jn.argsClass||(b=function(e){return e&&"object"==typeof e&&"number"==typeof e.length&&pn.call(e,"callee")&&!dn.call(e,"callee")||!1});var kn=bn||function(e){return e&&"object"==typeof e&&"number"==typeof e.length&&sn.call(e)==R||!1},_n=y({args:"object",init:"[]",top:"if (!(objectTypes[typeof object])) return result",loop:"result.push(index)"}),En=vn?function(e){return j(e)?jn.enumPrototypes&&"function"==typeof e||jn.nonEnumArgs&&e.length&&b(e)?_n(e):vn(e):[]}:_n,On={args:"collection, callback, thisArg",top:"callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3)",array:"typeof length == 'number'",keys:En,loop:"if (callback(iterable[index], index, collection) === false) return result"},Sn={args:"object, source, guard",top:"var args = arguments,\n argsIndex = 0,\n argsLength = typeof guard == 'number' ? 2 : args.length;\nwhile (++argsIndex < argsLength) {\n iterable = args[argsIndex];\n if (iterable && objectTypes[typeof iterable]) {",keys:En,loop:"if (typeof result[index] == 'undefined') result[index] = iterable[index]",bottom:" }\n}"},Cn={top:"if (!objectTypes[typeof iterable]) return result;\n"+On.top,array:!1},Tn=y(On),Ln=y(Sn,{top:Sn.top.replace(";",";\nif (argsLength > 3 && typeof args[argsLength - 2] == 'function') {\n var callback = baseCreateCallback(args[--argsLength - 1], args[argsLength--], 2);\n} else if (argsLength > 2 && typeof args[argsLength - 1] == 'function') {\n callback = args[--argsLength];\n}"),loop:"result[index] = callback ? callback(result[index], iterable[index]) : iterable[index]"}),Nn=y(On,Cn,{useHas:!1}),Fn=y(On,Cn);x(/x/)&&(x=function(e){return"function"==typeof e&&sn.call(e)==$});var In=cn?function(e){if(!e||sn.call(e)!=G||!jn.argsClass&&b(e))return!1;var n=e.valueOf,t=m(n)&&(t=cn(n))&&cn(t);return t?e==t||cn(e)==t:h(e)}:h;u.assign=Ln,u.bind=O,u.compact=E,u.forEach=_,u.forIn=Nn,u.forOwn=Fn,u.keys=En,u.merge=P,u.each=_,u.extend=Ln,u.clone=v,u.identity=S,u.isArguments=b,u.isArray=kn,u.isEmpty=w,u.isFunction=x,u.isObject=j,u.isPlainObject=In,u.isString=A,u.noop=C,u.VERSION="2.4.1",Z&&en&&nn&&((en.exports=u)._=u)}).call(this)},{}],3:[function(e,n){function t(e,n){switch(e&&e.type||null){case"FeatureCollection":return e.features=e.features.map(r(t,n)),e;case"Feature":return e.geometry=t(e.geometry,n),e;case"Polygon":case"MultiPolygon":return o(e,n);default:return e}}function r(e,n){return function(t){return e(t,n)}}function o(e,n){return"Polygon"===e.type?e.coordinates=a(e.coordinates,n):"MultiPolygon"===e.type&&(e.coordinates=e.coordinates.map(r(a,n))),e}function a(e,n){n=!!n,e[0]=i(e[0],!n);for(var t=1;t<e.length;t++)e[t]=i(e[t],n);return e}function i(e,n){return u(e)===n?e:e.reverse()}function u(e){return s.ring(e)>=0}var s=e("geojson-area");n.exports=t},{"geojson-area":4}],4:[function(e,n){function t(e){if("Polygon"===e.type)return r(e.coordinates);if("MultiPolygon"===e.type){for(var n=0,t=0;t<e.coordinates.length;t++)n+=r(e.coordinates[t]);return n}return null}function r(e){var n=0;if(e&&e.length>0){n+=Math.abs(o(e[0]));for(var t=1;t<e.length;t++)n-=Math.abs(o(e[t]))}return n}function o(e){var n=0;if(e.length>2){for(var t,r,o=0;o<e.length-1;o++)t=e[o],r=e[o+1],n+=a(r[0]-t[0])*(2+Math.sin(a(t[1]))+Math.sin(a(r[1])));n=n*i.RADIUS*i.RADIUS/2}return n}function a(e){return e*Math.PI/180}var i=e("wgs84");n.exports.geometry=t,n.exports.ring=o},{wgs84:5}],5:[function(e,n){n.exports.RADIUS=6378137,n.exports.FLATTENING=1/298.257223563,n.exports.POLAR_RADIUS=6356752.3142},{}],6:[function(e,n){n.exports={building:!0,highway:{included_values:{services:!0,rest_area:!0,escape:!0}},natural:{excluded_values:{coastline:!0,ridge:!0,arete:!0,tree_row:!0}},landuse:!0,waterway:{included_values:{riverbank:!0,dock:!0,boatyard:!0,dam:!0}},amenity:!0,leisure:!0,barrier:{included_values:{city_wall:!0,ditch:!0,hedge:!0,retaining_wall:!0,wall:!0,spikes:!0}},railway:{included_values:{station:!0,turntable:!0,roundhouse:!0,platform:!0}},area:!0,boundary:!0,man_made:{excluded_values:{cutline:!0,embankment:!0,pipeline:!0}},power:{included_values:{generator:!0,station:!0,sub_station:!0,transformer:!0}},place:!0,shop:!0,aeroway:{excluded_values:{taxiway:!0}},tourism:!0,historic:!0,public_transport:!0,office:!0,"building:part":!0,military:!0,ruins:!0,"area:highway":!0,craft:!0}},{}]},{},[1])(1)}); |
{ | ||
"name": "osmtogeojson", | ||
"version": "1.4.0", | ||
"version": "2.0.0", | ||
"description": "convert OSM to geojson", | ||
"main": "osmtogeojson.js", | ||
"main": "index.js", | ||
"scripts": { | ||
@@ -26,3 +26,3 @@ "test": "mocha -R spec" | ||
"dependencies": { | ||
"lodash": "~2.2.0", | ||
"geojson-rewind": "0.1.0", | ||
"xmldom": "~0.1.16", | ||
@@ -29,0 +29,0 @@ "optimist": "~0.3.5", |
@@ -28,11 +28,10 @@ osmtogeojson | ||
var osm = require('osmtogeojson'); | ||
osm.toGeojson(xml_data); | ||
var osmtogeojson = require('osmtogeojson'); | ||
osmtogeojson(osm_data); | ||
* as a browser library: | ||
<script src='lodash.js'></script> | ||
<script src='osmtogeojson.js'></script> | ||
osmtogeojson.toGeojson(xml_data); | ||
osmtogeojson(osm_data); | ||
@@ -42,3 +41,3 @@ API | ||
### `.toGeojson( data, options )` | ||
### `osmtogeojson( data, options )` | ||
@@ -45,0 +44,0 @@ Converts OSM data into GeoJSON. |
@@ -291,2 +291,3 @@ if (typeof require !== "undefined") { | ||
var json, geojson; | ||
// valid simple multipolygon | ||
json = { | ||
@@ -405,5 +406,35 @@ elements: [ | ||
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.toGeojson(json); | ||
expect(result).to.eql(geojson); | ||
}); | ||
it("multipolygon", function () { | ||
var json, geojson; | ||
// valid multipolygon | ||
json = { | ||
@@ -562,3 +593,3 @@ elements: [ | ||
[-1.1, 0.1] | ||
]], | ||
].reverse()], | ||
[[ | ||
@@ -606,3 +637,3 @@ [-1.0,-1.0], | ||
[0.0,-0.5] | ||
]] | ||
].reverse()] | ||
} | ||
@@ -633,3 +664,3 @@ }, | ||
[-1.1, 0.1] | ||
]] | ||
].reverse()] | ||
} | ||
@@ -667,2 +698,7 @@ }, | ||
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.toGeojson(json); | ||
expect(result).to.eql(geojson); | ||
}); | ||
@@ -898,4 +934,4 @@ // tags & pois | ||
geometry: { | ||
type: "MultiPolygon", | ||
coordinates: [[[ | ||
type: "Polygon", | ||
coordinates: [[ | ||
[2.0,1.0], | ||
@@ -905,3 +941,3 @@ [1.0,1.0], | ||
[2.0,1.0] | ||
]]] | ||
].reverse()] | ||
} | ||
@@ -1140,3 +1176,2 @@ }, | ||
expect(result.features).to.have.length(2); | ||
expect(_.pluck(_.pluck(result.features,"properties"),"id")).to.eql([1,2]); | ||
expect(result.features[0].properties.id).to.eql(1); | ||
@@ -1229,6 +1264,5 @@ expect(result.features[1].properties.id).to.eql(2); | ||
expect(result.features[0].properties.id).to.equal(1); | ||
expect(result.features[0].geometry.type).to.equal("MultiPolygon"); | ||
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(1); | ||
/* | ||
// simple multipolygon | ||
@@ -1313,4 +1347,2 @@ json = { | ||
expect(result.features[0].geometry.coordinates).to.have.length(1); | ||
expect(result.features[0].geometry.coordinates[0]).to.have.length(1); | ||
*/ | ||
}); | ||
@@ -1382,6 +1414,5 @@ // non-trivial ring building (way order and direction) | ||
expect(result.features[0].properties.id).to.equal(1); | ||
expect(result.features[0].geometry.type).to.equal("MultiPolygon"); | ||
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(1); | ||
expect(result.features[0].geometry.coordinates[0][0]).to.have.length(4); | ||
expect(result.features[0].geometry.coordinates[0]).to.have.length(4); | ||
// way directions | ||
@@ -1498,6 +1529,5 @@ json = { | ||
expect(result.features[0].properties.id).to.equal(1); | ||
expect(result.features[0].geometry.type).to.equal("MultiPolygon"); | ||
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(1); | ||
expect(result.features[0].geometry.coordinates[0][0]).to.have.length(7); | ||
expect(result.features[0].geometry.coordinates[0]).to.have.length(7); | ||
}); | ||
@@ -1565,6 +1595,5 @@ // unclosed rings | ||
expect(result.features[0].properties.id).to.equal(1); | ||
expect(result.features[0].geometry.type).to.equal("MultiPolygon"); | ||
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(1); | ||
expect(result.features[0].geometry.coordinates[0][0]).to.have.length(4); | ||
expect(result.features[0].geometry.coordinates[0]).to.have.length(4); | ||
expect(result.features[0].properties.tainted).to.not.equal(true); | ||
@@ -1630,6 +1659,5 @@ // matching ways, but unclosed ring | ||
expect(result.features[0].properties.id).to.equal(1); | ||
expect(result.features[0].geometry.type).to.equal("MultiPolygon"); | ||
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(1); | ||
expect(result.features[0].geometry.coordinates[0][0]).to.have.length(4); | ||
expect(result.features[0].geometry.coordinates[0]).to.have.length(4); | ||
expect(result.features[0].properties.tainted).to.not.equal(true); | ||
@@ -2602,1 +2630,39 @@ }); | ||
}); | ||
describe("other", function () { | ||
// | ||
it("sideeffects", function () { | ||
var json, json_before, json_after; | ||
json = { | ||
elements: [ | ||
{ | ||
type: "node", | ||
id: 1, | ||
tags: {"foo": "bar"}, | ||
user: "johndoe", | ||
lat: 1.234, | ||
lon: 4.321 | ||
}, | ||
{ | ||
type: "node", | ||
id: 2 | ||
}, | ||
{ | ||
type: "way", | ||
id: 1, | ||
nodes: [1,2,3] | ||
}, | ||
{ | ||
type: "relation", | ||
id: 1, | ||
members: [{type: "way", ref:1},{type: "way", ref:2},{type: "node", ref:1}] | ||
} | ||
] | ||
}; | ||
json_before = JSON.stringify(json); | ||
osmtogeojson.toGeojson(json); | ||
json_after = JSON.stringify(json); | ||
expect(json_after).to.equal(json_before); | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
658527
24
5054
2
72
2
1
+ Addedgeojson-rewind@0.1.0
+ Addedconcat-stream@1.2.1(transitive)
+ Addedgeojson-area@0.1.0(transitive)
+ Addedgeojson-rewind@0.1.0(transitive)
+ Addedminimist@0.0.5(transitive)
+ Addedwgs84@0.0.0(transitive)
- Removedlodash@~2.2.0
- Removedlodash@2.2.1(transitive)