Przecięcia odcinków Wykład 2 2006/07
Problem Dane: zbiór S={s 1,...,s n } odcinków na płaszczyźnie Wynik: zbiór punktów przecięć wszystkich odcinków z S, wraz z informacją które odcinki przecinają się w poszczególnych punktach Przypadek ogólny: możliwe wiele przecięć w jednym punkcie, dopuszczalne odcinki pionowe
Algorytm FindIntersections(S) Struktury danych: H kolejka priorytetowa wszystkich znanych zdarzeń na prawo od sweep line (zdarzenie: koniec odcinka lub przecięcie) V zbalansowane drzewo odcinków przecinających sweep line, uporządkowane wg współrzędnej y punktu przecięcia
Algorytm FindIntersections(S) H końce wszystkich odcinków z S (porządek względem współrzędnej x) V //zbalansowane drzewo odcinków, porządek względem kolejności przecinania sweep line Dopóki H Ustal następny punkt p w H, usuń p z H HandleEventPoint(p)
HandleEventPoint(p) Definicje: L(p) zbiór odcinków, których lewy koniec znajduje się w p P(p) zbiór odcinków, których prawy koniec znajduje się w p C(p) zbiór odcinków, które zawierają p we wnętrzu
HandleEventPoint(p) 1. Znajdź zbiór P(p) C(p) wszystkich odcinków w V, które zawierają p [tworzą spójny obszar w porządku przecinania sweep line] 2. Jeśli L(p) P(p) C(p) >1: podaj p jako przecięcie, razem z L(p) P(p) C(p) 3. Usuń P(p) C(p) z V 4. Wstaw L(p) C(p) do V [porządek w jakim przetną sweep line tuż na prawo od p; el. C(p) zmienią kolejność] 5. Szukaj przecięć nowych sąsiadów w V.
5. Szukaj przecięć nowych sąsiadów w V. Jeśli L(p) C(p)= s l najbliższy p element w V, większy od p (wyżej) s r najbliższy p element w V, mniejszy od p (niżej) FindNewEvent(s l, s r, p) w przeciwnym razie: s najmniejszy el. V w L(p) C(p) s l najw. el. V wśród mniejszych od s FindNewEvent(s l, s, p) s największy el. V w L(p) C(p) s r najmn. el. V wśród większych od s FindNewEvent(s, s r, p)
JEŻELI FindNewEvent(s l, s r, p) TO (s l i s r przecinają się na prawo od sweep line lub na sweep line i poniżej p) oraz (punkt przecięcia s l i s r nie występuje w H) dodaj punkt przecięcia s l i s r do H.
Poprawność i koszt Poprawność: jak wcześniej Czas: O(n log n + P log n), gdzie P to liczba przecięć inicjalizacja H: O(n log n) aktualizacja H: O((P+n) log n) P+n zdarzeń przy każdym zdarzeniu: jedno usunięcie, 2 wstawienia wstawienie/usunięcie: O(log n) aktualizacja V: wstawienie/usunięcie: O(log n) liczba wstawień/usunięć = liczba odcinków otrzymanych z S poprzez podział każdego odcinka na części w punktach przecięć Czy liczba tych odcinków liniowa względem liczby przecięć? Patrz: zależność między liczbą krawędzi, wierzchołków i ścian w grafie planarnym.
Dokładniej liczba wstawień/usunięć 2 * liczba krawędzi uzyskanego grafu = 2 * n e liczba wierzchołków grafu = 2n + P = n v Euler Formula: n v n e + n f 2 czyli n e n v +n f -2 a n f n v /3.
Koszt Pamięć: drzewo V: O(n) [w nim tylko odcinki z S] kolejka [priorytetowa] H (też może być drzewo): O(P) [w najgorszym razie wszystkie przecięcia w H w tym samym czasie] Jak zmniejszyć pamięć do O(n)? w H pamiętamy przecięcia tylko tych elementów S, które są sąsiednie w V gdy wstawiamy do H przecięcie odcinki są sąsiednie gdy usuwamy jakieś odcinki z V, usuwamy też ich sąsiadów z H Poprawność: przeciąć się mogą tylko sąsiedzi Czas: liczba wstawień/usunięć do H zwiększona TYLKO o liczbę wstawień/usunięć do V.
Planarny podział płaszczyzny Podwójnie połączona lista krawędzi: wierzchołek v: współrzędne v, IncidentEdge(v) wskazuje na dowolną incydentną półkrawędź; ściana f: OuterComponent(f): wskazuje dowolną półkrawędź na zewnętrznym brzegu InnerComponents(f): lista dziur, dla każdej dziury jedna półkrawędź.
Planarny podział płaszczyzny Podwójnie połączona lista krawędzi: półkrawędź e: Origin(e) wskaźnik na wierzchołek będący początkiem e Twin(e) wskaźnik na bliźniaczą półkrawędź IncidentFace(e) wskaźnik na ścianę incydentną do e (taka ściana tylko jedna ta po lewej od skierowanej krawędzi e) Next(e) następna krawędź w IncidentFace(e) Prev(e) poprzednia krawędź w IncidentFace(e)