Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

osmtogeojson

Package Overview
Dependencies
Maintainers
1
Versions
30
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

osmtogeojson - npm Package Compare versions

Comparing version 1.4.0 to 2.0.0

coverage/coverage.json

8

CHANGELOG.md

@@ -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 @@ -----

684

osmtogeojson.js

@@ -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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc