/**
* @constructor ToGeoJSON
* @param {Object} options provided by the provider
* @description osm to geojson without dependencies :)
Import Note : geojson wait for lon/lat where every body else use lat/lon
*/
function factory(options) {
//copy/pasted/adapter from https://github.com/jfirebaugh/leaflet-osm/blob/master/leaflet-osm.js
var service = {
options,
getAsArray,
getFeatures,
getNodes,
getWays,
getRelations,
getTags,
buildFeatures,
isWayArea,
interestingNode,
togeojson
};
return service;
function getFeatures(data) {
var features = [];
if (!(data instanceof Array)) {
data = buildFeatures(data);
}
for (let i = 0; i < data.length; i++) {
var d = data[i];
var feature = {
type: 'Feature',
geometry: {},
properties: {
id: d.id,
tags: d.tags
}
};
if (d.type === "changeset") {
//build rectangle
// X = Long; Y = Lat, lets do it clockwise
feature.geometry.type = 'Polygon';
var bounds = d.latLngBounds;
feature.geometry.coordinates = [[
[parseFloat(bounds._min_lon), parseFloat(bounds._min_lat)],
[parseFloat(bounds._min_lon), parseFloat(bounds._max_lat)],
[parseFloat(bounds._max_lon), parseFloat(bounds._max_lat)],
[parseFloat(bounds._max_lon), parseFloat(bounds._min_lat)],
[parseFloat(bounds._min_lon), parseFloat(bounds._min_lat)]
]];
} else if (d.type === "node") {
//add a Point
feature.geometry.type = 'Point';
feature.geometry.coordinates = [d.latLng[1], d.latLng[0]];
} else {
var lngLats = new Array(d.nodes.length);
for (let j = 0; j < d.nodes.length; j++) {
let latLng = d.nodes[j].latLng;
lngLats[j] = [latLng[1], latLng[0]];
}
if (isWayArea(d)) {
feature.geometry.type = 'Polygon';
feature.geometry.coordinates = [lngLats];
} else {
feature.geometry.type = 'LineString';
feature.geometry.coordinates = lngLats;
}
}
features.push(feature);
}
return features;
}
function getAsArray(data) {
if (Array.isArray(data)) {
return data;
} else if (typeof data === "object") {
return [data];
} else {
return [];
}
}
function getTags(data) {
var rawtags = getAsArray(data.tag);
var tags = {};
rawtags.forEach(function (t) {
tags[t._k] = t._v;
});
return tags;
}
function getChangesets(data) {
var result = [];
var nodes = getAsArray(data.osm.changeset);
for (var i = 0; i < nodes.length; i++) {
var node = nodes[i];
result.push({
id: node._id,
type: "changeset",
latLngBounds: node,
tags: getTags(node)
});
}
return result;
}
function getNodes(data) {
var nodesAsArray = getAsArray(data.osm.node);
var nodesById = {};
nodesAsArray.forEach(function (node) {
nodesById[node._id] = {
id: node._id,
type: 'node',
latLng: [parseFloat(node._lat), parseFloat(node._lon)],
tags: getTags(node)
};
});
return nodesById;
}
function getWays(data, nodes) {
var result = [];
var ways = getAsArray(data.osm.way);
var features = [];
ways.forEach(function (way) {
var nds = way.nd;
var way_object = {
id: way._id,
type: "way",
nodes: new Array(nds.length),
tags: getTags(way)
};
for (let j = 0; j < nds.length; j++) {
way_object.nodes[j] = nodes[nds[j]._ref];
}
result.push(way_object);
});
return result;
}
function getRelations(data, nodes, way) {
var result = [];
var rels = getAsArray(data.osm.relation);
for (let i = 0; i < rels.length; i++) {
var rel = rels[i];
var members = getAsArray(rel.member);
var rel_object = {
id: rel._id,
type: "relation",
members: new Array(members.length),
tags: getTags(rel)
};
for (let j = 0; j < members.length; j++) {
if (members[j]._type === "node") {
rel_object.members[j] = nodes[members[j]._ref];
} else{
// relation-way and relation-relation membership not implemented
rel_object.members[j] = null;
}
}
result.push(rel_object);
}
return result;
}
function buildFeatures(data) {
var features = [];
var nodes = getNodes(data); //-> {id: data, ...}
var ways = getWays(data, nodes); //->[]
var relations = getRelations(data, nodes, ways); //->[]
for (let node_id in nodes) {
var node = nodes[node_id];
if (interestingNode(node, ways, relations)) {
features.push(node);
}
}
for (let i = 0; i < ways.length; i++) {
var way = ways[i];
features.push(way);
}
return features;
}
function isWayArea(way) {
if (way.nodes[0] != way.nodes[way.nodes.length - 1]) {
return false;
}
for (let key in way.tags) {
if (options.areaTags.indexOf(key)) {
return true;
}
}
return false;
}
function interestingNode(node, ways, relations) {
var used = false;
for (let i = 0; i < ways.length; i++) {
if (ways[i].nodes.indexOf(node) >= 0) {
used = true;
break;
}
}
if (!used) {
return true;
}
for (let i = 0; i < relations.length; i++) {
if (relations[i].members.indexOf(node) >= 0) {
return true;
}
}
return false;
}
function togeojson(data, options) {
var res = {
type: 'FeatureCollection',
features: []
};
if (data) {
res.features = getFeatures(data);
}
return res;
}
}
export default factory;