Skip to content

Commit 6e0fb61

Browse files
committed
automatically create pedestrian crossing line when joining sidewalk/road
1 parent 5024fea commit 6e0fb61

File tree

2 files changed

+84
-34
lines changed

2 files changed

+84
-34
lines changed

data/core.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1950,6 +1950,7 @@ en:
19501950
title: Connect the features
19511951
connect_using_crossing:
19521952
title: Connect using a crossing
1953+
annotation: Connected using a crossing.
19531954
connect_using_ford:
19541955
title: Connect using a ford
19551956
continue_from_start:

modules/validations/crossing_ways.js

Lines changed: 83 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,28 @@ export function validationCrossingWays(context) {
476476
if (allowsTunnel(selectedFeatureType) && !skipTunnelFix) {
477477
fixes.push(makeAddBridgeOrTunnelFix('add_a_tunnel', 'temaki-tunnel', 'tunnel'));
478478
}
479+
480+
// special case: if
481+
// (1) we're about to join these lines with a highway=crossing node; and
482+
// (2) one of the lines is a sidewalk
483+
// then we will split the sidewalk and create a highway=crossing way
484+
const isSidewalk = (
485+
entities[0].tags.footway === 'sidewalk' ||
486+
entities[1].tags.footway === 'sidewalk' ||
487+
entities[0].tags.cycleway === 'sidewalk' ||
488+
entities[1].tags.cycleway === 'sidewalk'
489+
);
490+
if (connectionTags.highway === 'crossing' && isSidewalk) {
491+
const newAction = makeAddBridgeOrTunnelFix(
492+
'connect_using_crossing',
493+
'temaki-pedestrian',
494+
'crossing',
495+
connectionTags
496+
);
497+
// replace the default action with this action
498+
fixes = fixes.filter(action => action.id !== newAction.id);
499+
fixes.unshift(newAction);
500+
}
479501
}
480502

481503
// repositioning the features is always an option
@@ -498,7 +520,13 @@ export function validationCrossingWays(context) {
498520
}
499521
}
500522

501-
function makeAddBridgeOrTunnelFix(fixTitleID, iconName, bridgeOrTunnel){
523+
/**
524+
* @param {string} fixTitleID
525+
* @param {string} iconName
526+
* @param {'bridge' | 'tunnel' | 'crossing'} crossingType
527+
* @param {Tags=} connectionTags
528+
*/
529+
function makeAddBridgeOrTunnelFix(fixTitleID, iconName, crossingType, connectionTags){
502530
return new validationIssueFix({
503531
icon: iconName,
504532
title: t.append('issues.fix.' + fixTitleID + '.title'),
@@ -678,20 +706,35 @@ export function validationCrossingWays(context) {
678706
});
679707

680708
var tags = Object.assign({}, structureWay.tags); // copy tags
681-
if (bridgeOrTunnel === 'bridge'){
709+
if (crossingType === 'bridge'){
682710
tags.bridge = 'yes';
683711
tags.layer = '1';
684-
} else {
712+
} else if (crossingType === 'tunnel') {
685713
var tunnelValue = 'yes';
686714
if (getFeatureType(structureWay, graph) === 'waterway') {
687715
// use `tunnel=culvert` for waterways by default
688716
tunnelValue = 'culvert';
689717
}
690718
tags.tunnel = tunnelValue;
691719
tags.layer = '-1';
720+
} else if (crossingType === 'crossing') {
721+
// we know that the line will already have
722+
// `footway=sidewalk` or `cycleway=sidewalk`
723+
tags[tags.footway ? 'footway' : 'cycleway'] = 'crossing';
692724
}
725+
693726
// apply the structure tags to the way
694727
graph = actionChangeTags(structureWay.id, tags)(graph);
728+
729+
// for crossing, we also need to join the two lines
730+
if (crossingType === 'crossing') {
731+
const edgesToJoin = [
732+
[structEndNode1.id, structEndNode2.id],
733+
crossedEdge,
734+
];
735+
graph = actionConnectCrossingWays(crossingLoc, edgesToJoin, connectionTags)(graph);
736+
}
737+
695738
return graph;
696739
};
697740

@@ -701,6 +744,42 @@ export function validationCrossingWays(context) {
701744
});
702745
}
703746

747+
/**
748+
* @param {[number, number]} loc
749+
* @param {[string, string][]} edges
750+
* @param {Tags} connectionTags
751+
*/
752+
function actionConnectCrossingWays(loc, edges, connectionTags) {
753+
return (graph) => {
754+
// create the new node for the points
755+
var node = osmNode({ loc: loc, tags: connectionTags });
756+
graph = graph.replace(node);
757+
758+
var nodesToMerge = [node.id];
759+
var mergeThresholdInMeters = 0.75;
760+
761+
edges.forEach(function(edge) {
762+
var edgeNodes = [graph.entity(edge[0]), graph.entity(edge[1])];
763+
var nearby = geoSphericalClosestNode(edgeNodes, loc);
764+
// if there is already a suitable node nearby, use that
765+
// use the node if node has no interesting tags or if it is a crossing node #8326
766+
if ((!nearby.node.hasInterestingTags() || nearby.node.isCrossing()) && nearby.distance < mergeThresholdInMeters) {
767+
nodesToMerge.push(nearby.node.id);
768+
// else add the new node to the way
769+
} else {
770+
graph = actionAddMidpoint({loc: loc, edge: edge}, node)(graph);
771+
}
772+
});
773+
774+
if (nodesToMerge.length > 1) {
775+
// if we're using nearby nodes, merge them with the new node
776+
graph = actionMergeNodes(nodesToMerge, loc)(graph);
777+
}
778+
779+
return graph;
780+
};
781+
}
782+
704783
function makeConnectWaysFix(connectionTags) {
705784

706785
var fixTitleID = 'connect_features';
@@ -718,38 +797,8 @@ export function validationCrossingWays(context) {
718797
icon: fixIcon,
719798
title: t.append('issues.fix.' + fixTitleID + '.title'),
720799
onClick: function(context) {
721-
var loc = this.issue.loc;
722-
var edges = this.issue.data.edges;
723-
724800
context.perform(
725-
function actionConnectCrossingWays(graph) {
726-
// create the new node for the points
727-
var node = osmNode({ loc: loc, tags: connectionTags });
728-
graph = graph.replace(node);
729-
730-
var nodesToMerge = [node.id];
731-
var mergeThresholdInMeters = 0.75;
732-
733-
edges.forEach(function(edge) {
734-
var edgeNodes = [graph.entity(edge[0]), graph.entity(edge[1])];
735-
var nearby = geoSphericalClosestNode(edgeNodes, loc);
736-
// if there is already a suitable node nearby, use that
737-
// use the node if node has no interesting tags or if it is a crossing node #8326
738-
if ((!nearby.node.hasInterestingTags() || nearby.node.isCrossing()) && nearby.distance < mergeThresholdInMeters) {
739-
nodesToMerge.push(nearby.node.id);
740-
// else add the new node to the way
741-
} else {
742-
graph = actionAddMidpoint({loc: loc, edge: edge}, node)(graph);
743-
}
744-
});
745-
746-
if (nodesToMerge.length > 1) {
747-
// if we're using nearby nodes, merge them with the new node
748-
graph = actionMergeNodes(nodesToMerge, loc)(graph);
749-
}
750-
751-
return graph;
752-
},
801+
actionConnectCrossingWays(this.issue.loc, this.issue.data.edges, connectionTags),
753802
t('issues.fix.connect_crossing_features.annotation')
754803
);
755804
}

0 commit comments

Comments
 (0)