add validation for very close node on road

addresses issue #6241

also made a change in inspector, so that when an untagged entity has issues,
show the entity editor so that the issues are visible when an item is clicked
in the issues pane.
This commit is contained in:
Ming Gao
2019-04-29 22:57:15 -04:00
parent a3605f9b74
commit 18dff285d0
5 changed files with 112 additions and 15 deletions
+7
View File
@@ -1403,6 +1403,11 @@ en:
unknown_road:
message: "{feature} has no classification"
reference: "Roads without a specific type may not appear in maps or routing."
dupe_node_on_road:
title: Very close nodes on road
message: "Very close nodes on road"
ref_merge: "Nodes are less than 2 meters away; you may want to merge them."
ref_move_away: "Nodes are less than 2 meters away but not mergable; you may want to move them further apart."
impossible_oneway:
title: Impossible One-Ways
tip: "Find route issues with one-way features"
@@ -1491,6 +1496,8 @@ en:
title: Use different levels
use_tunnel:
title: Use a tunnel
merge_nodes:
title: Merge these nodes
intro:
done: done
ok: OK
+9 -14
View File
@@ -1737,6 +1737,12 @@
"message": "{feature} has no classification",
"reference": "Roads without a specific type may not appear in maps or routing."
},
"dupe_node_on_road": {
"title": "Very close nodes on road",
"message": "Very close nodes on road",
"ref_merge": "Nodes are less than 2 meters away; you may want to merge them.",
"ref_move_away": "Nodes are less than 2 meters away but not mergable; you may want to move them further apart."
},
"impossible_oneway": {
"title": "Impossible One-Ways",
"tip": "Find route issues with one-way features",
@@ -1863,6 +1869,9 @@
},
"use_tunnel": {
"title": "Use a tunnel"
},
"merge_nodes": {
"title": "Merge these nodes"
}
}
},
@@ -9092,20 +9101,6 @@
"description": "Japan GSI ortho Imagery. Usually better than bing, but a bit older.",
"name": "Japan GSI ortho Imagery"
},
"gsi.go.jp_airphoto": {
"attribution": {
"text": "GSI Japan"
},
"description": "Japan GSI airphoto Imagery. Not fully orthorectified, but a bit newer and/or differently covered than GSI ortho Imagery.",
"name": "Japan GSI airphoto Imagery"
},
"gsi.go.jp_seamlessphoto": {
"attribution": {
"text": "GSI Japan seamless photo"
},
"description": "Japan GSI seamlessphoto Imagery. The collection of latest imageries of GSI ortho, airphoto, post disaster and others.",
"name": "Japan GSI seamlessphoto Imagery"
},
"gsi.go.jp_std_map": {
"attribution": {
"text": "GSI Japan"
+3 -1
View File
@@ -52,8 +52,10 @@ export function uiInspector(context) {
var hasNonGeometryTags = entity.hasNonGeometryTags();
var isTaglessOrIntersectionVertex = entity.geometry(context.graph()) === 'vertex' &&
(!hasNonGeometryTags && !entity.isHighwayIntersection(context.graph()));
var issues = context.validator().getEntityIssues(_entityID);
// start with the preset list if the feature is new and untagged or is an uninteresting vertex
var showPresetList = (newFeature && !hasNonGeometryTags) || isTaglessOrIntersectionVertex;
var showPresetList = issues.length === 0 &&
((newFeature && !hasNonGeometryTags) || isTaglessOrIntersectionVertex);
if (showPresetList) {
wrap.style('right', '-100%');
+92
View File
@@ -0,0 +1,92 @@
import { operationMerge } from '../operations/index';
import { t } from '../util/locale';
import { validationIssue, validationIssueFix } from '../core/validation';
import { geoExtent } from '../geo';
export function validationDupeNodeOnRoad() {
var type = 'dupe_node_on_road';
function isNodeOnRoad(node, context) {
var parentWays = context.graph().parentWays(node);
for (var i = 0; i < parentWays.length; i++) {
if (parentWays[i].tags.highway) {
return true;
}
}
return false;
}
function findDupeNode(node, context) {
var epsilon = 2e-5,
extent = geoExtent([
[node.loc[0] - epsilon, node.loc[1] - epsilon],
[node.loc[0] + epsilon, node.loc[1] + epsilon]
]);
var filteredEnts = context.intersects(extent);
for (var i = 0; i < filteredEnts.length; i++) {
var entity = filteredEnts[i];
if (entity.type === 'node' && entity.id !== node.id &&
Math.abs(node.loc[0] - entity.loc[0]) < epsilon &&
Math.abs(node.loc[1] - entity.loc[1]) < epsilon &&
isNodeOnRoad(entity, context) ) {
return entity;
}
}
return null;
}
var validation = function(entity, context) {
if (entity.type !== 'node' || !isNodeOnRoad(entity, context)) return [];
var dupe = findDupeNode(entity, context);
if (dupe === null) return [];
var mergable = !operationMerge([entity.id, dupe.id], context).disabled();
var fixes = [];
if (mergable) {
fixes.push(
new validationIssueFix({
icon: 'iD-icon-plus',
title: t('issues.fix.merge_nodes.title'),
onClick: function() {
var entities = this.issue.entities,
operation = operationMerge([entities[0].id, entities[1].id], context);
if (!operation.disabled()) {
operation();
}
}
})
);
}
return [new validationIssue({
type: type,
severity: 'warning',
message: t('issues.dupe_node_on_road.message'),
reference: showReference,
entities: [entity, dupe],
fixes: fixes
})];
function showReference(selection) {
var referenceText = mergable
? t('issues.dupe_node_on_road.ref_merge')
: t('issues.dupe_node_on_road.ref_move_away');
selection.selectAll('.issue-reference')
.data([0])
.enter()
.append('div')
.attr('class', 'issue-reference')
.text(referenceText);
}
};
validation.type = type;
return validation;
}
+1
View File
@@ -1,6 +1,7 @@
export { validationAlmostJunction } from './almost_junction';
export { validationCrossingWays } from './crossing_ways';
export { validationDisconnectedWay } from './disconnected_way';
export { validationDupeNodeOnRoad } from './dupe_node_on_road';
export { validationFixmeTag } from './fixme_tag';
export { validationGenericName } from './generic_name';
export { validationImpossibleOneway } from './impossible_oneway';