ol-ext
Version:
A set of cool extensions for OpenLayers (ol) in node modules structure
185 lines (164 loc) • 5.56 kB
JavaScript
import ol_geom_LineString from 'ol/geom/LineString.js'
import { ol_coordinate_equal } from './GeomUtils';
(function () {
/**
* Visvalingam polyline simplification algorithm, adapted from http://bost.ocks.org/mike/simplify/simplify.js
* This uses the [Visvalingam–Whyatt](https://en.wikipedia.org/wiki/Visvalingam%E2%80%93Whyatt_algorithm) algorithm.
* @param {Object} options
* @param {number} [area] the tolerance area for simplification
* @param {number} [dist] a tolerance distance for simplification
* @param {number} [ratio=.8] a ratio of points to keep
* @param {number} [minPoints=2] minimum number of points to keep
* @param {boolean} [keepEnds] keep line ends
* @return { LineString } A new, simplified version of the original geometry.
* @api
*/
ol_geom_LineString.prototype.simplifyVisvalingam = function (options) {
var points = this.getCoordinates();
if (options.minPoints && options.minPoints >= points.length) {
return new ol_geom_LineString(points);
}
var heap = minHeap(),
maxArea = 0,
triangle,
triangles = [];
points = points.map(function (d) { return d.slice(0,2); });
for (var i = 1, n = points.length - 1; i < n; ++i) {
triangle = points.slice(i - 1, i + 2);
if (triangle[1][2] = area(triangle)) {
triangles.push(triangle);
heap.push(triangle);
}
}
for (i = 0, n = triangles.length; i < n; ++i) {
triangle = triangles[i];
triangle.previous = triangles[i - 1];
triangle.next = triangles[i + 1];
}
while (triangle = heap.pop()) {
// If the area of the current point is less than that of the previous point
// to be eliminated, use the latters area instead. This ensures that the
// current point cannot be eliminated without eliminating previously-
// eliminated points.
if (triangle[1][2] < maxArea) triangle[1][2] = maxArea;
else maxArea = triangle[1][2];
if (triangle.previous) {
triangle.previous.next = triangle.next;
triangle.previous[2] = triangle[2];
update(triangle.previous);
} else {
triangle[0][2] = triangle[1][2];
}
if (triangle.next) {
triangle.next.previous = triangle.previous;
triangle.next[0] = triangle[0];
update(triangle.next);
} else {
triangle[2][2] = triangle[1][2];
}
}
function update(triangle) {
heap.remove(triangle);
triangle[1][2] = area(triangle);
heap.push(triangle);
}
// Get area to remove
var w = options.area;
if (options.dist) w = options.dist * options.dist / 2;
// If no area
if (w === undefined || options.minPoints) {
// Get ordered weights
var weights = points.map(function (d) { return d.length < 3 ? Infinity : d[2] += Math.random(); /* break ties */ });
weights.sort(function (a, b) {
return b - a;
});
if (w) {
// Check min points
if (weights[options.minPoints] < w) {
w = weights[options.minPoints]
}
} else {
var pointsToKeep = options.minPoints;
// Calculate ratio
if (!pointsToKeep) {
var ratio = options.ratio || .8
pointsToKeep = Math.round(points.length * ratio);
}
pointsToKeep = Math.min(pointsToKeep, weights.length -1);
w = weights[pointsToKeep]
}
}
var result = points.filter(function (d) {
return d[2] > w;
});
if (options.keepEnds) {
if (!ol_coordinate_equal(result[0], points[0])) result.unshift(points[0]);
if (!ol_coordinate_equal(result[result.length-1], points[points.length-1])) result.push(points[points.length-1]);
}
return new ol_geom_LineString(result);
};
function compare(a, b) {
return a[1][2] - b[1][2];
}
function area(t) {
return Math.abs((t[0][0] - t[2][0]) * (t[1][1] - t[0][1]) - (t[0][0] - t[1][0]) * (t[2][1] - t[0][1]));
}
function minHeap() {
var heap = {},
array = [];
heap.push = function() {
for (var i = 0, n = arguments.length; i < n; ++i) {
var object = arguments[i];
up(object.index = array.push(object) - 1);
}
return array.length;
};
heap.pop = function() {
var removed = array[0],
object = array.pop();
if (array.length) {
array[object.index = 0] = object;
down(0);
}
return removed;
};
heap.size = function () {
return array.length;
};
heap.remove = function(removed) {
var i = removed.index,
object = array.pop();
if (i !== array.length) {
array[object.index = i] = object;
(compare(object, removed) < 0 ? up : down)(i);
}
return i;
};
function up(i) {
var object = array[i];
while (i > 0) {
var up = ((i + 1) >> 1) - 1,
parent = array[up];
if (compare(object, parent) >= 0) break;
array[parent.index = i] = parent;
array[object.index = i = up] = object;
}
}
function down(i) {
var object = array[i];
for (;;) {
var right = (i + 1) * 2,
left = right - 1,
down = i,
child = array[down];
if (left < array.length && compare(array[left], child) < 0) child = array[down = left];
if (right < array.length && compare(array[right], child) < 0) child = array[down = right];
if (down === i) break;
array[child.index = i] = child;
array[object.index = i = down] = object;
}
}
return heap;
}
})();
export default ol_geom_LineString