Added Douglas-Peucker linestring simplification to OpenLayers.Geometry.LineString. Thanks chrismayer for this excellent patch. p=chrismayer, r=me (closes #2869)

git-svn-id: http://svn.openlayers.org/trunk/openlayers@10969 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
This commit is contained in:
ahocevar
2010-12-15 13:38:52 +00:00
parent b61cec71a1
commit e9e2aec77d
4 changed files with 838 additions and 1 deletions

View File

@@ -547,6 +547,98 @@ OpenLayers.Geometry.LineString = OpenLayers.Class(OpenLayers.Geometry.Curve, {
}
return best;
},
/**
* APIMethod: simplify
* This function will return a simplified LineString.
* Simplification is based on the Douglas-Peucker algorithm.
*
*
* Parameters:
* tolerance - {number} threshhold for simplification in map units
*
* Returns:
* {OpenLayers.Geometry.LineString} the simplified LineString
*/
simplify: function(tolerance){
if (this && this !== null) {
var points = this.getVertices();
if (points.length < 3) {
return this;
}
var compareNumbers = function(a, b){
return (a-b);
};
/**
* Private function doing the Douglas-Peucker reduction
*/
var douglasPeuckerReduction = function(points, firstPoint, lastPoint, tolerance){
var maxDistance = 0;
var indexFarthest = 0;
for (var index = firstPoint; index < lastPoint; index++) {
distance = perpendicularDistance(points[firstPoint], points[lastPoint], points[index]);
if (distance > maxDistance) {
maxDistance = distance;
indexFarthest = index;
}
}
if (maxDistance > tolerance && indexFarthest != firstPoint) {
//Add the largest point that exceeds the tolerance
pointIndexsToKeep.push(indexFarthest);
douglasPeuckerReduction(points, firstPoint, indexFarthest, tolerance);
douglasPeuckerReduction(points, indexFarthest, lastPoint, tolerance);
}
};
/**
* Private function calculating the perpendicular distance
* TODO: check whether OpenLayers.Geometry.LineString::distanceTo() is faster or slower
*/
var perpendicularDistance = function(point1, point2, point){
//Area = |(1/2)(x1y2 + x2y3 + x3y1 - x2y1 - x3y2 - x1y3)| *Area of triangle
//Base = v((x1-x2)²+(x1-x2)²) *Base of Triangle*
//Area = .5*Base*H *Solve for height
//Height = Area/.5/Base
var area = Math.abs(0.5 * (point1.x * point2.y + point2.x * point.y + point.x * point1.y - point2.x * point1.y - point.x * point2.y - point1.x * point.y));
var bottom = Math.sqrt(Math.pow(point1.x - point2.x, 2) + Math.pow(point1.y - point2.y, 2));
var height = area / bottom * 2;
return height;
};
var firstPoint = 0;
var lastPoint = points.length - 1;
var pointIndexsToKeep = [];
//Add the first and last index to the keepers
pointIndexsToKeep.push(firstPoint);
pointIndexsToKeep.push(lastPoint);
//The first and the last point cannot be the same
while (points[firstPoint].equals(points[lastPoint])) {
lastPoint--;
//Addition: the first point not equal to first point in the LineString is kept as well
pointIndexsToKeep.push(lastPoint);
}
douglasPeuckerReduction(points, firstPoint, lastPoint, tolerance);
var returnPoints = [];
pointIndexsToKeep.sort(compareNumbers);
for (var index = 0; index < pointIndexsToKeep.length; index++) {
returnPoints.push(points[pointIndexsToKeep[index]]);
}
return new OpenLayers.Geometry.LineString(returnPoints);
}
else {
return this;
}
},
CLASS_NAME: "OpenLayers.Geometry.LineString"
});