Linearly interpolate extra dimensions in ol.geom.flat.closestPoint

This commit is contained in:
Tom Payne
2014-01-20 09:24:41 +01:00
parent 5bee477734
commit 6f0f42040c
3 changed files with 72 additions and 30 deletions

View File

@@ -95,14 +95,16 @@ ol.geom.closest.getClosestPoint = function(flatCoordinates, offset, end, stride,
if (offset == end) {
return minSquaredDistance;
}
var squaredDistance;
var i, squaredDistance;
if (maxDelta === 0) {
// All points are identical, so just test the first point.
squaredDistance = ol.geom.flat.squaredDistance(
x, y, flatCoordinates[offset], flatCoordinates[offset + 1]);
if (squaredDistance < minSquaredDistance) {
closestPoint[0] = flatCoordinates[offset];
closestPoint[1] = flatCoordinates[offset + 1];
for (i = 0; i < stride; ++i) {
closestPoint[i] = flatCoordinates[offset + i];
}
closestPoint.length = stride;
return squaredDistance;
} else {
return minSquaredDistance;
@@ -112,15 +114,16 @@ ol.geom.closest.getClosestPoint = function(flatCoordinates, offset, end, stride,
var tmpPoint = goog.isDef(opt_tmpPoint) ? opt_tmpPoint : [NaN, NaN];
var index = offset + stride;
while (index < end) {
ol.geom.flat.closestPoint(x, y,
flatCoordinates[index - stride], flatCoordinates[index - stride + 1],
flatCoordinates[index], flatCoordinates[index + 1], tmpPoint);
ol.geom.flat.closestPoint(
flatCoordinates, index - stride, index, stride, x, y, tmpPoint);
squaredDistance = ol.geom.flat.squaredDistance(
x, y, tmpPoint[0], tmpPoint[1]);
if (squaredDistance < minSquaredDistance) {
minSquaredDistance = squaredDistance;
closestPoint[0] = tmpPoint[0];
closestPoint[1] = tmpPoint[1];
for (i = 0; i < stride; ++i) {
closestPoint[i] = tmpPoint[i];
}
closestPoint.length = stride;
index += stride;
} else {
// Skip ahead multiple points, because we know that all the skipped
@@ -140,15 +143,16 @@ ol.geom.closest.getClosestPoint = function(flatCoordinates, offset, end, stride,
}
if (isRing) {
// Check the closing segment.
ol.geom.flat.closestPoint(x, y,
flatCoordinates[end - stride], flatCoordinates[end - stride + 1],
flatCoordinates[offset], flatCoordinates[offset + 1], tmpPoint);
ol.geom.flat.closestPoint(
flatCoordinates, end - stride, offset, stride, x, y, tmpPoint);
squaredDistance = ol.geom.flat.squaredDistance(
x, y, tmpPoint[0], tmpPoint[1]);
if (squaredDistance < minSquaredDistance) {
minSquaredDistance = squaredDistance;
closestPoint[0] = tmpPoint[0];
closestPoint[1] = tmpPoint[1];
for (i = 0; i < stride; ++i) {
closestPoint[i] = tmpPoint[i];
}
closestPoint.length = stride;
}
}
return minSquaredDistance;

View File

@@ -2,39 +2,50 @@ goog.provide('ol.geom.flat');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.math');
goog.require('goog.vec.Mat4');
/**
* Returns the point on the line segment (x1, y1) to (x2, y2) that is closest to
* the point (x, y).
* Returns the point on the 2D line segment flatCoordinates[offset1] to
* flatCoordinates[offset2] that is closest to the point (x, y). Extra
* dimensions are linearly interpolated.
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset1 Offset 1.
* @param {number} offset2 Offset 2.
* @param {number} stride Stride.
* @param {number} x X.
* @param {number} y Y.
* @param {number} x1 X1.
* @param {number} y1 Y1.
* @param {number} x2 X2.
* @param {number} y2 Y2.
* @param {Array.<number>} closestPoint Closest point.
*/
ol.geom.flat.closestPoint = function(x, y, x1, y1, x2, y2, closestPoint) {
var dx = x2 - x1;
var dy = y2 - y1;
ol.geom.flat.closestPoint =
function(flatCoordinates, offset1, offset2, stride, x, y, closestPoint) {
var x1 = flatCoordinates[offset1];
var y1 = flatCoordinates[offset1 + 1];
var dx = flatCoordinates[offset2] - x1;
var dy = flatCoordinates[offset2 + 1] - y1;
var i, offset;
if (dx === 0 && dy === 0) {
closestPoint[0] = x1;
closestPoint[1] = y1;
offset = offset1;
} else {
var t = ((x - x1) * dx + (y - y1) * dy) / (dx * dx + dy * dy);
if (t > 1) {
closestPoint[0] = x2;
closestPoint[1] = y2;
offset = offset2;
} else if (t > 0) {
closestPoint[0] = x1 + dx * t;
closestPoint[1] = y1 + dy * t;
for (i = 0; i < stride; ++i) {
closestPoint[i] = goog.math.lerp(flatCoordinates[offset1 + i],
flatCoordinates[offset2 + i], t);
}
closestPoint.length = stride;
return;
} else {
closestPoint[0] = x1;
closestPoint[1] = y1;
offset = offset1;
}
}
for (i = 0; i < stride; ++i) {
closestPoint[i] = flatCoordinates[offset + i];
}
closestPoint.length = stride;
};

View File

@@ -113,6 +113,33 @@ describe('ol.geom.closest', function() {
});
describe('with multi-dimensional data', function() {
var flatCoordinates = [0, 0, 10, -10, 2, 2, 30, -20];
var stride = 4;
describe('ol.geom.closest.getClosestPoint', function() {
it('interpolates M coordinates', function() {
var maxDelta = Math.sqrt(ol.geom.closest.getMaxSquaredDelta(
flatCoordinates, 0, flatCoordinates.length, stride, 0));
expect(maxDelta).to.roughlyEqual(Math.sqrt(8), 1e-9);
var closestPoint = [NaN, NaN];
expect(ol.geom.closest.getClosestPoint(
flatCoordinates, 0, flatCoordinates.length, stride,
maxDelta, false, 1, 1, closestPoint, Infinity)).
to.roughlyEqual(0, 1e-9);
expect(closestPoint).to.have.length(stride);
expect(closestPoint[0]).to.be(1);
expect(closestPoint[1]).to.be(1);
expect(closestPoint[2]).to.be(20);
expect(closestPoint[3]).to.be(-15);
});
});
});
});