💡 Cho đường C được tạo bởi tập hợp các đoạn thẳng nối tiếp nhau của một tập hợp điểm. Cho trước một độ error rate nhất định, rút gọn số lượng điểm của tập hợp này sao cho vẫn giữ được hình dạng của đường C ban đầu.
Thuật toán này còn được biết đến với tên là Ramer–Douglas–Peucker.Thuật toán được phát triển độc lập bởi Urs Ramer vào năm 1972 và bởi David Douglas và Thomas Peucker vào năm 1973.
Thuật toán
Cho đường dưới dạng tập hợp của điểm sắp xếp thứ tự:
và một giá trị độ sai .
Ta định nghĩa hàm là hàm lược bỏ các điểm trong tập điểm từ index đến như sau:
Cho lần lượt nhận giá trị từ đến :
Tính , với:
là đoạn thẳng nối và
hàm là hàm đo khoảng cách từ điểm đến
Tìm
Nếu : tất cả các điểm từ đến đều có thể lược bỏ
Nếu tại index thứ , ta chia đoạn thẳng thành 2 phần để thực hiện gọi đệ quy như sau:
Minh họa
Source code
// pointIndices là mảng để lưu trữ các index được giữ lại sau quá trình thu gọn
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;
}
}
// tolerance là giá trị delta
if ((maxD > tolerance) && (indexFurthest != 0)){
pointIndices.push(indexFurthest);
fReduce(points, firstPoint, indexFurthest, tolerance, pointIndices)
fReduce(points, indexFurthest, lastPoint, tolerance, pointIndices)
}
}
Thuật toán tính khoảng cách điểm đến đường thẳng
Khoảng cách từ điểm đến đoạn là chiều dài đoạn .
Ta có:
Tuy nhiên, có thể được tính bởi công thức cross product của vector và như sau:
Với là góc tạo bởi vector và .
Source code
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;
}