From f6c284a3beaf910302cff6f63ab6ec92bc0bfeff Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Fri, 22 Mar 2019 15:28:13 -0400 Subject: [PATCH] Minor code cleanups, swap some math for existing functions --- modules/actions/straighten.js | 122 ++++++++++++++----------------- modules/operations/straighten.js | 36 +++++---- 2 files changed, 71 insertions(+), 87 deletions(-) diff --git a/modules/actions/straighten.js b/modules/actions/straighten.js index 6207b316b..506f032a9 100644 --- a/modules/actions/straighten.js +++ b/modules/actions/straighten.js @@ -1,11 +1,7 @@ -import { actionDeleteNode } from './delete_node'; import _difference from 'lodash-es/difference'; -import _filter from 'lodash-es/filter'; -import { - geoVecInterp, - geoVecLength -} from '../geo'; +import { actionDeleteNode } from './delete_node'; +import { geoVecDot, geoVecInterp, geoVecLength } from '../geo'; /* @@ -13,50 +9,49 @@ import { */ export function actionStraighten(selectedIDs, projection) { - function positionAlongWay(n, s, e) { - return ((n[0] - s[0]) * (e[0] - s[0]) + (n[1] - s[1]) * (e[1] - s[1])) / - (Math.pow(e[0] - s[0], 2) + Math.pow(e[1] - s[1], 2)); + function positionAlongWay(a, o, b) { + return geoVecDot(a, b, o) / geoVecDot(b, b, o); } // Return all selected ways as a continuous, ordered array of nodes function allNodes(graph) { - var nodes = [], - startNodes = [], - endNodes = [], - remainingWays = [], - selectedWays = selectedIDs.filter(function(w) { - return graph.entity(w).type === 'way'; - }), - selectedNodes = selectedIDs.filter(function(n) { - return graph.entity(n).type === 'node'; - }); + var nodes = []; + var startNodes = []; + var endNodes = []; + var remainingWays = []; + var selectedWays = selectedIDs.filter(function(w) { + return graph.entity(w).type === 'way'; + }); + var selectedNodes = selectedIDs.filter(function(n) { + return graph.entity(n).type === 'node'; + }); for (var i = 0; i < selectedWays.length; i++) { var way = graph.entity(selectedWays[i]); - nodes = way.nodes.slice(0); - remainingWays.push(nodes); - startNodes.push(nodes[0]); - endNodes.push(nodes[nodes.length-1]); + nodes = way.nodes.slice(0); + remainingWays.push(nodes); + startNodes.push(nodes[0]); + endNodes.push(nodes[nodes.length-1]); } // Remove duplicate end/startNodes (duplicate nodes cannot be at the line end, - // and need to be removed so currNode _difference calculation below works) + // and need to be removed so currNode _difference calculation below works) // i.e. ["n-1", "n-1", "n-2"] => ["n-2"] - startNodes = _filter(startNodes, function(n) { + startNodes = startNodes.filter(function(n) { return startNodes.indexOf(n) === startNodes.lastIndexOf(n); }); - endNodes = _filter(endNodes, function(n) { + endNodes = endNodes.filter(function(n) { return endNodes.indexOf(n) === endNodes.lastIndexOf(n); }); // Choose the initial endpoint to start from - var currNode = _difference(startNodes, endNodes).concat(_difference(endNodes, startNodes))[0], - nextWay = []; - nodes = []; + var currNode = _difference(startNodes, endNodes).concat(_difference(endNodes, startNodes))[0]; + var nextWay = []; + nodes = []; // Create nested function outside of loop to avoid "function in loop" lint error var getNextWay = function(currNode, remainingWays) { - return _filter(remainingWays, function(way) { + return remainingWays.filter(function(way) { return way[0] === currNode || way[way.length-1] === currNode; })[0]; }; @@ -64,59 +59,51 @@ export function actionStraighten(selectedIDs, projection) { // Add nodes to end of nodes array, until all ways are added while (remainingWays.length) { nextWay = getNextWay(currNode, remainingWays); - remainingWays = _difference(remainingWays, [nextWay]); if (nextWay[0] !== currNode) { nextWay.reverse(); } nodes = nodes.concat(nextWay); - currNode = nodes[nodes.length-1]; } // If user selected 2 nodes to straighten between, then slice nodes array to those nodes if (selectedNodes.length === 2) { - var startNodeIdx = nodes.indexOf(selectedNodes[0]), - endNodeIdx = nodes.indexOf(selectedNodes[1]), - sortedStartEnd = [startNodeIdx, endNodeIdx]; + var startNodeIdx = nodes.indexOf(selectedNodes[0]); + var endNodeIdx = nodes.indexOf(selectedNodes[1]); + var sortedStartEnd = [startNodeIdx, endNodeIdx]; - sortedStartEnd.sort(function(a, b) { - return a - b; - }); - + sortedStartEnd.sort(function(a, b) { return a - b; }); nodes = nodes.slice(sortedStartEnd[0], sortedStartEnd[1]+1); } return nodes.map(function(n) { return graph.entity(n); }); } + var action = function(graph, t) { if (t === null || !isFinite(t)) t = 1; t = Math.min(Math.max(+t, 0), 1); - var nodes = allNodes(graph), - points = nodes.map(function(n) { return projection(n.loc); }), - startPoint = points[0], - endPoint = points[points.length-1], - toDelete = [], - i; + var nodes = allNodes(graph); + var points = nodes.map(function(n) { return projection(n.loc); }); + var startPoint = points[0]; + var endPoint = points[points.length-1]; + var toDelete = []; + var i; for (i = 1; i < points.length-1; i++) { - var node = nodes[i], - point = points[i]; + var node = nodes[i]; + var point = points[i]; if (t < 1 || graph.parentWays(node).length > 1 || graph.parentRelations(node).length || - node.hasInterestingTags()) { - - var u = positionAlongWay(point, startPoint, endPoint), - p = [ - startPoint[0] + u * (endPoint[0] - startPoint[0]), - startPoint[1] + u * (endPoint[1] - startPoint[1]) - ], - loc2 = projection.invert(p); - + node.hasInterestingTags() + ) { + var u = positionAlongWay(point, startPoint, endPoint); + var p = geoVecInterp(startPoint, endPoint, u); + var loc2 = projection.invert(p); graph = graph.replace(node.move(geoVecInterp(node.loc, loc2, t))); } else { @@ -137,23 +124,22 @@ export function actionStraighten(selectedIDs, projection) { action.disabled = function(graph) { // check way isn't too bendy - var nodes = allNodes(graph), - points = nodes.map(function(n) { return projection(n.loc); }), - startPoint = points[0], - endPoint = points[points.length-1], - threshold = 0.2 * geoVecLength(startPoint, endPoint), - i; + var nodes = allNodes(graph); + var points = nodes.map(function(n) { return projection(n.loc); }); + var startPoint = points[0]; + var endPoint = points[points.length-1]; + var threshold = 0.2 * geoVecLength(startPoint, endPoint); + var i; if (threshold === 0) { return 'too_bendy'; } - for (i = 1; i < points.length-1; i++) { - var point = points[i], - u = positionAlongWay(point, startPoint, endPoint), - p0 = startPoint[0] + u * (endPoint[0] - startPoint[0]), - p1 = startPoint[1] + u * (endPoint[1] - startPoint[1]), - dist = Math.sqrt(Math.pow(p0 - point[0], 2) + Math.pow(p1 - point[1], 2)); + for (i = 1; i < points.length - 1; i++) { + var point = points[i]; + var u = positionAlongWay(point, startPoint, endPoint); + var p = geoVecInterp(startPoint, endPoint, u); + var dist = geoVecLength(p, point); // to bendy if point is off by 20% of total start/end distance in projected space if (isNaN(dist) || dist > threshold) { diff --git a/modules/operations/straighten.js b/modules/operations/straighten.js index 72dc3d829..e26572096 100644 --- a/modules/operations/straighten.js +++ b/modules/operations/straighten.js @@ -1,7 +1,5 @@ import _uniq from 'lodash-es/uniq'; import _difference from 'lodash-es/difference'; -import _includes from 'lodash-es/includes'; -import _filter from 'lodash-es/filter'; import { t } from '../util/locale'; import { actionStraighten } from '../actions/index'; @@ -18,24 +16,21 @@ export function operationStraighten(selectedIDs, context) { operation.available = function() { - var nodes = [], - startNodes = [], - endNodes = [], - selectedNodes = []; + var nodes = []; + var startNodes = []; + var endNodes = []; + var selectedNodes = []; + // collect nodes along selected ways for (var i = 0; i < selectedIDs.length; i++) { if (!context.hasEntity(selectedIDs[i])) return false; var entity = context.entity(selectedIDs[i]); - if (entity.type === 'node') { selectedNodes.push(entity.id); continue; - } - - if (entity.type !== 'way' || - entity.isClosed()) { - return false; + } else if (entity.type !== 'way' || entity.isClosed()) { + return false; // exit early, can't straighten these } nodes = nodes.concat(entity.nodes); @@ -44,23 +39,26 @@ export function operationStraighten(selectedIDs, context) { } // Remove duplicate end/startNodes (duplicate nodes cannot be at the line end) - startNodes = _filter(startNodes, function(n) { + startNodes = startNodes.filter(function(n) { return startNodes.indexOf(n) === startNodes.lastIndexOf(n); }); - endNodes = _filter(endNodes, function(n) { + endNodes = endNodes.filter(function(n) { return endNodes.indexOf(n) === endNodes.lastIndexOf(n); }); // Return false if line is only 2 nodes long - // Return false unless exactly 0 or 2 specific nodes are selected - if (_uniq(nodes).length <= 2 || !_includes([0,2], selectedNodes.length)) return false; + if (_uniq(nodes).length <= 2) return false; + + // Return false unless exactly 0 or 2 specific start/end nodes are selected + if (!(selectedNodes.length === 0 || selectedNodes.length === 2)) return false; // Ensure all ways are connected (i.e. only 2 unique endpoints/startpoints) if (_difference(startNodes, endNodes).length + _difference(endNodes, startNodes).length !== 2) return false; - // Ensure both selected nodes lie on the selected path - if (selectedNodes.length && (!_includes(nodes, selectedNodes[0]) || - !_includes(nodes, selectedNodes[1]))) return false; + // Ensure both start/end selected nodes lie on the selected path + if (selectedNodes.length === 2 && ( + nodes.indexOf(selectedNodes[0]) === -1 || nodes.indexOf(selectedNodes[1]) === -1 + )) return false; return true; };