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:
@@ -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"
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user