Có nhiều cách để kiểm tra một điểm có thuộc đường thằng (tương tự với đoạn thẳng) hay không: bằng cách sử dụng các cơng thức hình học hoặc thuật tốn vẽ đường thẳng,… Ngồi những cách trên, ta sẽ giới thiệu một phương pháp đơn giản nhất là sử dụng phép so sánh góc để giải quyết vấn đề này.
Trong demo sau, khi bạn di chuyển chuột ngang lên trên đoạn thẳng, bạn sẽ đoạn thẳng chuyển sang màu đỏ.
Ý tưởng:
Ta có đoạn thẳng AB tạo nên góc α (so với phương ngang hoặc phương bất kì), và mọi điểm thuộc AB đều tạo nên góc α so với phương ngang.
Hay nói cách khác, ta xem đoạn thẳng AB là đường chéo của một tam giác vng ABM. Tỉ lệ giữa hai cạnh góc vng của tam giác này sẽ bằng với tỉ lệ hai cạnh góc vng tạo bởi tam giác vng AXN. Minh họa như hình dưới đây:
Như vậy việc xác định một điểm X có thuộc AB hay khơng chỉ cần dựa vào 2 yếu tố:
(1) X phải nằm trong vùng hình chữ nhật được tạo bởi đường chéo AB (ngoại tiếp tam giác ABM).
(2) Góc XAN và BAM phải bằng nhau.
Ngoài ra, do việc so sánh là kiểu số thực và có thể do độ rộng của đoạn thẳng khác nhau nên ta cần chấp nhận một giá trị sai số EPSILON nào đó.
51 | P a g e Muốn chính xác hơn khi độ rộng của đoạn thẳng thay đổi, bạn có thể tính góc sai số cho phép bằng cách dựa vào ½ độ rộng đoạn thẳng và khoảng cách AX để tính. Tuy nhiên, điều này khơng quan trọng lắm và làm cho việc kiểm tra tốn thêm chi phí.
Để đơn giản, ta sẽ tính tỉ lệ (tan) thay vì tính góc α:
Line.prototype.contains = function(x, y) { if( x < Math.min(this.handler1.cx,this.handler2.cx) || x > Math.max(this.handler1.cx,this.handler2.cx) || y < Math.min(this.handler1.cy,this.handler2.cy) || y > Math.max(this.handler1.cy,this.handler2.cy)) return false; var dx = this.handler1.cx-this.handler2.cx; var dy = this.handler1.cy-this.handler2.cy; var tan1 = Math.abs(dy/dx);
var tan2 = Math.abs((y-this.handler1.cy)/(x-this.handler1.cx)); return Math.abs(tan1 - tan2) < EPSILON;
}