Files
iD/modules/validations/crossing_ways.js
2018-12-20 12:16:54 -05:00

113 lines
4.2 KiB
JavaScript

import { geoExtent, geoLineIntersection } from '../geo';
import { set as d3_set } from 'd3-collection';
import { t } from '../util/locale';
import {
ValidationIssueType,
ValidationIssueSeverity,
validationIssue,
} from './validation_issue';
export function validationHighwayCrossingOtherWays() {
// Check if the edge going from n1 to n2 crosses (without a connection node)
// any edge on way. Return the corss point if so.
function findEdgeToWayCrossCoords(n1, n2, way, graph, edgePairsVisited) {
var crossCoords = [];
for (var j = 0; j < way.nodes.length - 1; j++) {
var nidA = way.nodes[j],
nidB = way.nodes[j + 1];
if (nidA === n1.id || nidA === n2.id ||
nidB === n1.id || nidB === n2.id) {
// n1 or n2 is a connection node; skip
continue;
}
var edgePair = edgePairString(n1.id, n2.id, nidA, nidB);
if (edgePairsVisited.has(edgePair)) continue;
edgePairsVisited.add(edgePair);
var nA = graph.entity(nidA),
nB = graph.entity(nidB),
point = geoLineIntersection([n1.loc, n2.loc], [nA.loc, nB.loc]);
if (point) crossCoords.push(point);
}
return crossCoords;
}
// n1 and n2 from one edge, nA and nB from the other edge
function edgePairString(n1, n2, nA, nB) {
return n1 > nA ? n1 + n2 + nA + nB : nA + nB + n1 + n2;
}
function findCrossingsByWay(entity, graph, tree, edgePairsVisited) {
var edgeCrossInfos = [];
if (entity.type !== 'way' || !entity.tags.highway) return edgeCrossInfos;
if (entity.geometry(graph) !== 'line') return edgeCrossInfos;
for (var i = 0; i < entity.nodes.length - 1; i++) {
var nid1 = entity.nodes[i],
nid2 = entity.nodes[i + 1],
n1 = graph.entity(nid1),
n2 = graph.entity(nid2),
extent = geoExtent([
[
Math.min(n1.loc[0], n2.loc[0]),
Math.min(n1.loc[1], n2.loc[1])
],
[
Math.max(n1.loc[0], n2.loc[0]),
Math.max(n1.loc[1], n2.loc[1])
]
]),
intersected = tree.intersects(extent, graph);
for (var j = 0; j < intersected.length; j++) {
if (intersected[j].type !== 'way') continue;
// only check crossing highway, waterway, building, and railway
var way = intersected[j];
if (!(way.tags.highway || way.tags.building ||
way.tags.railway || way.tags.waterway)) {
continue;
}
if (way.tags.waterway && entity.tags.bridge === 'yes') {
continue;
}
var crossCoords = findEdgeToWayCrossCoords(n1, n2, way, graph, edgePairsVisited);
for (var k = 0; k < crossCoords.length; k++) {
edgeCrossInfos.push({
ways: [entity, way],
cross_point: crossCoords[k],
});
}
}
}
return edgeCrossInfos;
}
var validation = function(changes, graph, tree) {
// create one issue per crossing point
var edited = changes.created.concat(changes.modified),
edgePairsVisited = d3_set(),
issues = [];
for (var i = 0; i < edited.length; i++) {
var crosses = findCrossingsByWay(edited[i], graph, tree, edgePairsVisited);
for (var j = 0; j < crosses.length; j++) {
issues.push(new validationIssue({
type: ValidationIssueType.crossing_ways,
severity: ValidationIssueSeverity.error,
message: t('issues.crossing_ways.message'),
tooltip: t('issues.crossing_ways.tooltip'),
entities: crosses[j].ways,
coordinates: crosses[j].cross_point,
}));
}
}
return issues;
};
return validation;
}