mirror of
https://github.com/FoggedLens/iD.git
synced 2026-04-29 15:16:07 +02:00
validate crossing aeroways (#9315)
This commit is contained in:
committed by
Martin Raifer
parent
a2e347ac97
commit
f244e63661
@@ -41,6 +41,7 @@ _Breaking developer changes, which may affect downstream projects or sites that
|
||||
#### :scissors: Operations
|
||||
#### :camera: Street-Level
|
||||
#### :white_check_mark: Validation
|
||||
* Add warning if aeroways cross each other, buildings or highways ([#9315], thanks [@k-yle])
|
||||
#### :bug: Bugfixes
|
||||
* Prevent degenerate ways caused by deleting a corner of a triangle ([#10003], thanks [@k-yle])
|
||||
#### :earth_asia: Localization
|
||||
|
||||
@@ -1778,6 +1778,16 @@ en:
|
||||
title: Crossing Ways
|
||||
message: "{feature} crosses {feature2}"
|
||||
tip: "Find features that incorrectly cross over one another"
|
||||
aeroway-aeroway:
|
||||
reference: "Crossing aeroways should be connected."
|
||||
aeroway-building:
|
||||
reference: "Aeroways crossing buildings should use bridges or different layers."
|
||||
aeroway-highway:
|
||||
reference: "Aeroways crossing railways should be connected."
|
||||
aeroway-railway:
|
||||
reference: "Aeroways crossing highways should be connected."
|
||||
aeroway-waterway:
|
||||
reference: "Aeroways crossing waterways should use tunnels."
|
||||
building-building:
|
||||
reference: "Buildings should not intersect except on different layers."
|
||||
building-highway:
|
||||
|
||||
@@ -233,6 +233,10 @@ export var osmRoutableHighwayTagValues = {
|
||||
unclassified: true, road: true, service: true, track: true, living_street: true, bus_guideway: true, busway: true,
|
||||
path: true, footway: true, cycleway: true, bridleway: true, pedestrian: true, corridor: true, steps: true, ladder: true
|
||||
};
|
||||
/** aeroway tags that are treated as routable for aircraft */
|
||||
export const osmRoutableAerowayTags = {
|
||||
runway: true, taxiway: true
|
||||
};
|
||||
// "highway" tag values that generally do not allow motor vehicles
|
||||
export var osmPathHighwayTagValues = {
|
||||
path: true, footway: true, cycleway: true, bridleway: true, pedestrian: true, corridor: true, steps: true, ladder: true
|
||||
|
||||
@@ -8,7 +8,7 @@ import { modeSelect } from '../modes/select';
|
||||
import { geoAngle, geoExtent, geoLatToMeters, geoLonToMeters, geoLineIntersection,
|
||||
geoSphericalClosestNode, geoSphericalDistance, geoVecAngle, geoVecLength, geoMetersToLat, geoMetersToLon } from '../geo';
|
||||
import { osmNode } from '../osm/node';
|
||||
import { osmFlowingWaterwayTagValues, osmPathHighwayTagValues, osmRailwayTrackTagValues, osmRoutableHighwayTagValues } from '../osm/tags';
|
||||
import { osmFlowingWaterwayTagValues, osmPathHighwayTagValues, osmRailwayTrackTagValues, osmRoutableAerowayTags, osmRoutableHighwayTagValues } from '../osm/tags';
|
||||
import { t } from '../core/localizer';
|
||||
import { utilDisplayLabel } from '../util/utilDisplayLabel';
|
||||
import { validationIssue, validationIssueFix } from '../core/validation';
|
||||
@@ -44,7 +44,7 @@ export function validationCrossingWays(context) {
|
||||
}
|
||||
|
||||
function allowsBridge(featureType) {
|
||||
return featureType === 'highway' || featureType === 'railway' || featureType === 'waterway';
|
||||
return featureType === 'highway' || featureType === 'railway' || featureType === 'waterway' || featureType === 'aeroway';
|
||||
}
|
||||
function allowsTunnel(featureType) {
|
||||
return featureType === 'highway' || featureType === 'railway' || featureType === 'waterway';
|
||||
@@ -63,6 +63,8 @@ export function validationCrossingWays(context) {
|
||||
|
||||
var tags = entity.tags;
|
||||
|
||||
if (tags.aeroway in osmRoutableAerowayTags) return 'aeroway';
|
||||
|
||||
if (hasTag(tags, 'building') && !ignoredBuildings[tags.building]) return 'building';
|
||||
if (hasTag(tags, 'highway') && osmRoutableHighwayTagValues[tags.highway]) return 'highway';
|
||||
|
||||
@@ -126,6 +128,9 @@ export function validationCrossingWays(context) {
|
||||
primary: true, primary_link: true, secondary: true, secondary_link: true
|
||||
};
|
||||
|
||||
/**
|
||||
* @returns {object | null} the tags for the connecting node, or null if the entities should not be joined
|
||||
*/
|
||||
function tagsForConnectionNodeIfAllowed(entity1, entity2, graph, lessLikelyTags) {
|
||||
var featureType1 = getFeatureType(entity1, graph);
|
||||
var featureType2 = getFeatureType(entity2, graph);
|
||||
@@ -134,6 +139,27 @@ export function validationCrossingWays(context) {
|
||||
var geometry2 = entity2.geometry(graph);
|
||||
var bothLines = geometry1 === 'line' && geometry2 === 'line';
|
||||
|
||||
/**
|
||||
* @typedef {NonNullable<ReturnType<getFeatureType>>} FeatureType
|
||||
* @type {`${FeatureType}-${FeatureType}`}
|
||||
*/
|
||||
const featureTypes = [featureType1, featureType2].sort().join('-');
|
||||
|
||||
if (featureTypes === 'aeroway-aeroway') return {};
|
||||
|
||||
if (featureTypes === 'aeroway-highway') {
|
||||
const isServiceRoad = entity1.tags.highway === 'service' || entity2.tags.highway === 'service';
|
||||
const isPath = entity1.tags.highway in osmPathHighwayTagValues || entity2.tags.highway in osmPathHighwayTagValues;
|
||||
// only significant roads get the aeroway=aircraft_crossing tag
|
||||
return isServiceRoad || isPath ? {} : { aeroway: 'aircraft_crossing' };
|
||||
}
|
||||
|
||||
if (featureTypes === 'aeroway-railway') {
|
||||
return { aeroway: 'aircraft_crossing', railway: 'level_crossing' };
|
||||
}
|
||||
|
||||
if (featureTypes === 'aeroway-waterway') return null;
|
||||
|
||||
if (featureType1 === featureType2) {
|
||||
if (featureType1 === 'highway') {
|
||||
var entity1IsPath = osmPathHighwayTagValues[entity1.tags.highway];
|
||||
@@ -167,7 +193,6 @@ export function validationCrossingWays(context) {
|
||||
if (featureType1 === 'railway') return {};
|
||||
|
||||
} else {
|
||||
var featureTypes = [featureType1, featureType2];
|
||||
if (featureTypes.indexOf('highway') !== -1) {
|
||||
if (featureTypes.indexOf('railway') !== -1) {
|
||||
if (!bothLines) return {};
|
||||
|
||||
@@ -202,6 +202,60 @@ describe('iD.validations.crossing_ways', function () {
|
||||
expect(issues).to.have.lengthOf(0);
|
||||
});
|
||||
|
||||
it('ignores a routable aeroway crossing a non-routable aeroway', function() {
|
||||
createWaysWithOneCrossingPoint({ aeroway: 'taxiway' }, { aeroway: 'aerodrome' });
|
||||
const issues = validate();
|
||||
expect(issues).to.have.lengthOf(0);
|
||||
});
|
||||
|
||||
it('ignores an aeroway crossing a road tunnel', function() {
|
||||
createWaysWithOneCrossingPoint({ aeroway: 'runway' }, { highway: 'trunk', tunnel: 'yes', layer: '-1' });
|
||||
const issues = validate();
|
||||
expect(issues).to.have.lengthOf(0);
|
||||
});
|
||||
|
||||
it('ignores an aeroway crossing a road bridge', function() {
|
||||
createWaysWithOneCrossingPoint({ aeroway: 'runway' }, { highway: 'trunk', bridge: 'yes', layer: '1' });
|
||||
const issues = validate();
|
||||
expect(issues).to.have.lengthOf(0);
|
||||
});
|
||||
|
||||
it('ignores an aeroway crossing a rail tunnel', function() {
|
||||
createWaysWithOneCrossingPoint({ aeroway: 'runway' }, { railway: 'track', tunnel: 'yes', layer: '-1' });
|
||||
const issues = validate();
|
||||
expect(issues).to.have.lengthOf(0);
|
||||
});
|
||||
|
||||
it('ignores an aeroway crossing a rail bridge', function() {
|
||||
createWaysWithOneCrossingPoint({ aeroway: 'runway' }, { railway: 'track', bridge: 'yes', layer: '1' });
|
||||
const issues = validate();
|
||||
expect(issues).to.have.lengthOf(0);
|
||||
});
|
||||
|
||||
it('ignores an aeroway bridge crossing a road', function() {
|
||||
createWaysWithOneCrossingPoint({ aeroway: 'runway', bridge: 'yes', layer: '2' }, { highway: 'trunk', layer: '1' });
|
||||
const issues = validate();
|
||||
expect(issues).to.have.lengthOf(0);
|
||||
});
|
||||
|
||||
it('ignores an aeroway bridge crossing a railway', function() {
|
||||
createWaysWithOneCrossingPoint({ aeroway: 'runway', bridge: 'yes', layer: '1' }, { railway: 'track' });
|
||||
const issues = validate();
|
||||
expect(issues).to.have.lengthOf(0);
|
||||
});
|
||||
|
||||
it('ignores an aeroway crossing a culvert', function() {
|
||||
createWaysWithOneCrossingPoint({ aeroway: 'taxiway' }, { waterway: 'ditch', tunnel: 'culvert', layer: -1 });
|
||||
const issues = validate();
|
||||
expect(issues).to.have.lengthOf(0);
|
||||
});
|
||||
|
||||
it('ignores an aeroway crossing a building on a different layer', function() {
|
||||
createWaysWithOneCrossingPoint({ aeroway: 'runway' }, { building: 'yes', layer: '0.5' });
|
||||
const issues = validate();
|
||||
expect(issues).to.have.lengthOf(0);
|
||||
});
|
||||
|
||||
// warning crossing cases between ways
|
||||
it('flags road crossing road', function() {
|
||||
createWaysWithOneCrossingPoint({ highway: 'residential' }, { highway: 'residential' });
|
||||
@@ -453,4 +507,38 @@ describe('iD.validations.crossing_ways', function () {
|
||||
verifySingleCrossingIssue(validate(), {});
|
||||
});
|
||||
|
||||
it('flags an aeroway crosing another aeroway', function() {
|
||||
createWaysWithOneCrossingPoint({ aeroway: 'runway' }, { aeroway: 'taxiway' });
|
||||
verifySingleCrossingIssue(validate(), {});
|
||||
});
|
||||
|
||||
it('flags an aeroway crosing a major road', function() {
|
||||
createWaysWithOneCrossingPoint({ aeroway: 'runway' }, { highway: 'motorway' });
|
||||
verifySingleCrossingIssue(validate(), { aeroway: 'aircraft_crossing' });
|
||||
});
|
||||
|
||||
it('flags an aeroway crosing a service road', function() {
|
||||
createWaysWithOneCrossingPoint({ aeroway: 'runway' }, { highway: 'service' });
|
||||
verifySingleCrossingIssue(validate(), {});
|
||||
});
|
||||
|
||||
it('flags an aeroway crosing a path', function() {
|
||||
createWaysWithOneCrossingPoint({ aeroway: 'runway' }, { highway: 'corridor' });
|
||||
verifySingleCrossingIssue(validate(), {});
|
||||
});
|
||||
|
||||
it('flags an aeroway crosing a railway', function() {
|
||||
createWaysWithOneCrossingPoint({ aeroway: 'taxiway' }, { railway: 'disused' });
|
||||
verifySingleCrossingIssue(validate(), { aeroway: 'aircraft_crossing', railway: 'level_crossing' });
|
||||
});
|
||||
|
||||
it('flags an aeroway crosing a waterway', function() {
|
||||
createWaysWithOneCrossingPoint({ aeroway: 'runway' }, { waterway: 'canal' });
|
||||
verifySingleCrossingIssue(validate(), null);
|
||||
});
|
||||
|
||||
it('flags an aeroway crosing a building', function() {
|
||||
createWaysWithOneCrossingPoint({ aeroway: 'runway' }, { building: 'hangar' });
|
||||
verifySingleCrossingIssue(validate(), null);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user