diff --git a/data/core.yaml b/data/core.yaml index b4b210721..b8e9fa945 100644 --- a/data/core.yaml +++ b/data/core.yaml @@ -1171,13 +1171,13 @@ en: crossing_ways: message: "{feature} crosses {feature2} without enough context." building-building: - tip: Buildings should not intersect except on separate layers. + tip: Buildings should not intersect except on different layers. building-highway: tip: Highways crossing buildings should use bridges, tunnels, coverings, or entrances. building-railway: tip: Railways crossing buildings should use bridges or tunnels. building-water: - tip: Waterways crossing buildings should use tunnels or separate layers. + tip: Waterways crossing buildings should use tunnels or different layers. highway-highway: tip: Crossing highways should use bridges, tunnels, or intersections. highway-railway: @@ -1190,6 +1190,10 @@ en: tip: Railways crossing water should use bridges or tunnels. water-water: tip: Crossing waterways should be connected or use tunnels. + tunnel-tunnel: + tip: Crossing tunnels should use different layers. + bridge-bridge: + tip: Crossing bridges should use different layers. highway_almost_junction: message: "{highway} is very close but not connected to {highway2}." tip: Intersecting highways should share a junction vertex. diff --git a/dist/locales/en.json b/dist/locales/en.json index 6d9df650a..5734d28c9 100644 --- a/dist/locales/en.json +++ b/dist/locales/en.json @@ -1422,7 +1422,7 @@ "crossing_ways": { "message": "{feature} crosses {feature2} without enough context.", "building-building": { - "tip": "Buildings should not intersect except on separate layers." + "tip": "Buildings should not intersect except on different layers." }, "building-highway": { "tip": "Highways crossing buildings should use bridges, tunnels, coverings, or entrances." @@ -1431,7 +1431,7 @@ "tip": "Railways crossing buildings should use bridges or tunnels." }, "building-water": { - "tip": "Waterways crossing buildings should use tunnels or separate layers." + "tip": "Waterways crossing buildings should use tunnels or different layers." }, "highway-highway": { "tip": "Crossing highways should use bridges, tunnels, or intersections." @@ -1450,6 +1450,12 @@ }, "water-water": { "tip": "Crossing waterways should be connected or use tunnels." + }, + "tunnel-tunnel": { + "tip": "Crossing tunnels should use different layers." + }, + "bridge-bridge": { + "tip": "Crossing bridges should use different layers." } }, "highway_almost_junction": { diff --git a/modules/validations/crossing_ways.js b/modules/validations/crossing_ways.js index 2631f37fc..a83e7a307 100644 --- a/modules/validations/crossing_ways.js +++ b/modules/validations/crossing_ways.js @@ -146,6 +146,28 @@ export function validationHighwayCrossingOtherWays(context) { return false; } + function canConnectEntities(entity1, entity2) { + var featureType1 = getFeatureTypeForTags(entity1.tags); + var featureType2 = getFeatureTypeForTags(entity2.tags); + if (featureType1 === featureType2) { + if (featureType1 === 'highway') return true; + if (featureType1 === 'water') return true; + if (featureType1 === 'railway') return true; + } else { + var featureTypes = new Set([featureType1, featureType2]); + if (featureTypes.has('highway')) { + if (featureTypes.has('water')) { + // do not allow adding fords on structures + if (hasTag(entity1.tags, 'tunnel') && hasTag(entity2.tags, 'tunnel')) return false; + if (hasTag(entity1.tags, 'bridge') && hasTag(entity2.tags, 'bridge')) return false; + return true; + } + if (featureTypes.has('building') || featureTypes.has('railway')) return true; + } + } + return false; + } + function findCrossingsByWay(entity, graph, tree, edgePairsVisited) { var edgeCrossInfos = []; if (entity.type !== 'way') return edgeCrossInfos; @@ -238,14 +260,54 @@ export function validationHighwayCrossingOtherWays(context) { entities = _map(entities, function(way) { return getFeatureWithFeatureTypeTagsForWay(way, graph); }); - - var crossingTypeID = crossing.featureTypes.sort().join('-'); + var crossingTypeID; + if (hasTag(entities[0].tags, 'tunnel') && hasTag(entities[1].tags, 'tunnel')) { + crossingTypeID = 'tunnel-tunnel'; + } + else if (hasTag(entities[0].tags, 'bridge') && hasTag(entities[1].tags, 'bridge')) { + crossingTypeID = 'bridge-bridge'; + } + else { + crossingTypeID = crossing.featureTypes.sort().join('-'); + } var messageDict = { feature: utilDisplayLabel(entities[0], context), feature2: utilDisplayLabel(entities[1], context) }; + var fixes = []; + if (canConnectEntities(entities[0], entities[1])) { + fixes.push(new validationIssueFix({ + title: t('issues.fix.add_connection_vertex.title'), + onClick: function() { + var loc = this.issue.coordinates; + var ways = this.issue.info.ways; + + context.perform( + function actionConnectCrossingWays(graph) { + + var node = osmNode(); + graph = graph.replace(node); + + var way0 = graph.entity(ways[0].id); + var choice0 = geoChooseEdge(graph.childNodes(way0), loc, context.projection); + var edge0 = [way0.nodes[choice0.index - 1], way0.nodes[choice0.index]]; + graph = actionAddMidpoint({loc: choice0.loc, edge: edge0}, node)(graph); + + var way1 = graph.entity(ways[1].id); + var choice1 = geoChooseEdge(graph.childNodes(way1), loc, context.projection); + var edge1 = [way1.nodes[choice1.index - 1], way1.nodes[choice1.index]]; + graph = actionAddMidpoint({loc: choice1.loc, edge: edge1}, node)(graph); + + return graph; + }, + t('issues.fix.add_connection_vertex.undo_redo') + ); + } + })); + } + issues.push(new validationIssue({ type: ValidationIssueType.crossing_ways, severity: ValidationIssueSeverity.warning, @@ -254,36 +316,7 @@ export function validationHighwayCrossingOtherWays(context) { entities: entities, info: {'ways': crossing.ways}, coordinates: crossing.cross_point, - fixes: [ - new validationIssueFix({ - title: t('issues.fix.add_connection_vertex.title'), - onClick: function() { - var loc = this.issue.coordinates; - var ways = this.issue.info.ways; - - context.perform( - function actionConnectCrossingWays(graph) { - - var node = osmNode(); - graph = graph.replace(node); - - var way0 = graph.entity(ways[0].id); - var choice0 = geoChooseEdge(graph.childNodes(way0), loc, context.projection); - var edge0 = [way0.nodes[choice0.index - 1], way0.nodes[choice0.index]]; - graph = actionAddMidpoint({loc: choice0.loc, edge: edge0}, node)(graph); - - var way1 = graph.entity(ways[1].id); - var choice1 = geoChooseEdge(graph.childNodes(way1), loc, context.projection); - var edge1 = [way1.nodes[choice1.index - 1], way1.nodes[choice1.index]]; - graph = actionAddMidpoint({loc: choice1.loc, edge: edge1}, node)(graph); - - return graph; - }, - t('issues.fix.add_connection_vertex.undo_redo') - ); - } - }) - ] + fixes: fixes })); } }