diff --git a/src/ol/coordinate.js b/src/ol/coordinate.js index 85f0b5318e..a0eebcde74 100644 --- a/src/ol/coordinate.js +++ b/src/ol/coordinate.js @@ -42,6 +42,45 @@ ol.coordinate.add = function(coordinate, delta) { }; +/** + * Calculates the point closest to the passed coordinate on the passed segment. + * This is the foot of the perpendicular of the coordinate to the segment when + * the foot is on the segment, or the closest segment coordinate when the foot + * is outside the segment. + * + * @param {ol.Coordinate} coordinate The coordinate. + * @param {Array.} segment The two coordinates of the segment. + * @return {ol.Coordinate} The foot of the perpendicular of the coordinate to + * the segment. + */ +ol.coordinate.closestOnSegment = function(coordinate, segment) { + var x0 = coordinate[0]; + var y0 = coordinate[1]; + var start = segment[0]; + var end = segment[1]; + var x1 = start[0]; + var y1 = start[1]; + var x2 = end[0]; + var y2 = end[1]; + var dx = x2 - x1; + var dy = y2 - y1; + var along = (dx == 0 && dy == 0) ? 0 : + ((dx * (x0 - x1)) + (dy * (y0 - y1))) / ((dx * dx + dy * dy) || 0); + var x, y; + if (along <= 0) { + x = x1; + y = y1; + } else if (along >= 1) { + x = x2; + y = y2; + } else { + x = x1 + along * dx; + y = y1 + along * dy; + } + return [x, y]; +}; + + /** * @param {number=} opt_fractionDigits The number of digits to include * after the decimal point. Default is `0`. @@ -136,6 +175,19 @@ ol.coordinate.squaredDistance = function(coord1, coord2) { }; +/** + * Calculate the squared distance from a coordinate to a line segment. + * + * @param {ol.Coordinate} coordinate Coordinate of the point. + * @param {Array.} segment Line segment (2 coordinates). + * @return {number} Squared distance from the point to the line segment. + */ +ol.coordinate.squaredDistanceToSegment = function(coordinate, segment) { + return ol.coordinate.squaredDistance(coordinate, + ol.coordinate.closestOnSegment(coordinate, segment)); +}; + + /** * @param {ol.Coordinate|undefined} coordinate Coordinate. * @return {string} Hemisphere, degrees, minutes and seconds. diff --git a/src/ol/geom/base.js b/src/ol/geom/base.js deleted file mode 100644 index 9950aab807..0000000000 --- a/src/ol/geom/base.js +++ /dev/null @@ -1,31 +0,0 @@ -goog.provide('ol.geom'); - -goog.require('ol.coordinate'); - - -/** - * Calculate the squared distance from a point to a line segment. - * - * @param {ol.Coordinate} coordinate Coordinate of the point. - * @param {Array.} segment Line segment (2 coordinates). - * @return {number} Squared distance from the point to the line segment. - */ -ol.geom.squaredDistanceToSegment = function(coordinate, segment) { - // http://de.softuses.com/103478, Kommentar #1 - var v = segment[0]; - var w = segment[1]; - var l2 = ol.coordinate.squaredDistance(v, w); - if (l2 === 0) { - return ol.coordinate.squaredDistance(coordinate, v); - } - var t = ((coordinate[0] - v[0]) * (w[0] - v[0]) + - (coordinate[1] - v[1]) * (w[1] - v[1])) / l2; - if (t < 0) { - return ol.coordinate.squaredDistance(coordinate, v); - } - if (t > 1) { - return ol.coordinate.squaredDistance(coordinate, w); - } - return ol.coordinate.squaredDistance(coordinate, - [v[0] + t * (w[0] - v[0]), v[1] + t * (w[1] - v[1])]); -}; diff --git a/src/ol/geom/linestring.js b/src/ol/geom/linestring.js index 11b2fd3e05..e7ed07843b 100644 --- a/src/ol/geom/linestring.js +++ b/src/ol/geom/linestring.js @@ -3,8 +3,8 @@ goog.provide('ol.geom.LineString'); goog.require('goog.asserts'); goog.require('goog.events.EventType'); goog.require('ol.CoordinateArray'); +goog.require('ol.coordinate'); goog.require('ol.extent'); -goog.require('ol.geom'); goog.require('ol.geom.Geometry'); goog.require('ol.geom.GeometryEvent'); goog.require('ol.geom.GeometryType'); @@ -104,7 +104,7 @@ ol.geom.LineString.prototype.distanceFromCoordinate = function(coordinate) { var coordinates = this.getCoordinates(); var dist2 = Infinity; for (var i = 0, j = 1, len = coordinates.length; j < len; i = j++) { - dist2 = Math.min(dist2, ol.geom.squaredDistanceToSegment(coordinate, + dist2 = Math.min(dist2, ol.coordinate.squaredDistanceToSegment(coordinate, [coordinates[i], coordinates[j]])); } return Math.sqrt(dist2); diff --git a/test/spec/ol/coordinate.test.js b/test/spec/ol/coordinate.test.js new file mode 100644 index 0000000000..baee06d42d --- /dev/null +++ b/test/spec/ol/coordinate.test.js @@ -0,0 +1,42 @@ +goog.provide('ol.test.coordinate'); + +describe.only('ol.coordinate', function() { + + describe('#closestOnSegment', function() { + it('can handle points where the foot of the perpendicular is closest', + function() { + var point = [2, 5]; + var segment = [[-5, 0], [10, 0]]; + expect(ol.coordinate.closestOnSegment(point, segment)) + .to.eql([2, 0]); + }); + it('can handle points where the foot of the perpendicular is not closest', + function() { + var point = [0, -6]; + var segment = [[-5, 0], [0, -1]]; + expect(ol.coordinate.closestOnSegment(point, segment)) + .to.eql([0, -1]); + }); + }); + + describe('#squaredDistanceToSegment', function() { + it('can handle points where the foot of the perpendicular is closest', + function() { + var point = [2, 5]; + var segment = [[-5, 0], [10, 0]]; + expect(ol.coordinate.squaredDistanceToSegment(point, segment)) + .to.eql(25); + }); + it('can handle points where the foot of the perpendicular is not closest', + function() { + var point = [0, -6]; + var segment = [[-5, 0], [0, -1]]; + expect(ol.coordinate.squaredDistanceToSegment(point, segment)) + .to.eql(25); + }); + + }); + +}); + +goog.require('ol.coordinate');