Giao của các polyline

Một phần của tài liệu Một số vấn đề cơ sở dữ liệu không gian (Trang 56)

Để giải quyết bài toán này, trước tiên cần xác định giao của các đoạn thẳng.

Cho tập S các đoạn thẳng, kiểm tra xem tồn tại giao của cặp đoạn thẳng

bất kỳ. Xét một cách tuần tự, thuật toán này cần thời gian thực hiện là O(n2) và

dừng khi phát hiện một giao điểm. Sử dụng thuật toán quét đoạn thẳng plan- sweep sẽ cải thiện được tốc độ, mức O(log(n)).

Kỹ thuật đoạn thẳng quét có thể phát hiện giao điểm của tập các đoạn thẳng nhờ vào thuộc tính sau. Giả sử vẽ một đoạn thẳng đứng, giao một số đoạn thẳng thuộc S (hình 3.5). Sử dụng một danh sách lưu các giao điểm đó sắp xếp

theo toạ độ y tại mỗi thời điểm.

s1

s2

s3

Xét giao giữa hai đoạn thẳng s1, s2, nếu đường thẳng đứng l càng gần giao điểm này thì các giao của s1, s2 với l càng có nhiều khả năng liên tiếp trong danh

sách.

Thuộc tính này cho phép chúng ta không cần kiểm tra giao của một đoạn thẳng với tất cả các đoạn thẳng khác. Quét đường thẳng đứng l từ trái qua phải và duy trì một danh sách các đoạn thẳng đang có giao điểm với l, khi đó chỉ cần

kiểm tra giao của các đoạn thẳng xuất hiện kề nhau trong danh sách. Xây dựng một danh sách L và một danh sách sự kiện E lưu toạ độ x của các điểm mút. Có thể xảy ra hai trường hợp:

l gặp điểm bên trái của một đoạn thẳng s. Chèn s vào L, khi đó, nhiều nhất

hai đoạn thẳng trong L (trên và dưới s) được kiểm tra giao với s.

l gặp điểm bên phải của một đoạn thẳng s. Xoá s khỏi L, khi đó hai đoạn

thẳng lân cận với s được kiểm tra giao điểm với nhau.

SegmentIntersectionTest (S: tập các đoạn thẳng): boolean

begin

Sắp xếp 2n điểm mút của các đoạn thẳng trong S, đưa vào E

for (i = 1 to 2n) do begin

p = E[i]

if (p là điểm bên trái của s)

begin

Insert(s,L)

if (Above(s,L) giao với s) return true

end if

if (p là điểm bên phải của s)

begin

if (Above(s,L) giao với Below(s,L)) return true Delete(s,L)

end if

end for end

Trong thuật toán này, danh sách sự kiện E đơn giản là một mảng, danh

sách L cần có các thao tác chèn, xoá và các hàm Above, Below, do đó có thể sử

dụng cấu trúc cây. Trong trường hợp bài toán có kích thước đầu vào không lớn, việc sử dụng thuật toán nhạy cảm với kích thước đầu ra là một lựa chọn thích hợp. Có hai thuật toán loại này.

 Thuật toán thứ nhất là sự mở rộng từ thuật toán đọan thẳng quét đã trình bày trên, thời gian thực hiện là O((n+k)log n), với k là số giao điểm.

 Thuật toán thứ hai tính số giao điểm giữa hai tập đoạn thẳng, các đoạn thẳng trong mỗi tập là không giao nhau. Thuật toán này khá tối ưu, có thể đạt O(nlogn + k).

Với thuật toán thứ nhất, cần sử dụng hai điều kiện bổ sung:

 Một giao điểm được xem như một sự kiện vì nó tạo nên thay đổi trong danh sách L. Do vậy, mỗi khi phát hiện một giao điểm, cần chèn nó vào

 Khi đường thẳng quét gặp một giao điểm giữa s1, s2 thì hai đoạn thẳng này phải được đảo vị trí trong L. Và khi đó, tất cả các đoạn thẳng lân cận với

chúng phải được kiểm tra

SegmentIntersection (S: tập các đoạn thẳng): tập điểm

begin

Sắp xếp 2n điểm mút của các đoạn thẳng trong S, đưa vào E L = i

while (L <> i)

begin

p = Min(E) // lấy từ E

if (p là điểm bên trái của s)

begin

Insert(s,L)

s1 = Above(s,L), s2 = Below(s,L)

if (s1 giao với s) AddInter(s ∩ s1, E)

if (s2 giao với s) AddInter(s ∩ s2, E)

end if

if (p là điểm bên phải của s)

begin

s1 = Above(s,L), s2 = Below(s,L) Delete(s,L)

if (s1 giao với s2 về bên phải p) AddInter(s1 ∩ s2, E)

end if

if (p là giao s1, s2)

s3 = Above(Max(s1,s2), L); s4 = Below(Min(s1,s2)), L)

if (s3 giao Min(s1,s2))), AddInter(s3 ∩ Min(s1,s2)), E)

if (s4 giao Max(s1,s2))), AddInter(s4 ∩ Max(s1,s2)), E) Đổi chỗ s1, s2 trong L

end

if (s3 giao với s2) AddInter(s3 ∩ s2, E)

if (s2 giao với s) AddInter(s ∩ s2, E)

end

end

Trong thuật toán này, bước chuẩn bị (sắp xếp) thực hiện trong O(n log n).

Vòng lặp chính thực hiện 2n+k lần, với k là số giao điểm. Trong vòng lặp, mỗi thao tác cần O(log n). Nếu E được cài đặt như một cấu trúc hàng đợi ưu tiên. Do vậy, để thực hiện toàn bộ thuật toán, cần O((n+k)log n). Rõ ràng thuật toán này

nhanh hơn cách sử dụng vòng lặp khi số lượng giao điểm k nhỏ.

Mặc dù vậy, vẫn tồn tại một khoảng cách giữa độ phức tạp của thuật toán với trường hợp thuận lợi nhất. Vấn đề này được khắc phục khi sử dụng thuật toán thứ hai, xác định giao của hai tập hợp các đoạn thẳng. Có thể quy ước các đoạn thẳng trong hai tập có màu khác nhau, chẳng hạn xanh và đỏ, thuật toán này còn được gọi là thuật toán Red-blue intersection.

So với thuật toán trước, điểm sửa đổi đầu tiên của thuật toán này là ở chỗ nó sẽ duy trì hai danh sách Lr, Lb. Vì các đoạn thẳng cùng màu không giao nhau, nên các danh sách chỉ thay đổi khi gặp điểm mút của một đoạn thẳng. Tức là, danh sách sự kiện có thể được quản lý như một mảng tĩnh gồm 2n phần tử được sắp xếp (O(n log n)).

Để xác định các giao điểm của một đoạn thẳng trong tập này với các đoạn thẳng trong tập kia, giả sử đường màu đỏ r và tập xanh {bi}, khi đường thẳng quét l chạm đến điểm mút bên phải của r, trước khi loại bỏ r, tìm trong danh

sách Lb các đoạn thẳng giao với r. Có hai trường hợp:

Trường hợp 1 (3.6a). Tất cả các đoạn thẳng trong Lb giao với r đều liên

tiếp trong Lb. Khi đó, có thể duyệt trước và sau trong Lb cho đến khi gặp một đoạn thẳng không giao với r. Độ phức tập ở đây là O(n log n + k).

Trường hợp 2 (3.6b). Tất cả các đoạn thẳng giao với r không xuất hiện

liên tục trong Lb. Trong hình trên, đường b2 không giao với r nhưng lại nằm giữa

b1 và b3 là hai đường có giao r. Do đó, cần duyệt toàn bộ danh sách để xác định

các giao điểm. b3 b2 l b 3 b2 b1 r (a) b3 b2 b1 r l (b) b1 r l (c)

Hình 3.6. Kiểm tra giao của đường thẳng r với các đường khác

Việc giải quyết tốt bài toán xác định giao của hai tập hợp các đoạn thẳng cho phép dễ dàng xác định giao của hai polyline. Khi đó, mỗi polyline được xem như một tập hợp các đoạn thẳng có cùng một màu

Một phần của tài liệu Một số vấn đề cơ sở dữ liệu không gian (Trang 56)

Tải bản đầy đủ (PDF)

(119 trang)