From 2e5e3791c5e9d6b8217b01715bfd47baa4a98cf3 Mon Sep 17 00:00:00 2001 From: Quincy Morgan Date: Mon, 8 Jun 2020 11:58:10 -0400 Subject: [PATCH] Disable the straighten operation for selections that are already straight (close #7658) --- data/core.yaml | 3 ++ dist/locales/en.json | 4 ++ modules/actions/straighten_nodes.js | 61 ++++++++++++++++++++--------- modules/actions/straighten_way.js | 25 ++++++++++-- 4 files changed, 71 insertions(+), 22 deletions(-) diff --git a/data/core.yaml b/data/core.yaml index 16bc84950..786e4bb10 100644 --- a/data/core.yaml +++ b/data/core.yaml @@ -183,6 +183,9 @@ en: not_downloaded: single: This can't be straightened because parts of it have not yet been downloaded. multiple: These can't be straightened because parts of them have not yet been downloaded. + straight_enough: + single: This can't be made straighter than it already is. + multiple: These can't be made straighter than they already are. too_large: single: This can't be straightened because not enough of it is currently visible. multiple: These can't be straightened because not enough of them are currently visible. diff --git a/dist/locales/en.json b/dist/locales/en.json index 8dec84130..d88ed18c1 100644 --- a/dist/locales/en.json +++ b/dist/locales/en.json @@ -241,6 +241,10 @@ "single": "This can't be straightened because parts of it have not yet been downloaded.", "multiple": "These can't be straightened because parts of them have not yet been downloaded." }, + "straight_enough": { + "single": "This can't be made straighter than it already is.", + "multiple": "These can't be made straighter than they already are." + }, "too_large": { "single": "This can't be straightened because not enough of it is currently visible.", "multiple": "These can't be straightened because not enough of them are currently visible." diff --git a/modules/actions/straighten_nodes.js b/modules/actions/straighten_nodes.js index 45e4c5615..42d764123 100644 --- a/modules/actions/straighten_nodes.js +++ b/modules/actions/straighten_nodes.js @@ -8,13 +8,8 @@ export function actionStraightenNodes(nodeIDs, projection) { return geoVecDot(a, b, o) / geoVecDot(b, b, o); } - - var action = function(graph, t) { - if (t === null || !isFinite(t)) t = 1; - t = Math.min(Math.max(+t, 0), 1); - - var nodes = nodeIDs.map(function(id) { return graph.entity(id); }); - var points = nodes.map(function(n) { return projection(n.loc); }); + // returns the endpoints of the long axis of symmetry of the `points` bounding rect + function getEndpoints(points) { var ssr = geoGetSmallestSurroundingRectangle(points); // Choose line pq = axis of symmetry. @@ -24,23 +19,31 @@ export function actionStraightenNodes(nodeIDs, projection) { var q1 = [(ssr.poly[2][0] + ssr.poly[3][0]) / 2, (ssr.poly[2][1] + ssr.poly[3][1]) / 2 ]; var p2 = [(ssr.poly[3][0] + ssr.poly[4][0]) / 2, (ssr.poly[3][1] + ssr.poly[4][1]) / 2 ]; var q2 = [(ssr.poly[1][0] + ssr.poly[2][0]) / 2, (ssr.poly[1][1] + ssr.poly[2][1]) / 2 ]; - var p, q; var isLong = (geoVecLength(p1, q1) > geoVecLength(p2, q2)); if (isLong) { - p = p1; - q = q1; - } else { - p = p2; - q = q2; + return [p1, q1]; } + return [p2, q2]; + } - // Move points onto line pq + + var action = function(graph, t) { + if (t === null || !isFinite(t)) t = 1; + t = Math.min(Math.max(+t, 0), 1); + + var nodes = nodeIDs.map(function(id) { return graph.entity(id); }); + var points = nodes.map(function(n) { return projection(n.loc); }); + var endpoints = getEndpoints(points); + var startPoint = endpoints[0]; + var endPoint = endpoints[1]; + + // Move points onto the line connecting the endpoints for (var i = 0; i < points.length; i++) { var node = nodes[i]; var point = points[i]; - var u = positionAlongWay(point, p, q); - var point2 = geoVecInterp(p, q, u); + var u = positionAlongWay(point, startPoint, endPoint); + var point2 = geoVecInterp(startPoint, endPoint, u); var loc2 = projection.invert(point2); graph = graph.replace(node.move(geoVecInterp(node.loc, loc2, t))); } @@ -49,8 +52,30 @@ export function actionStraightenNodes(nodeIDs, projection) { }; - action.disabled = function() { - return false; + action.disabled = function(graph) { + + var nodes = nodeIDs.map(function(id) { return graph.entity(id); }); + var points = nodes.map(function(n) { return projection(n.loc); }); + var endpoints = getEndpoints(points); + var startPoint = endpoints[0]; + var endPoint = endpoints[1]; + + var maxDistance = 0; + + for (var i = 0; i < points.length; i++) { + var point = points[i]; + var u = positionAlongWay(point, startPoint, endPoint); + var p = geoVecInterp(startPoint, endPoint, u); + var dist = geoVecLength(p, point); + + if (!isNaN(dist) && dist > maxDistance) { + maxDistance = dist; + } + } + + if (maxDistance < 0.0001) { + return 'straight_enough'; + } }; diff --git a/modules/actions/straighten_way.js b/modules/actions/straighten_way.js index b317d8606..b13c94311 100644 --- a/modules/actions/straighten_way.js +++ b/modules/actions/straighten_way.js @@ -81,6 +81,12 @@ export function actionStraightenWay(selectedIDs, projection) { return nodes.map(function(n) { return graph.entity(n); }); } + function shouldKeepNode(node, graph) { + return graph.parentWays(node).length > 1 || + graph.parentRelations(node).length || + node.hasInterestingTags(); + } + var action = function(graph, t) { if (t === null || !isFinite(t)) t = 1; @@ -97,10 +103,7 @@ export function actionStraightenWay(selectedIDs, projection) { var node = nodes[i]; var point = points[i]; - if (t < 1 || graph.parentWays(node).length > 1 || - graph.parentRelations(node).length || - node.hasInterestingTags() - ) { + if (t < 1 || shouldKeepNode(node, graph)) { var u = positionAlongWay(point, startPoint, endPoint); var p = geoVecInterp(startPoint, endPoint, u); var loc2 = projection.invert(p); @@ -135,6 +138,8 @@ export function actionStraightenWay(selectedIDs, projection) { return 'too_bendy'; } + var maxDistance = 0; + for (i = 1; i < points.length - 1; i++) { var point = points[i]; var u = positionAlongWay(point, startPoint, endPoint); @@ -144,8 +149,20 @@ export function actionStraightenWay(selectedIDs, projection) { // to bendy if point is off by 20% of total start/end distance in projected space if (isNaN(dist) || dist > threshold) { return 'too_bendy'; + } else if (dist > maxDistance) { + maxDistance = dist; } } + + var keepingAllNodes = nodes.every(function(node, i) { + return i === 0 || i === nodes.length - 1 || shouldKeepNode(node, graph); + }); + + if (maxDistance < 0.0001 && + // Allow straightening even if already straight in order to remove extraneous nodes + keepingAllNodes) { + return 'straight_enough'; + } }; action.transitionable = true;