Add method Polyline.closestLayerPoint
Also fix method L.LineUtil.simplify for empty geometry
This commit is contained in:
parent
cf83c2e146
commit
263a5b9b5f
@ -41,6 +41,7 @@
|
||||
|
||||
<!-- /layer -->
|
||||
<script type="text/javascript" src="suites/layer/TileLayerSpec.js"></script>
|
||||
<script type="text/javascript" src="suites/layer/vector/PolylineGeometrySpec.js"></script>
|
||||
|
||||
<!-- /map -->
|
||||
<script type="text/javascript" src="suites/map/MapSpec.js"></script>
|
||||
|
@ -3,3 +3,26 @@ function noSpecs() {
|
||||
expect('specs').toBe();
|
||||
});
|
||||
}
|
||||
|
||||
if (!Array.prototype.map) {
|
||||
Array.prototype.map = function(fun /*, thisp */) {
|
||||
"use strict";
|
||||
|
||||
if (this === void 0 || this === null)
|
||||
throw new TypeError();
|
||||
|
||||
var t = Object(this);
|
||||
var len = t.length >>> 0;
|
||||
if (typeof fun !== "function")
|
||||
throw new TypeError();
|
||||
|
||||
var res = new Array(len);
|
||||
var thisp = arguments[1];
|
||||
for (var i = 0; i < len; i++) {
|
||||
if (i in t)
|
||||
res[i] = fun.call(thisp, t[i], i, t);
|
||||
}
|
||||
|
||||
return res;
|
||||
};
|
||||
}
|
35
spec/suites/layer/vector/PolylineGeometrySpec.js
Normal file
35
spec/suites/layer/vector/PolylineGeometrySpec.js
Normal file
@ -0,0 +1,35 @@
|
||||
describe('PolylineGeometry', function() {
|
||||
|
||||
var c = document.createElement('div');
|
||||
c.style.width = '400px';
|
||||
c.style.height = '400px';
|
||||
var map = new L.Map(c);
|
||||
map.setView(new L.LatLng(55.8, 37.6), 6);
|
||||
|
||||
describe("#distanceTo", function() {
|
||||
it("should calculate correct distances to points", function() {
|
||||
var p1 = map.latLngToLayerPoint(new L.LatLng(55.8, 37.6));
|
||||
var p2 = map.latLngToLayerPoint(new L.LatLng(57.123076977278, 44.861962891635));
|
||||
var latlngs = [[56.485503424111, 35.545556640339], [55.972522915346, 36.116845702918], [55.502459116923, 34.930322265253], [55.31534617509, 38.973291015816]]
|
||||
.map(function(ll) {
|
||||
return new L.LatLng(ll[0], ll[1]);
|
||||
});
|
||||
var polyline = new L.Polyline([], {
|
||||
'noClip': true
|
||||
});
|
||||
map.addLayer(polyline);
|
||||
|
||||
expect(polyline.closestLayerPoint(p1)).toEqual(null);
|
||||
|
||||
polyline.setLatLngs(latlngs);
|
||||
var point = polyline.closestLayerPoint(p1);
|
||||
expect(point).not.toEqual(null);
|
||||
expect(point.distance).not.toEqual(Infinity);
|
||||
expect(point.distance).not.toEqual(NaN);
|
||||
|
||||
var point2 = polyline.closestLayerPoint(p2);
|
||||
|
||||
expect(point.distance).toBeLessThan(point2.distance);
|
||||
});
|
||||
});
|
||||
});
|
@ -9,7 +9,7 @@ L.LineUtil = {
|
||||
* Improves rendering performance dramatically by lessening the number of points to draw.
|
||||
*/
|
||||
simplify: function(/*Point[]*/ points, /*Number*/ tolerance) {
|
||||
if (!tolerance) return points.slice();
|
||||
if (!tolerance || !points.length) return points.slice();
|
||||
|
||||
// stage 1: vertex reduction
|
||||
points = this.reducePoints(points, tolerance);
|
||||
@ -25,6 +25,12 @@ L.LineUtil = {
|
||||
return Math.sqrt(this._sqPointToSegmentDist(p, p1, p2));
|
||||
},
|
||||
|
||||
closestPointOnSegment: function(/*Point*/ p, /*Point*/ p1, /*Point*/ p2) {
|
||||
var point = this._sqClosestPointOnSegment(p, p1, p2);
|
||||
point.distance = Math.sqrt(point._sqDist);
|
||||
return point;
|
||||
},
|
||||
|
||||
// Douglas-Peucker simplification, see http://en.wikipedia.org/wiki/Douglas-Peucker_algorithm
|
||||
simplifyDP: function(points, tol) {
|
||||
var maxDist2 = 0,
|
||||
@ -140,8 +146,10 @@ L.LineUtil = {
|
||||
return dx * dx + dy * dy;
|
||||
},
|
||||
|
||||
// square distance from point to a segment
|
||||
_sqPointToSegmentDist: function(p, p1, p2) {
|
||||
/**
|
||||
* @return L.Point point on segment with attribute _sqDist - square distance to segment
|
||||
*/
|
||||
_sqClosestPointOnSegment: function(p, p1, p2) {
|
||||
var x2 = p2.x - p1.x,
|
||||
y2 = p2.y - p1.y;
|
||||
|
||||
@ -150,10 +158,18 @@ L.LineUtil = {
|
||||
var dot = (p.x - p1.x) * x2 + (p.y - p1.y) * y2,
|
||||
t = dot / this._sqDist(p1, p2);
|
||||
|
||||
if (t < 0) return this._sqDist(p, p1);
|
||||
if (t > 1) return this._sqDist(p, p2);
|
||||
var apoint = p1;
|
||||
if (t > 1) {
|
||||
apoint = p2;
|
||||
} else if (t > 0) {
|
||||
apoint = new L.Point(p1.x + x2 * t, p1.y + y2 * t);
|
||||
}
|
||||
apoint._sqDist = this._sqDist(p, apoint);
|
||||
return apoint;
|
||||
},
|
||||
|
||||
var proj = new L.Point(p1.x + x2 * t, p1.y + y2 * t);
|
||||
return this._sqDist(p, proj);
|
||||
// distance from a point to a segment between two points
|
||||
_sqPointToSegmentDist: function(p, p1, p2) {
|
||||
return this._sqClosestPointOnSegment(p, p1, p2)._sqDist;
|
||||
}
|
||||
};
|
@ -51,6 +51,25 @@ L.Polyline = L.Path.extend({
|
||||
return removed;
|
||||
},
|
||||
|
||||
closestLayerPoint: function(p) {
|
||||
var minDistance = Infinity, parts = this._parts, p1, p2, minPoint = null;
|
||||
|
||||
for (var j = 0, jLen = parts.length; j < jLen; j++) {
|
||||
var points = parts[j];
|
||||
for (var i = 1, len = points.length; i < len; i++) {
|
||||
p1 = points[i-1];
|
||||
p2 = points[i];
|
||||
var point = L.LineUtil._sqClosestPointOnSegment(p, p1, p2);
|
||||
if (point._sqDist < minDistance) {
|
||||
minDistance = point._sqDist;
|
||||
minPoint = point;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (minPoint) minPoint.distance = Math.sqrt(minDistance);
|
||||
return minPoint;
|
||||
},
|
||||
|
||||
_getPathPartStr: function(points) {
|
||||
var round = L.Path.VML;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user