• Nie Znaleziono Wyników

Obcinanie odcinków i prostych

W dokumencie Grafika komputerowa I – MIM UW (Stron 32-35)

3. Obcinanie linii i wielokątów

3.1. Obcinanie odcinków i prostych

— wyznaczeniu fragmentu odcinka lub prostej, który leży wewnątrz okna na ekranie (ogólniej: dowolnego wielokąta), lub

— wyznaczeniu fragmentu odcinka lub prostej, który leży wewnątrz ustalonej bryły wielościen-nej.

Rozwiązanie jednego z tych zadań może być potrzebne w celu narysowania pewnej części odcin-ka, a także w konstrukcyjnej geometrii brył, w algorytmach widoczności i w śledzeniu promieni, o czym będzie mowa dalej.

Jeśli problem do rozwiązania polega na wyznaczeniu części wspólnej odcinka (lub prostej) i wielokąta (lub wielościanu) wypukłego, to możemy ten wielokąt (wielościan) przedstawić ja-ko przecięcie pewnej liczby półpłaszczyzn (półprzestrzeni) i sprowadzić zadanie do obcinania półpłaszczyznami (półprzestrzeniami).

3.1.1. Wyznaczanie punktu przecięcia odcinka i prostej

Dane są punkty końcowe odcinka, p1 = (x1, y1) i p2 = (x2, y2), oraz współczynniki a, b, c równania prostej ax+by = c. Mamy znaleźć (jeśli istnieje) punkt wspólny tego odcinka i prostej.

Przedstawienie parametryczne odcinka, p = p1+ t(p2− p1), czyli " x y # = " x1 y1 # + t " x2− x1 y2− y1 # dla t ∈ [0, 1], (3.1)

wstawiamy do równania prostej, otrzymując równanie

a(x1+ t(x2− x1)) + b(y1+ t(y2− y1)) = c, którego rozwiązaniem jest

t = c − ax1− by1 a(x2− x1) + b(y2− y1).

Jeśli t /∈ [0, 1], to prosta i odcinek są rozłączne. W przeciwnym razie możemy obliczyć

współrzędne x, y punktu wspólnego. Wzór jest szczególnie prosty w przypadku, gdy równanie prostej obcinającej ma postać x = c (prosta jest wtedy pionowa), lub y = c (prosta jest pozioma).

Prawie identyczne jest wyprowadzenie odpowiednich wzorów w przestrzeni trójwymiarowej, dla danych punktów końcowych (x1, y1, z1), (x2, y2, z2) i równania płaszczyzny obcinającej ax +

by + cz = d.

3.1.2. Algorytm Sutherlanda-Cohena

Omówimy najbardziej popularną wersję obcinania do okna prostokątnego. Dla dowolnego wielokąta/wielościanu wypukłego zasada działania algorytmu jest identyczna.

Dane są punkty końcowe odcinka i prostokątne okno. Proste, na których leżą krawędzie okna, dzielą płaszczyznę na 9 obszarów. Przyporządkujemy im czterobitowe kody przedstawione na rysunku 3.1a.

Rysunek 3.1. Algorytm Sutherlanda-Cohena: podział płaszczyzny na obszary a) podział płasz-czyzny na obszary, b) odrzucanie odcinka.

Kody obszarów, do których należą końce odcinka, możemy wyznaczyć na podstawie ich współrzędnych. Zauważmy, że jeśli oba kody na dowolnej pozycji mają jedynkę, to cały odcinek leży poza oknem (rys.3.1b). Jeśli oba punkty końcowe mają kod 0, to cały odcinek leży wewnątrz okna. Jeśli kody są różne od 0, ale nie mają jedynki jednocześnie na żadnej pozycji, to odcinek może, ale nie musi mieć części wewnątrz okna.

Dla dowolnego wielokąta lub wielościanu określa się kody o liczbie bitów równej liczbie kra-wędzi albo ścian. Algorytm wyznacza punkt przecięcia odcinka z krakra-wędzią, której odpowiada 1 w którymś kodzie, a następnie zastępuje jeden z punktów (ten, w którego kodzie występuje ta jedynka) przez punkt przecięcia. Nie grozi przy tym dzielenie przez 0 (dlaczego?).

#define NIC 0 #define CAŁY 1 #define CZĘŚĆ 2

char SC clip ( punkt &p1, punkt &p2 ) { char wynik, c1, c2; wynik = CAŁY; c1 = KodPunktu ( p1 ); c2 = KodPunktu ( p2 ); while ( c1 || c2 ) { if ( c1 & c2 ) return NIC; if ( !c1) { zamień ( p1, p2 ); zamień ( c1, c2 ); } switch ( c1 ) {

case 0001: case 0101: case 1001: ∗p1= punkt przecięcia z prostą x = xmin; break; case 0010: case 0110: case 1010: ∗p1= punkt przecięcia z prostą x = xmax; break; case 0100: ∗p1= punkt przecięcia z prostą y = ymin; break;

} c1 = KodPunktu ( p1 ); ∗kod = CZĘŚĆ; } return wynik; }/∗SC clip∗/ 3.1.3. Algorytm Lianga-Barsky’ego

Wadą algorytmu Sutherlanda-Cohena jest to, że obliczane są punkty, które mogą być na-stępnie odrzucone (ponieważ leżą poza oknem). Zabiera to czas, a ponadto wprowadza większe błędy zaokrągleń. Aby otrzymać algorytm pozbawiony tych wad, skorzystamy z parametrycz-nego przedstawienia odcinka (3.1). Oznaczymy ∆x = x2 − x1, ∆y = y2 − y1. Aby dokonać obcięcia odcinka, zawęzimy przedział zmienności parametru t do przedziału odpowiadającego części wspólnej odcinka z oknem, a dopiero potem wyznaczymy punkty końcowe. Zauważmy, że w ogólności możemy przyjąć na początku inny przedział niż [0, 1], co umożliwi obcinanie odcinka który leży na prostej przechodzącej przez punkty (x1, y1) i (x2, y2), ale o innych koń-cach. Możemy nawet przyjąć początkowy przedział [−∞, +∞], który reprezentuje całą prostą (ale wtedy procedura obcinania musi wyprowadzić wynik w postaci odpowiednich wartości parametru prostej).

float t1, t2;

char Test ( float p, float q ) { float r; if ( p < 0 ) { r = q/p; if ( r > t2 ) return 0; else if ( r > t1 ) t1 = r; } else if ( p > 0 ) { r = q/p; if ( r < t1 ) return 0; else if ( r < t2 ) then t2 = r; } else if ( q < 0 ) return 0; return 1; }/∗Test∗/

char LB clip ( punkt ∗p1, punkt ∗p2 ) { float dx, dy; t1 = 0; t2 = 1; dx = p2−>x − p1−>x; if ( Test ( −dx, p1−>x − xmin ) ) if ( Test ( dx, xmax − p1−>x ) ) { dy = p2−>y − p1−>y;

if ( Test ( −dy, p1−>y − ymin ) ) if ( ( Test ( dy, ymax − p1−>y ) ) {

if ( t2 != 1 ) { p2−>x += t2∗dx; p2−>y += t2∗dy; } if ( t1 != 0 ) { p1−>x += t1∗dx; p1−>y += t1∗dy; } return 1;

} } return 0; }/∗LB clip∗/

Wartością funkcji jest 1 jeśli przynajmniej część odcinka jest widoczna i 0 w przeciwnym razie. Zasada działania algorytmu wiąże się z interpretacją prostych, na których leżą krawędzie okna, jako zbiorów algebraicznych. Funkcja f (x, y) = ax+by −c, której zbiorem miejsc zerowych jest taka prosta, jest dodatnia w półpłaszczyźnie zawierającej okno (to jest zapewnione przez odpowiedni wybór znaku współczynników a, b, c). Parametr q funkcji Test otrzymuje wartość tej funkcji w punkcie p1 kolejno dla każdej krawędzi okna. Po wykryciu, że przedział zmienności parametru t jest pusty, funkcja ma wartość 0. W przeciwnym razie, po obcięciu wszystkimi krawędziami okna, procedura oblicza punkty końcowe części odcinka widocznej w oknie (uwaga na kolejność obliczania tych punktów; w pewnej książce wykryłem błąd, polegający na zmianie kolejności).

Algorytm Lianga-Barsky’ego, podobnie jak algorytm Sutherlanda-Cohena, może być łatwo zmodyfikowaniy w celu obcinania odcinków do dowolnych wielokątów lub wielościanów wypu-kłych.

3.1.4. Obcinanie prostych

Jeśli mamy wyznaczyć część wspólną danej prostej i prostokątnego okna, to możemy użyć algorytmu Lianga-Barsky’ego. Opierając się na przedstawieniu prostej w postaci niejawnej, za pomocą równania liniowego ax + by = c, możemy to zadanie wykonać jeszcze trochę szybciej. W tym celu trzeba obliczyć wartości funkcji f (x, y) = ax+by−c w wierzchołkach okna, a następnie, badając znaki wartości funkcji f w tych punktach, wyznaczyć punkty przecięcia prostej tylko z tymi krawędziami okna, które są przez prostą przecięte. Zysk z takiego podejścia to kilka zaoszczędzonych działań arytmetycznych, co (w przypadku średnim) przekłada się na prawie o połowę krótszy czas działania. Ponieważ procedury obcinania należą do oprogramowania pod-stawowego w bibliotekach graficznych (często są one implementowane sprzętowo) i wywoływane wiele razy, więc każde ich przyspieszenie jest istotne.

W dokumencie Grafika komputerowa I – MIM UW (Stron 32-35)