Tư tưởng chính của thuật toán
Bước 1: Với tập hợp điểm , sinh ra một đường cong Bezier với các thông số lần lượt là tiếp tuyến bên trái, tiếp tuyến bên phải, và độ sai lệch cho phép
Bước 2: Tính giá trị là sai số của đường cong khi khớp với tập điểm .
Nếu , ngừng thuật toán, chính là đường cong cần tìm
Nếu không, ta chia tập điểm thành 2 phần tại điểm có khoảng cách xa nhất so với , tạm gọi là điểm rồi áp dụng gọi đệ quy cho 2 tập điểm mới: và để tiếp tục tìm đường cong để khớp với 2 tập điểm mới.
Một số điểm nhấn của thuật toán
Để tiện cho việc tính toán, ta dùng công thức tính đường cong với tham số :
Đối với đường cong Bezier bậc 3 với control points thì tiếp tuyến của đường cong tại các điểm đầu mút và nằm trên đường thẳng chứa đoạn và đường thẳng chứa đoạn . Điều này được thể hiện qua công thức:
Như vậy, ta có thể biểu diễn và với lần lượt các các vector tiếp tuyến tại và
Như vậy việc khớp đường cong với một tập điểm thực chất là ta đi kiếm giá trị phù hợp của . Chi tiết để tính toán đã được mô tả khá kỹ trong paper từ trang 618 đến trang 620 nên mình không viết lại nữa. Implementation của phần này nằm trong function generateBezier, bạn có thể tham khảo trong phần source code.
Việc còn lại là cần tính khoảng cách từ 1 điểm đến đường cong , với phương trình tham số :
Mình mượn lại hình vẽ trong bài báo. Như vậy để tính khoảng cách từ đến nghĩa là chúng ta cần tính . Như vậy, việc khớp đường cong nghĩa là ta cần cực tiểu hóa khoảng cách của tất cả các điểm trong tập đến : , với là giá trị tham số tương ứng với điểm . Để đơn giản hóa, ta tìm cực tiểu của tổng bình phương khoảng cách của tất các các điểm trong tập đến đường cong: .
Vậy làm sao tính giá trị tham số cho một điểm ? Đầu tiên, ta tạm thời xấp xỉ các giá trị cho từng điểm , bằng cách đo khoảng khách của một đoạn trên tổng khoảng cách các đoạn từ đến (tham khảo function chordLengthParam). Sau đó ta cố gắng tính chính xác hơn theo phương phắp lặp Newton-Ralphson, nhờ vào nhận xét rằng vector khoảng cách từ và tiếp tuyến tại là vuông góc, ta có . Công thức để cạp nhật sau mỗi lần lặp tìm nghiệm: .