Point reduction algorithm Ramer - Douglas - Peuker
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 \(C\) be a path by set of \(n \) ordered points:
\(C=\{P_1,P_2,\dots,P_n\}\) and an tolerance rate \(\delta > 0\)
We define function \(fReduce(points, start,end,\delta)\) is the function to reduce points in \(points\) from \(start\) index to \(end\) index as following:
Let \(i=[(start+1) \dots (end-1)]\)
Calculate \(d_i = d(P_i, \overline{P_{start}P_{end}})\) inwhich:
\(\overline{P_{start}P_{end}}\) is the line segment that connects \(P_{start}\) and \(P_{end}\)
function \(d(P_i, \overline{P_iP_j})\) is the function to measure the Euclidean distance from \(P_i\) to \(\overline{P_iP_j}\)
Find \(d_{max} = \max d(P_i,\overline{P_{start}P_{end}})\)
If \(d_{max} \le \delta\): remove all points \([P_{start+1} \dots P_{end-1}]\)
If \(d_{max} > \delta\) at the \(k^{th}\) index, we split the \(points\) at \(k\) and makes 2 recursive calls:
\(fReduce(points, start,k,\delta)\)
\(fReduce(points, k, end,\delta)\)
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 \(A\) to \(BC\) is the length of \(AH\). Knowing:
$$\displaystyle S_{ABC} = \frac {AH \times BC} {2} \implies AH = \frac {2 \times S_{ABC}} {BC}$$
\(S_{ABC}\) can be calculated by the cross product of those vectors \(\overrightarrow{AB}\) and \(\overrightarrow{AC}\):
$$\displaystyle 2 \times S_{ABC} = |\overrightarrow{AB}||\overrightarrow{AC}||\sin \theta|=|\overrightarrow{AB} \times \overrightarrow{AC}| \implies AH = \frac {|\overrightarrow{AB} \times \overrightarrow{AC}|} 2$$
With \(\theta\) is the angle by \(\overrightarrow{AB}\) and \(\overrightarrow{AC}\).
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;
}