+
osmtogeojson is a Javascript module for converting OSM data (OSM XML or Overpass JSON) to GeoJSON. It works in the browser, nodejs and can also be used as a command line tool. This OSM conversion code was written for and is maintained by the overpass-turbo project.
+
Usage:
+
+ - In the browser:
+
+
+ <script src='osmtogeojson.js'></script>
+
+
+ osmtogeojson(osm_data);
+
+
+
+ - As a nodejs library:
+
+
+ $ npm install osmtogeojson
+
+
+ var osmtogeojson = require('osmtogeojson');
+ osmtogeojson(xml_data);
+
+
+
+ - As a command line tool:
+
+
+ $ npm install -g osmtogeojson
+
+
+ $ osmtogeojson file.osm > file.geojson
+
+
+
+
+ Read more about the API in the official
documentation.
+
+
+
+
+
diff --git a/assets/osmtogeojson/index.js b/assets/osmtogeojson/index.js
new file mode 100644
index 0000000..4f9cf2d
--- /dev/null
+++ b/assets/osmtogeojson/index.js
@@ -0,0 +1,945 @@
+var _ = require("./lodash.custom.js");
+var rewind = require("geojson-rewind");
+
+// see https://wiki.openstreetmap.org/wiki/Overpass_turbo/Polygon_Features
+var polygonFeatures = {};
+require("osm-polygon-features").forEach(function(tags) {
+ if (tags.polygon === "all")
+ polygonFeatures[tags.key] = true;
+ else {
+ var list = (tags.polygon === "whitelist") ? "included_values" : "excluded_values",
+ tagValuesObj = {};
+ tags.values.forEach(function(value) { tagValuesObj[value] = true; });
+ polygonFeatures[tags.key] = {};
+ polygonFeatures[tags.key][list] = tagValuesObj;
+ }
+});
+
+var osmtogeojson = {};
+
+osmtogeojson = function( data, options ) {
+
+ options = _.merge(
+ {
+ verbose: false,
+ 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: polygonFeatures,
+ },
+ 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();
+ // helper functions
+ function centerGeometry(object) {
+ var pseudoNode = _.clone(object);
+ pseudoNode.lat = object.center.lat;
+ pseudoNode.lon = object.center.lon;
+ pseudoNode.__is_center_placeholder = true;
+ nodes.push(pseudoNode);
+ }
+ function boundsGeometry(object) {
+ var pseudoWay = _.clone(object);
+ pseudoWay.nodes = [];
+ function addPseudoNode(lat,lon,i) {
+ var pseudoNode = {
+ type:"node",
+ id: "_"+pseudoWay.type+"/"+pseudoWay.id+"bounds"+i,
+ lat: lat,
+ lon: lon
+ }
+ pseudoWay.nodes.push(pseudoNode.id);
+ nodes.push(pseudoNode);
+ }
+ addPseudoNode(pseudoWay.bounds.minlat,pseudoWay.bounds.minlon,1);
+ addPseudoNode(pseudoWay.bounds.maxlat,pseudoWay.bounds.minlon,2);
+ addPseudoNode(pseudoWay.bounds.maxlat,pseudoWay.bounds.maxlon,3);
+ addPseudoNode(pseudoWay.bounds.minlat,pseudoWay.bounds.maxlon,4);
+ pseudoWay.nodes.push(pseudoWay.nodes[0]);
+ pseudoWay.__is_bounds_placeholder = true;
+ ways.push(pseudoWay);
+ }
+ function fullGeometryWay(way) {
+ function addFullGeometryNode(lat,lon,id) {
+ var geometryNode = {
+ type:"node",
+ id: id,
+ lat: lat,
+ lon: lon,
+ __is_uninteresting: true
+ }
+ nodes.push(geometryNode);
+ }
+ if (!_.isArray(way.nodes)) {
+ way.nodes = way.geometry.map(function(nd) {
+ if (nd !== null) // have to skip ref-less nodes
+ return "_anonymous@"+nd.lat+"/"+nd.lon;
+ else
+ return "_anonymous@unknown_location";
+ });
+ }
+ way.geometry.forEach(function(nd, i) {
+ if (nd) {
+ addFullGeometryNode(
+ nd.lat,
+ nd.lon,
+ way.nodes[i]
+ );
+ }
+ });
+ }
+ function fullGeometryRelation(rel) {
+ function addFullGeometryNode(lat,lon,id) {
+ var geometryNode = {
+ type:"node",
+ id: id,
+ lat: lat,
+ lon: lon
+ }
+ nodes.push(geometryNode);
+ }
+ function addFullGeometryWay(geometry,id) {
+ // shared multipolygon ways cannot be defined multiple times with the same id.
+ if (ways.some(function (way) { // todo: this is slow :(
+ return way.type == "way" && way.id == id;
+ })) return;
+ var geometryWay = {
+ type: "way",
+ id: id,
+ nodes:[]
+ }
+ function addFullGeometryWayPseudoNode(lat,lon) {
+ // todo? do not save the same pseudo node multiple times
+ var geometryPseudoNode = {
+ type:"node",
+ id: "_anonymous@"+lat+"/"+lon,
+ lat: lat,
+ lon: lon,
+ __is_uninteresting: true
+ }
+ geometryWay.nodes.push(geometryPseudoNode.id);
+ nodes.push(geometryPseudoNode);
+ }
+ geometry.forEach(function(nd) {
+ if (nd) {
+ addFullGeometryWayPseudoNode(
+ nd.lat,
+ nd.lon
+ );
+ } else {
+ geometryWay.nodes.push(undefined);
+ }
+ });
+ ways.push(geometryWay);
+ }
+ rel.members.forEach(function(member, i) {
+ if (member.type == "node") {
+ if (member.lat) {
+ addFullGeometryNode(
+ member.lat,
+ member.lon,
+ member.ref
+ );
+ }
+ } else if (member.type == "way") {
+ if (member.geometry) {
+ member.ref = "_fullGeom"+member.ref;
+ addFullGeometryWay(
+ member.geometry,
+ member.ref
+ );
+ }
+ }
+ });
+ }
+ // 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