From d82d5dc3d04b5f407118444a22afc38437291add Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Thu, 21 Dec 2017 14:54:15 -0500 Subject: [PATCH] Add skipID to geoChooseEdge, to ignore dragging node --- modules/geo/geo.js | 15 +++++---- test/spec/geo/geo.js | 77 +++++++++++++++++++++++++++++++++++++------- 2 files changed, 74 insertions(+), 18 deletions(-) diff --git a/modules/geo/geo.js b/modules/geo/geo.js index e96bc81b9..318283931 100644 --- a/modules/geo/geo.js +++ b/modules/geo/geo.js @@ -157,14 +157,17 @@ export function geoRotate(points, angle, around) { // projection onto that edge, if such a projection exists, or the distance to // the closest vertex on that edge. Returns an object with the `index` of the // chosen edge, the chosen `loc` on that edge, and the `distance` to to it. -export function geoChooseEdge(nodes, point, projection) { +export function geoChooseEdge(nodes, point, projection, skipID) { var dist = geoEuclideanDistance; var points = nodes.map(function(n) { return projection(n.loc); }); + var ids = nodes.map(function(n) { return n.id; }); var min = Infinity; var idx; var loc; for (var i = 0; i < points.length - 1; i++) { + if (ids[i] === skipID || ids[i + 1] === skipID) continue; + var o = points[i]; var s = geoVecSubtract(points[i + 1], o); var v = geoVecSubtract(point, o); @@ -187,11 +190,11 @@ export function geoChooseEdge(nodes, point, projection) { } } - return { - index: idx, - distance: min, - loc: loc - }; + if (idx !== undefined) { + return { index: idx, distance: min, loc: loc }; + } else { + return null; + } } diff --git a/test/spec/geo/geo.js b/test/spec/geo/geo.js index 989c55714..c9762e051 100644 --- a/test/spec/geo/geo.js +++ b/test/spec/geo/geo.js @@ -291,20 +291,12 @@ describe('iD.geo', function() { var projection = function (l) { return l; }; projection.invert = projection; - it('returns undefined properties for a degenerate way (no nodes)', function() { - expect(iD.geoChooseEdge([], [0, 0], projection)).to.eql({ - index: undefined, - distance: Infinity, - loc: undefined - }); + it('returns null for a degenerate way (no nodes)', function() { + expect(iD.geoChooseEdge([], [0, 0], projection)).to.be.null; }); - it('returns undefined properties for a degenerate way (single node)', function() { - expect(iD.geoChooseEdge([iD.osmNode({loc: [0, 0]})], [0, 0], projection)).to.eql({ - index: undefined, - distance: Infinity, - loc: undefined - }); + it('returns null for a degenerate way (single node)', function() { + expect(iD.geoChooseEdge([iD.osmNode({loc: [0, 0]})], [0, 0], projection)).to.be.null; }); it('calculates the orthogonal projection of a point onto a segment', function() { @@ -344,6 +336,67 @@ describe('iD.geo', function() { expect(choice.distance).to.eql(5); expect(choice.loc).to.eql([5, 0]); }); + + it('skips the given nodeID at end of way', function() { + // + // a --*-- b + // e | + // | | + // d - c + // + // * = [2, 0] + var a = [0, 0]; + var b = [5, 0]; + var c = [5, 5]; + var d = [2, 5]; + var e = [2, 0.1]; // e.g. user is dragging e onto ab + var nodes = [ + iD.osmNode({id: 'a', loc: a}), + iD.osmNode({id: 'b', loc: b}), + iD.osmNode({id: 'c', loc: c}), + iD.osmNode({id: 'd', loc: d}), + iD.osmNode({id: 'e', loc: e}) + ]; + var choice = iD.geoChooseEdge(nodes, e, projection, 'e'); + expect(choice.index).to.eql(1); + expect(choice.distance).to.eql(0.1); + expect(choice.loc).to.eql([2, 0]); + }); + + it('skips the given nodeID in middle of way', function() { + // + // a --*-- b + // d | + // / \ | + // e c + // + // * = [2, 0] + var a = [0, 0]; + var b = [5, 0]; + var c = [5, 5]; + var d = [2, 0.1]; // e.g. user is dragging d onto ab + var e = [0, 5]; + var nodes = [ + iD.osmNode({id: 'a', loc: a}), + iD.osmNode({id: 'b', loc: b}), + iD.osmNode({id: 'c', loc: c}), + iD.osmNode({id: 'd', loc: d}), + iD.osmNode({id: 'e', loc: e}) + ]; + var choice = iD.geoChooseEdge(nodes, d, projection, 'd'); + expect(choice.index).to.eql(1); + expect(choice.distance).to.eql(0.1); + expect(choice.loc).to.eql([2, 0]); + }); + + it('returns null if all nodes are skipped', function() { + var nodes = [ + iD.osmNode({id: 'a', loc: [0, 0]}), + iD.osmNode({id: 'b', loc: [5, 0]}), + ]; + var choice = iD.geoChooseEdge(nodes, [2, 2], projection, 'a'); + expect(choice).to.be.null; + }); }); describe('geoLineIntersection', function() {