Add initial ol.geom.simplify

This commit is contained in:
Tom Payne
2013-12-05 14:13:47 +01:00
parent 94393c0050
commit ec03be94d6
2 changed files with 512 additions and 0 deletions

219
src/ol/geom/simplifygeom.js Normal file
View File

@@ -0,0 +1,219 @@
// Based on simplify-js https://github.com/mourner/simplify-js
// Copyright (c) 2012, Vladimir Agafonkin
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
goog.provide('ol.geom.simplify');
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {number} end End.
* @param {number} stride Stride.
* @param {number} squaredTolerance Squared tolerance.
* @param {boolean} highQuality Highest quality.
* @param {Array.<number>=} opt_simplifiedFlatCoordinates Simplified flat
* coordinates.
* @return {Array.<number>} Simplified line string.
*/
ol.geom.simplify.lineString = function(flatCoordinates, offset, end, stride,
squaredTolerance, highQuality, opt_simplifiedFlatCoordinates) {
var simplifiedFlatCoordinates = goog.isDef(opt_simplifiedFlatCoordinates) ?
opt_simplifiedFlatCoordinates : [];
if (!highQuality) {
end = ol.geom.simplify.radialDistance(flatCoordinates, offset, end,
stride, squaredTolerance,
simplifiedFlatCoordinates, 0);
flatCoordinates = simplifiedFlatCoordinates;
offset = 0;
stride = 2;
}
simplifiedFlatCoordinates.length = ol.geom.simplify.douglasPeucker(
flatCoordinates, offset, end, stride, squaredTolerance,
simplifiedFlatCoordinates, 0);
return simplifiedFlatCoordinates;
};
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {number} end End.
* @param {number} stride Stride.
* @param {number} squaredTolerance Squared tolerance.
* @param {Array.<number>} simplifiedFlatCoordinates Simplified flat
* coordinates.
* @param {number} simplifiedOffset Simplified offset.
* @return {number} Simplified offset.
*/
ol.geom.simplify.douglasPeucker = function(flatCoordinates, offset, end,
stride, squaredTolerance, simplifiedFlatCoordinates, simplifiedOffset) {
var n = (end - offset) / stride;
if (n < 3) {
for (; offset < end; offset += stride) {
simplifiedFlatCoordinates[simplifiedOffset++] =
flatCoordinates[offset];
simplifiedFlatCoordinates[simplifiedOffset++] =
flatCoordinates[offset + 1];
}
return simplifiedOffset;
}
var MarkerArray = goog.global['Uint8Array'] ? Uint8Array : Array;
var markers = new MarkerArray(n);
markers[0] = 1;
markers[n - 1] = 1;
var stack = [offset, end - stride];
var index = 0;
var i;
while (stack.length > 0) {
var last = stack.pop();
var first = stack.pop();
var maxSquaredDistance = 0;
var x1 = flatCoordinates[first];
var y1 = flatCoordinates[first + 1];
var x2 = flatCoordinates[last];
var y2 = flatCoordinates[last + 1];
for (i = first + stride; i < last; i += stride) {
var x = flatCoordinates[i];
var y = flatCoordinates[i + 1];
var squaredDistance =
ol.geom.simplify.squaredSegmentDistance(x, y, x1, y1, x2, y2);
if (squaredDistance > maxSquaredDistance) {
index = i;
maxSquaredDistance = squaredDistance;
}
}
if (maxSquaredDistance > squaredTolerance) {
markers[(index - offset) / stride] = 1;
if (first + stride < index) {
stack.push(first, index);
}
if (index + stride < last) {
stack.push(index, last);
}
}
}
for (i = 0; i < n; ++i) {
if (markers[i]) {
simplifiedFlatCoordinates[simplifiedOffset++] =
flatCoordinates[offset + i * stride];
simplifiedFlatCoordinates[simplifiedOffset++] =
flatCoordinates[offset + i * stride + 1];
}
}
return simplifiedOffset;
};
/**
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {number} end End.
* @param {number} stride Stride.
* @param {number} squaredTolerance Squared tolerance.
* @param {Array.<number>} simplifiedFlatCoordinates Simplified flat
* coordinates.
* @param {number} simplifiedOffset Simplified offset.
* @return {number} Simplified offset.
*/
ol.geom.simplify.radialDistance = function(flatCoordinates, offset, end,
stride, squaredTolerance, simplifiedFlatCoordinates, simplifiedOffset) {
if (end <= offset + stride) {
// zero or one point, no simplification possible, so copy and return
for (; offset < end; offset += stride) {
simplifiedFlatCoordinates[simplifiedOffset++] = flatCoordinates[offset];
simplifiedFlatCoordinates[simplifiedOffset++] =
flatCoordinates[offset + 1];
}
return simplifiedOffset;
}
var x1 = flatCoordinates[offset];
var y1 = flatCoordinates[offset + 1];
// copy first point
simplifiedFlatCoordinates[simplifiedOffset++] = x1;
simplifiedFlatCoordinates[simplifiedOffset++] = y1;
var x2 = x1;
var y2 = y1;
for (offset += stride; offset < end; offset += stride) {
x2 = flatCoordinates[offset];
y2 = flatCoordinates[offset + 1];
if (ol.geom.simplify.squaredDistance(x1, y1, x2, y2) > squaredTolerance) {
// copy point at offset
simplifiedFlatCoordinates[simplifiedOffset++] = x2;
simplifiedFlatCoordinates[simplifiedOffset++] = y2;
x1 = x2;
y1 = y2;
}
}
if (x2 != x1 || y2 != y1) {
// copy last point
simplifiedFlatCoordinates[simplifiedOffset++] = x2;
simplifiedFlatCoordinates[simplifiedOffset++] = y2;
}
return simplifiedOffset;
};
/**
* Returns the square of the distance between the points (x1, y1) and (x2, y2).
* @param {number} x1 X1.
* @param {number} y1 Y1.
* @param {number} x2 X2.
* @param {number} y2 Y2.
* @return {number} Squared distance.
*/
ol.geom.simplify.squaredDistance = function(x1, y1, x2, y2) {
var dx = x2 - x1;
var dy = y2 - y1;
return dx * dx + dy * dy;
};
/**
* Returns the square of the closest distance between the point (x, y) and the
* line segment (x1, y1) to (x2, y2).
* @param {number} x X.
* @param {number} y Y.
* @param {number} x1 X1.
* @param {number} y1 Y1.
* @param {number} x2 X2.
* @param {number} y2 Y2.
* @return {number} Squared distance.
*/
ol.geom.simplify.squaredSegmentDistance = function(x, y, x1, y1, x2, y2) {
var dx = x2 - x1;
var dy = y2 - y1;
if (dx !== 0 || dy !== 0) {
var t = ((x - x1) * dx + (y - y1) * dy) / (dx * dx + dy * dy);
if (t > 1) {
x1 = x2;
y1 = y2;
} else if (t > 0) {
x1 += dx * t;
y1 += dy * t;
}
}
return ol.geom.simplify.squaredDistance(x, y, x1, y1);
};