Where possible, leave a segment between structures and intersections when applying the "add a bridge/tunnel" fix (close #7202)

This commit is contained in:
Quincy Morgan
2020-01-09 11:36:19 -05:00
parent 5011039087
commit 6c30ae2664
+43 -21
View File
@@ -3,7 +3,7 @@ import { actionChangeTags } from '../actions/change_tags';
import { actionMergeNodes } from '../actions/merge_nodes';
import { actionSplit } from '../actions/split';
import { modeSelect } from '../modes/select';
import { geoAngle, geoExtent, geoLineIntersection, geoSphericalClosestNode, geoVecAngle, geoMetersToLon, geoVecLength } from '../geo';
import { geoAngle, geoExtent, geoLineIntersection, geoSphericalClosestNode, geoSphericalDistance, geoVecAngle, geoMetersToLon } from '../geo';
import { osmNode } from '../osm/node';
import { osmFlowingWaterwayTagValues, osmPathHighwayTagValues, osmRailwayTrackTagValues, osmRoutableHighwayTagValues } from '../osm/tags';
import { t } from '../util/locale';
@@ -524,35 +524,57 @@ export function validationCrossingWays(context) {
// clamp the length to a reasonable range
structLengthMeters = Math.min(Math.max(structLengthMeters, 4), 50);
// the proposed length of the structure, in decimal degrees
var structLengthDeg = geoMetersToLon(structLengthMeters, crossingLoc[1]);
var halfStructLength = structLengthDeg / 2;
var angle = geoVecAngle(edgeNodes[0].loc, edgeNodes[1].loc);
var locNewNode1 = [crossingLoc[0] + Math.cos(angle) * halfStructLength,
crossingLoc[1] + Math.sin(angle) * halfStructLength];
var locNewNode2 = [crossingLoc[0] + Math.cos(angle + Math.PI) * halfStructLength,
crossingLoc[1] + Math.sin(angle + Math.PI)* halfStructLength];
var endpointLocGetter1 = function(lengthMeters) {
var length = geoMetersToLon(lengthMeters, crossingLoc[1]);
return [crossingLoc[0] + Math.cos(angle) * length,
crossingLoc[1] + Math.sin(angle) * length];
};
var endpointLocGetter2 = function(lengthMeters) {
var length = geoMetersToLon(lengthMeters, crossingLoc[1]);
return [crossingLoc[0] + Math.cos(angle + Math.PI) * length,
crossingLoc[1] + Math.sin(angle + Math.PI) * length];
};
// avoid creating very short edges from splitting too close to another node
var minEdgeLengthMeters = 0.55;
// decide where to bound the structure along the way, splitting as necessary
function determineEndpoint(edge, endNode, proposedNodeLoc) {
function determineEndpoint(edge, endNode, locGetter) {
var newNode;
// avoid creating very short edges from splitting too close to another node
var minEdgeLength = 0.000005;
var idealLength = structLengthMeters / 2;
// distance between the crossing location and the end of the edge,
// the maximum length of this side of the structure
var crossingToEdgeEndDistance = geoSphericalDistance(crossingLoc, endNode.loc);
if (crossingToEdgeEndDistance - idealLength > minEdgeLengthMeters) {
// the edge is long enough to insert a new node
// the loc that would result in the full expected length
var idealNodeLoc = locGetter(idealLength);
// split only if edge is long
if (geoVecLength(crossingLoc, endNode.loc) - geoVecLength(crossingLoc, proposedNodeLoc) > minEdgeLength) {
// if the edge is long, insert a new node
newNode = osmNode();
graph = actionAddMidpoint({ loc: proposedNodeLoc, edge: edge }, newNode)(graph);
graph = actionAddMidpoint({ loc: idealNodeLoc, edge: edge }, newNode)(graph);
} else {
// otherwise use the edge endpoint
newNode = endNode;
} else if (endNode.isIntersection(graph)) {
// the end node is an intersection, try to leave a segment
// between it and the structure - #7202
var insetLength = crossingToEdgeEndDistance - minEdgeLengthMeters;
if (insetLength > minEdgeLengthMeters) {
var insetNodeLoc = locGetter(insetLength);
newNode = osmNode();
graph = actionAddMidpoint({ loc: insetNodeLoc, edge: edge }, newNode)(graph);
}
}
// if the edge is too short to subdivide as desired, then
// just bound the structure at the existing end node
if (!newNode) newNode = endNode;
var splitAction = actionSplit(newNode.id)
.limitWays(resultWayIDs); // only split selected or created ways
@@ -565,8 +587,8 @@ export function validationCrossingWays(context) {
return newNode;
}
var structEndNode1 = determineEndpoint(edge, edgeNodes[1], locNewNode1);
var structEndNode2 = determineEndpoint([edgeNodes[0].id, structEndNode1.id], edgeNodes[0], locNewNode2);
var structEndNode1 = determineEndpoint(edge, edgeNodes[1], endpointLocGetter1);
var structEndNode2 = determineEndpoint([edgeNodes[0].id, structEndNode1.id], edgeNodes[0], endpointLocGetter2);
var structureWay = resultWayIDs.map(function(id) {
return graph.entity(id);