💡 Let C be a path created by a set of consecutive line segments of a set of points. Given a certain error rate, reduce the number of points in this set so that the shape of the original path C is still maintained.
This algorithm is also known as Ramer–Douglas–Peucker. The algorithm was developed independently by Urs Ramer in 1972 and by David Douglas and Thomas Peucker in 1973.
Algorithm
Given be a path by set of ordered points:
and an tolerance rate
We define function is the function to reduce points in from index to index as following:
Let
Calculate inwhich:
is the line segment that connects and
function is the function to measure the Euclidean distance from to
Find
If : remove all points
If at the index, we split the at and makes 2 recursive calls:
Illustration
Source Code
// pointIndices is the array to store points after reduction process
function fReduce(points, firstPoint, lastPoint, tolerance, pointIndices){
let maxD = 0;
let indexFurthest = 0;
for (let i=firstPoint + 1; i< lastPoint - 1; i++){
let distance = dPointLine(points[i], points[firstPoint], points[lastPoint]);
if (distance > maxD){
maxD = distance;
// lưu index của điểm xa nhất
indexFurthest = i;
}
}
if ((maxD > tolerance) && (indexFurthest != 0)){
pointIndices.push(indexFurthest);
// recursive calls
fReduce(points, firstPoint, indexFurthest, tolerance, pointIndices)
fReduce(points, indexFurthest, lastPoint, tolerance, pointIndices)
}
}
Calculate distance from a point to a line
Distance from to is the length of . Knowing:
can be calculated by the cross product of those vectors and :
With is the angle by and .
Souce code
// calculate distance from point p1 to line p2p3
function dPointLine(p1, p2, p3){
let area = Math.abs(0.5 * (p2.x * p3.y + p3.x * p1.y + p1.x * p2.y - p3.x * p2.y - p1.x * p3.y - p2.x * p1.y))
let bottom = p2.dist(p3);
let height = area / bottom * 2.0;
return height;
}