Tietokonegrafiikan perusteet T-111.4300 3 op Luento 2: 2D Katselu Lauri Savioja 11/07 2D katselu / 1 Sisältö Ikkuna ja näyttöalue Viivanleikkaus ikkunaan Monikulmion leikkaus ikkunaan Tekstin leikkaus Erikoistapauksia 2D katselu / 2 1
Ikkunointi ja leikkaus Ongelma Halutaan käyttää ohjelmassa sovelluskohteeseen sopivia koordinaatteja, mutta piirtää sama kuva eri laitteilla, joilla on aivan erilainen koordinaatisto. Esim. karttasovelluksen perusyksikkönä metri kohteena 100 x 100 km maa-alue näyttölaitteen resoluutio 480 x 640 pikseliä, piirturin resoluutio 10000 x 7000 askelta. Ajatus: Irrotetaan kuvien määrittely niiden piirtämisestä. Luovutaan ohjelmassa laitekoordinaatistosta (DC) ja käytetään maailmankoordinaatistoa (WC). Y y X x World Coordinates (WC) Device Coordinates (DC) 2D katselu / 3 Katseluoperaatio Graafiset tulostusprimitiivit "piirtävät" kuviteltua maailmaa. Laitteelle kuva syntyy "katselemalla" maailmaa ikkunan läpi. Ikkunan ulkopuolelle jäävät osat leikataan pois. Jäljelle jääneet osat muunnetaan laitekoordinaatistoon. 2D katselu / 4 2
Ikkunan ja näyttöalueen suhteet Ikkunan () avulla olemme saaneet määritellyksi sen alueen "maailmasta", jonka pitäisi näkyä. Miten määrittelemme laitteen kuva-alueelta sen osa-alueen, jolle "näkymä" halutaan piirtää? Kuva-alue jaetaan osa-alueisiin, joita kutsutaan näyttöalueiksi (viewport), vrt. frame:t www-sivuilla Erityisesti vuorovaikutteisessa grafiikassa useat yhtäaikaiset näyttöalueet (viewport) ovat tärkeitä. 2D katselu / 5 Ikkuna-näyttöalue (jatkuu) Ikkuna-näyttöalue-muunnos yw yd WT VT WB WC WL WR Kuvaus maailmankoordinaatistosta (ikkunasta) kuva-alueen koordinaatistoon (näyttöalueelle): VR! VL x D = (x w! W L) + V WR! WL eli x D = a x W + b y D = c y W + d VT! VB yd = (yw! W B) + V missä a = (V R - V L ) / (W R - W L ) WT! WB b = V L - a W L (vast. c ja d) Ts. kukin piste vaatii 2 kertolaskua ja 2 yhteenlaskua. xw 2D katselu / 6 VB DC VL VR xd L B 3
Viivakuvion leikkaus ikkunaan Esim. viiden viivan ketjusta (1 polyline) jää jäljelle neljä viivaa (2 ketjua): polyline polyline1 polyline2 1 3 2 1 3 2 4 4 5 Viivakuvion kukin jana leikataan erikseen: Rasterilaitteilla leikkaus voi tapahtua juovakonversion yhteydessä (vain ikkunassa olevat pikselit piirretään). Mieluummin lasketaan ensin näkyvälle janan osalle uudet päätepisteet. 2D katselu / 7 Viivakuvion leikkaus (jatkuu) Vertaamalla janan päätepisteitä ikkunarajoihin saadaan nopeasti selville kolme vaihtoehtoa: 1) Viivan molemmat päätepisteet ikkunan sisällä => viiva kokonaan näkyvissä: PIIRRÄ 2) Viivan toinen päätepiste ikkunan sisällä, toinen ulkona => osa näkyvissä: LEIKKAA 3) Viivan molemmat päätepisteet ulkona a) => osa näkyvissä: LEIKKAA b) => viiva ulkona : UNOHDA Kuinka päästään nopeasti helppoihin tapauksiin? 2D katselu / 8 4
Viivanleikkaus (jatkuu) Cohen-Sutherland-algoritmi Pyritään välttämään viiva-reuna leikkausten laskeminen mahd. pitkälle Testataan voidaanko jokin viiva piirtää kokonaan Testataan voidaanko jokin viiva jättää kokonaan piirtämättä Leikataan viiva reunan kohdalta, siten, että osa siitä voidaan hyväksyä Jatketaan jokaiselle viivalle ed. askelta, kunnes jäljelle jäävät osat voidaan joko hyväksyä tai hylätä 2D katselu / 9 Viivakuvion leikkaus (jatkuu) Cohen-Sutherland-algoritmi: koodataan viivan P1, P2 molemmat päätepisteet neljällä bitillä, jotka kertovat, minkä ikkunarajojen (tai niiden jatkeitten) suhteen ollaan ulkopuolella: b1 1001 1000 1010 0001 0000 0010 b3 b2 b4 0101 0100 0110 Huomio #1 : ( Code (P1) = 0 ) and ( Code (P2) = 0 ) => viiva kokonaan sisällä : PIIRRÄ Huomio #2 : ( Code (P1) and Code (P2) ) <> 0 => viiva kokonaan saman rajan ulkopuolella : UNOHDA 2D katselu / 10 5
var Leikkaus-koodi (Cohen-Sutherland) : record xl, xr, yb, rt : real end; procedure Clip_line (x1, y1, x2, y2 : real); type edge = (left, right, bottom, top); outcode = set of edge; var c, c1, c2 : outcode; x, y : real; procedure code (x, y : real; var c : outcode); c := [ ]; if x <.xl then c := [left] else if x >.xr then c := [right]; if y <.yb then c := c + [bottom] else if y >.yt then c := c + [top]; end; code(x1, y1, c1); code(x2, y2, c2); while (((c1 <> [ ]) or (c2 <> [ ])) and (c1 * c2 = [ ])) do if c1 <> [ ] then c := c1 else c := c2; if left in c then { left edge crossed } x :=.xl; y := y1 + (.xl - x1) * (y2 - y1) / (x2 - x1); end else if right in c then { right edge crossed } x :=.xr; y := y1 + (.xr - x1) * (y2 - y1) / (x2 - x1); end else if bottom in c then { bottom edge crossed } y :=.yb; x := x1 + (.yb - y1) * (x2 - x1) / (y2 - y1); end else if top in c then { top edge crossed } y :=.yt; x := x1 + (.yt - y1) * (x2 - x1) / (y2 - y1); end; if c = c1 then x1 := x; y1 := y; code(x1, y1, c1) end else x2 := x; y2 := y; code(x2, y2, c2) end end; if (c1 = [ ]) and (c2 = [ ]) then showline(x1, y1, x2, y2); end; 2D katselu / 11 Viivanleikkaus (jatkuu) Kuinka monta kertaa ohjelman while-osa enintään suoritetaan? kukin suoritus sisältää yhden kerto- ja jakolaskun liukuluvuilla maksimi: 4 * ja 4 / operaatiota 2D katselu / 12 6
Viivanleikkausalgoritmit (jatkuu) Liang-Barsky-algoritmi: tarkastellaan janaa parametrimuodossa: p(u) = p 1 + u p = p 1 + u (p 2 - p 1 ) ; u [0..1] eli x(u) = x 1 + X * u = x 1 + (x 2 - x 1 ) * u y(u) = y 1 + Y * u = y 1 + (y 2 - y 1 ) * u ikkunan sisällä olo voidaan ilmaista epäyhtälöillä W left <= x(u) <= W right W bottom <= y(u) <= W top joista jokainen on muotoa p k u q k 2D katselu / 13 Viivanleikkaus (jatkuu) janan ja ikkunareunan leikkauspisteitä voidaan tutkia parametrin u suhteen, laskematta leikkauksen (x,y)-koordinaatteja: jos leikattava, niin lasketaan r = q k / p k, jota verrataan aikaisempiin janan päätepisteiden parametriarvoihin u 1 ja u 2 (aluksi 0 ja 1) p:n etumerkistä ja vertailuista r:n ja u 1,2 :n välillä saadaan selville hylättävät viivat leikkauspisteet lasketaan vasta lopuksi u:n perusteella, jos ikkunan sisälle jäi mitään vertailu Cohen-Sutherland-algoritmiin: kaikki neljä leikkausta lasketaan aina, jollei janaa hylätä ikkunan ulkopuolisena leikkauksen laskeminen vaatii vain jakolaskun; toisaalta neljä kertolaskua tarvitaan lopullisten koordinaattien laskennassa summa summarum: (a) algoritmit voittavat toisensa eri tilanteissa (b) neljää leikkauslaskentaa ei voi välttää 2D katselu / 14 7
Taas uusi viivanleikkausalgoritmi Geometrinen puolitushaku (midpoint subdivision algorithm): tutkitaan janan päätepisteitä kuten edellä: jos kokonaan sisällä tai ulkona => PIIRRÄ tai UNOHDA muuten jaa viiva puoliksi ja toista sama rekursiivisesti kummallekin puolikkaalle tehokasta, koska: puolituspisteen haku kokonaislukukoordinaatistossa vaatii vain yhteenlaskun ja shift:in: x m = ( x 1 + x 2 ) / 2 y m = ( y 1 + y 2 ) / 2 rekursio voidaan toteuttaa iteraationa laitetasolla toistojen maksimimäärä = log 2 (ikkunan resoluutio) näkyvien osien piirtäminen voidaan suorittaa lopuksi yhdellä kertaa, kun leikkauspisteet on haettu. 2D katselu / 15 Esim. Geometrinen puolitus (jatkuu) 1 1/2 1 2 1/4 1/8 3 4 2D katselu / 16 8
Monikulmioalueen leikkaus Alueen täyttöalgoritmit edellyttävät, että rajat muodostavat yhtenäisen sulkeutuvan monikulmion => pelkkä erillisten viivojen leikkaus ei riitä, vaan kuvio on suljettava lisäviivoilla ikkunarajoja pitkin Esim. fill-area lisäviiva 2D katselu / 17 Monikulmion leikkaus (jatkuu) Sutherland-Hodgman-algoritmi Idea: on helppo suorittaa leikkaus yhden (äärettömän) suoran suhteen kerrallaan. Esim. clip left Huom! clip top clip right clip bottom Huom! 2D katselu / 18 9
Monikulmion leikkaus (jatkuu) Sutherland-Hodgman-algoritmin idea: monikulmion esitys on nurkkapisteiden jono (stream) kutakin pistettä jonossa verrataan ikkunareunaan: sisällä => säilytä jonossa ulkona => unohda aina, kun ikkunan reuna ylitetään (perättäiset pisteet eri puolilla), lisätään leikkauspiste jonoon myös viimeisen ja ensimmäisen pisteen väli tutkitaan, jotta kuvio sulkeutuisi 2D katselu / 19 Sutherland-Hodgman (jatkuu) esim. p1 p2 p3 p4 p5 p6 p7 ( p1) => p1' p2 p3 p3' p4' p5 p5' ( p1') p1 p2 p1' p2 p7 p4 p3 p3' p3 p4' p5 p5 p6 p5' uusi pistejono siirretään seuraavan ikkunarajan suhteen leikkaavalle proseduurille tuloksena aina yhtenäinen sulkeutuva reunaviiva, vaikka alue pilkkoutuisikin => voi tulla ylimääräisiä reunoja, kuten p3' p4' Kuinka toimitaan, jos näitä halutaan välttää? 2D katselu / 20 10
Tekstin leikkaus "Kaikki tai ei mitään" -periaate kolmella eri tasolla toteutettuna: a) koko merkkijono tai sana b) yksi kirjain kerrallaan c) kirjaimen jokainen viiva tai pikseli 2D katselu / 21 Erikoistapaukset (jatkuu) Reiälliset monikulmiot moniosaisia tietorakenteita, esim. listarakenteita ((p1 p2 p3 p4 p5 p6) (q1 q2 q3 q4)) tai yhdistetään erilliset reunat apuviivoilla yhdeksi p1 p2 p3 q2 q1 q4 q3 q2 p3 p4 p5 p6 Huom! kiertosuunta, jana p3 q2 kahdesti Mielivaltaisen muotoiset ikkunan reunaviivat (stencil) esim. PostScript-kielessä 2D katselu / 22 11