modules/actions/extract.js (77 lines of code) (raw):
import { geoPath as d3_geoPath } from 'd3-geo';
import { osmNode } from '../osm/node';
export function actionExtract(entityID, projection) {
var extractedNodeID;
var action = function(graph) {
var entity = graph.entity(entityID);
if (entity.type === 'node') {
return extractFromNode(entity, graph);
}
return extractFromArea(entity, graph);
};
function extractFromNode(node, graph) {
extractedNodeID = node.id;
// Create a new node to replace the one we will detach
var replacement = osmNode({ loc: node.loc });
graph = graph.replace(replacement);
// Process each way in turn, updating the graph as we go
graph = graph.parentWays(node)
.reduce(function(accGraph, parentWay) {
return accGraph.replace(parentWay.replaceNode(entityID, replacement.id));
}, graph);
// Process any relations too
return graph.parentRelations(node)
.reduce(function(accGraph, parentRel) {
return accGraph.replace(parentRel.replaceMember(node, replacement));
}, graph);
}
function extractFromArea(entity, graph) {
var keysToCopyAndRetain = ['source', 'wheelchair'];
var keysToRetain = ['type'];
var buildingKeysToRetain = ['architect', 'building', 'height', 'layer'];
var centroid = d3_geoPath(projection).centroid(entity.asGeoJSON(graph, true));
var isBuilding = entity.tags.building;
var areaTags = Object.assign({}, entity.tags); // shallow copy
var pointTags = {};
for (var key in areaTags) {
if (keysToRetain.indexOf(key) !== -1) {
continue;
}
if (isBuilding) {
// don't transfer building-related tags
if (buildingKeysToRetain.indexOf(key) !== -1 ||
key.match(/^building:.{1,}/) ||
key.match(/^roof:.{1,}/)) continue;
}
// copy the tag from the area to the point
pointTags[key] = areaTags[key];
// leave addresses and some other tags so they're on both features
if (keysToCopyAndRetain.indexOf(key) !== -1 || key.match(/^addr:.{1,}/)) {
continue;
}
// remove the tag from the area
delete areaTags[key];
}
if (!isBuilding) {
// ensure that the area keeps the area geometry
areaTags.area = 'yes';
}
var replacement = osmNode({ loc: centroid, tags: pointTags });
graph = graph.replace(replacement);
extractedNodeID = replacement.id;
return graph.replace(entity.update({tags: areaTags}));
}
action.getExtractedNodeID = function() {
return extractedNodeID;
};
action.disabled = function(graph) {
var entity = graph.entity(entityID);
if (entity.type === 'node') {
var parentRels = graph.parentRelations(entity);
for (var i = 0; i < parentRels.length; i++) {
var relation = parentRels[i];
if (!relation.hasFromViaTo()) continue;
for (var j = 0; j < relation.members.length; j++) {
var m = relation.members[j];
if (m.id === entityID && (m.role === 'via' || m.role === 'location_hint')) {
return 'restriction';
}
}
}
}
return false;
};
return action;
}