Thuật toán rút gọn số điểm trên đường cong Douglas-Peuker

💡 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.

Cho đường C dưới dạng tập hợp của n điểm sắp xếp thứ tự:

C=(P1,P2,,Pn) và một giá trị độ sai δ>0.

Ta định nghĩa hàm fReduce(points,start,end,δ) là hàm lược bỏ các điểm trong tập điểm points từ index start đến end như sau:

  • Cho i lần lượt nhận giá trị từ start+1 đến end1:

  • Tính di=d(Pi,PstartPend), với:

    • PstartPend là đoạn thẳng nối Pstart và Pend

    • hàm d(Pi,PiPj) là hàm đo khoảng cách từ điểm Pi đến PiPj

  • Tìm dmax=maxd(Pi,PstartPend)

  • Nếu dmaxδ: tất cả các điểm từ Pstart+1 đến Pend1 đều có thể lược bỏ

Nếu dmax>δ tại index thứ k, ta chia đoạn thẳng thành 2 phần để thực hiện gọi đệ quy như sau:

  • fReduce(points,start,k,δ)

  • fReduce(points,k,end,δ)

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)
    }
}
				
			

Khoảng cách từ điểm A đến đoạn BC là chiều dài đoạn AH.

Ta có: SABC=AH×BC2AH=2×SABCBC

Tuy nhiên, SABC có thể được tính bởi công thức cross product của vector AB và AC như sau:

2×SABC=|AB||AC||sinθ|=|AB×AC|AH=|AB×AC|2

Với θ là góc tạo bởi vector AB và AC.

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;
}
				
			

Subscribe to SkyGLab

Scroll to Top