Professional Documents
Culture Documents
Racunarska Grafika
Racunarska Grafika
Racunarska Grafika
2
K U CA : Radojke Laki 15/][ c 11050 Beograd Srbija, YUGOSLAVIA
KOLA : Narodnog Fronta 37 11000 Beograd Srbija, YUGOSLAVIA I NTERNET: mailto:brcha@geocities.com http://www.geocities.com/SiliconValley/Campus/3732/Graka.html
Sadraj
1 Uvod 2 Osnovni pojmovi 2.1 Osnovne operacije . . . . . . . . . . . . . . . . . . . . . . 2.1.1 Denicije primitivnih funkcija u C-u . . . . . . . 2.2 Proirenje ekrana . . . . . . . . . . . . . . . . . . . . . . 2.2.1 Denicija funkcija za realne koordinate . . . . . 2.2.2 Implementacija nkcija za realne koordinate . . 2.2.3 Krive . . . . . . . . . . . . . . . . . . . . . . . . . 2.2.3.1 Program za crtanje kruga kao 100-ugla 7 9 9 9 11 12 13 14 15
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
3 2D Prostor 17 3.1 Geometrija 2D prostora . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 3.1.1 Prave . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 3.1.2 Vektori pravca . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 3.1.3 ta je unutra, a ta napolju? . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 3.2 2D transformacije . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 3.2.1 Kompozicije 2D Transformacija . . . . . . . . . . . . . . . . . . . . . . . . . . 22 3.2.2 Transformacija Prozor->V IEWPORT . . . . . . . . . . . . . . . . . . . . . . . . 24 3.2.3 Denicija funkcija za matri ne transformacije dvodimenzionalnog prostora 24 c 3.2.4 Implementacija funkcija za matri ne transformacije dvodimenzionalnog prosc tora . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 3.3 Objekti u 2D gra kom prostoru . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 c 3.3.1 Denicija struktura i funkcija za modeliranje objekata . . . . . . . . . . . . . 27 3.3.2 Implementacija funkcija za modeliranje objekata . . . . . . . . . . . . . . . . 28 3.3.3 Koordinatni sistem gledaoca . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 3.3.3.1 Denicija funkcija za manipulisanje OBSERVER CSom . . . . . . . . 29 3.3.3.2 Implementacija funkcija za manipulisanje OBSERVER CSom . . . . 30 3.3.4 Konstrukcija objekata . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 3.3.4.1 Denicija funkcija za deniciju objekata . . . . . . . . . . . . . . . 32 3.3.4.2 Implementacija funkcija za deniciju objekata . . . . . . . . . . . . 32 3.4 Jo neke korisne stvari u 2D prostoru . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 3.4.1 L INE C LIPPING (granice prikaza linija) . . . . . . . . . . . . . . . . . . . . 34 3.4.1.1 Denicija funkcija i promenljivih za LINE CLIPPING / BLANKING . 36 3.4.1.2 Implementacija funkcija za LINE CLIPPING / BLANKING . . . . . . 37 3.4.2 Orjentacija konveksnog mnogougla . . . . . . . . . . . . . . . . . . . . . . . 39 3.4.3 Presek dva konveksna mnogougla . . . . . . . . . . . . . . . . . . . . . . . . 41 A Fajl GRAPH U TILITIES A.1 Denicija funkcija - GRAPH U TILITIES . H . . . . . . . . . . . . . . . . . . . . . . . . . A.2 Implementacija funkcija - GRAPH U TILITIES . C . . . . . . . . . . . . . . . . . . . . . . 3 45 45 46
SADRAJ
51
Slike
2.1 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17 Apsolutni i koordinatni sistem ekrana (prozora) . . . . . . . . . . . . . . . . . . . . Vektor pravca . . . . . . . . . . . . . . . . . . . . . . . Konveksan n-tougao . . . . . . . . . . . . . . . . . . . Rotacija ta ke . . . . . . . . . . . . . . . . . . . . . . . c Transformacija smicanja (SHEAR) . . . . . . . . . . . . Originalna pozicija objekta . . . . . . . . . . . . . . . . Transliran objekat za vektor T sa slike 3.5 - T (;x ;y ) Objekat rotiran za 30 - R( = 30 ) . . . . . . . . . . . Objekat vra en na mesto - T (x y ) . . . . . . . . . . . . c Transformacija prozor -> VIEWPORT . . . . . . . . . . Prikaz se enja linija . . . . . . . . . . . . . . . . . . . c Podela ravni produenjem stranica pravougaonika . Deo direktno orjentisanog mnogougla . . . . . . . . . Deo retrogradno orjentisanog mnogougla . . . . . . . Mnogouglovi A i B (osen en je trenutni presek) . . c Prvi korak: Se enje o stranicu 3-1 mnogougla B . . . . c Drugi korak: Se enje o stranicu 1-2 mnogougla B . . . c Tre i korak: Se enje o stranicu 2-3 mnogougla B . . . c c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 18 19 21 22 23 23 23 24 24 35 35 40 40 42 42 42 43
SLIKE
Glava 1
Uvod
Kompjuterska graka je relativno nova grana ra unarstva koja je u poslednje vreme u hiperekspanzc iji. Od pojave Apple R -ovog Macintosh R -a i MIT-ovog X Window System R -a po etkom osc amdesetih, kompjuterska graka se ubrzano razvija i nadograduje. Sada se ve kompjuter skoro c i ne moe zamisliti bez dobre video i muzi ke kartice, velikog monitora, jakih zvu nika, modema c c i nekog gra kog operativnog sistema (naalost uglavnom Microsoft R Windows R -a 95/98), a c ni fabrika koja ne nadgleda rad maina vizualizuju i ih na kompjuterima. Shodno tome, komc pjuterska graka bi mogla da se denie kao igra ka ili ukras bez koga se vie ne moe. c Iako je kompjuterska graka hyper-moderna nauka, njeni koreni lee duboko u prolosti, medu prvim covekovim pokuajima da neto razume, da neto otkrije. Logi no, mislim na ge c ometriju i matematiku, jer kompjuterska graka nisu samo lepe slike, animacije, kompjuterske igre i sl. koje vidimo na ekranima (ili VR-lemovima). Naprotiv, kompjuterska graka je vrlo sloen matemati ki aparat koji koristi znanja iz geometrije, i sinteti ke i analiti ke, linearne algec c c bre, trigonometrije, pa cak i iz estetike.
GLAVA 1. UVOD
Glava 2
Osnovni pojmovi
2.1 Osnovne operacije
Dva osnovna pristupa kompjuterskoj graci su vektorski i rasterski pristup. Vektorski pristup je u neku ruku na viem nivou, i zasnovan je na denisanju objekata pomo u vektora. Moglo bi se c re i da su dve osnovne operacije koje izvrava gra ki uredaj u vektorskom pristupu komjuterc c skoj graci: 1. moveto(x,y) pomera kurzor na poziciju (x,y)1 2. lineto(x,y) crta liniju do pozicije (x,y)2 Rasterski pristup graci je zasnovan na denisanju objekata pomo u matrice PIXELa (ta aka). c c Svaki PIXEL ima celobrojne koordinate i svoju boju. Zbog toga se rasterski pristup naziva i BITMAP pristup ( MAP a BIT ova). Boja se uglavnom prikazuje kao uredena trojka brojeva koji pred stavljaju intenzitet crvene, zelene i plave boje u RGB(R ED -G REEN -B LUE ) sistemu3 . Zbog cinjenice da se vektorski pristup moe lako implementirati unitar rasterskog, i cinjenice da je 90% gra kih uredaja zasnovano na rasterskom pristupu, ja cu se samo na njega i ograni iti. c c P IXEL cu da modeliram kao uredeni par celobrojnih koordinata (x y ) kome cu da dodeljujem broj koji predstavlja indeks boje. Boje cu da prikazujem kao uredenu trojku brojeva iz skupa 0 1](r g b) kome cu da dodeljujem indeks unutar palete boja (vidi algoritam 2.1.1).
Fajl: primitives.h */ Projekat: Osnovi raunarske grafike c Organizacija: Matematika gimnazija u Beogradu c Datum: 1999/02/18 Autor: Filip S. Bri IVc c c Email: brcha@geocities.com
A DOBE R P OST S CRIPT R -u: x y moveto
A DOBE R P OST S CRIPT R -u: x y moveto jo i CMY(C YAN -M AGENTA -Y ELLOW ) sistem, HSV(H UE -S ATURATION -VALUE, ponekad nazivan i HSB, B=B RIGHTNES ) sistem, HLS(H UE -L IGHTNESS -S ATURATION )
3 Postoji
10
* URL: http://www.geocities.com/SiliconValley/Campus/3732/Grafika.html */ #ifndef __PRIMITIVES_H #define __PRIMITIVES_H /* ISO C #include /* ISO C #include /* ISO C #include /* ISO C #include /* ISO C #include /* ISO C #include /* ISO C #include /* POSIX #include Standatd: <errno.h> Standard: <assert.h> Standard: <ctype.h> Standard: <math.h> Standard: <signal.h> Standard: <stdio.h> Standard: <string.h> Standard: <unistd.h> 4.1.3 Errors <errno.h> */ 4.2 DIAGNOSTICS <assert.h> */ 4.3 CHARACTER HANDLING <ctype.h> */ 4.5 MATHEMATICS <math.h> */ 4.7 SIGNAL HANDLING <signal.h> */ 4.9 INPUT/OUTPUT <stdio.h> */ 4.11 STRING HANDLING <string.h> */ 2.10 Symbolic Constants <unistd.h> */
/* memory allocation utilities (Fusion Systems inc.) */ #include <allocUtil.h> /* stack of any type (Fusion Systems inc.) */ #include <stack.h> /* boolean type definition (Fusion Systems inc.) */ #include <bool.h> /* Maksimalna veliina poligona */ c #define maxPoly 100 char *programName; /* Ime programa (prozora) */ int numColors; /* Broj boja <- beginGraphics() */ int nXpixels,nYpixels; /* Veliina ekrana/viewport-a <- beginGraphics() */ c /* Struktura pixel-a = ureeni par (x,y) */ d struct pixelVector{ int x,y; }; int currentColor; /* Tekua boja */ c float *red,*green,*blue; /* Tabela boja, nizovi od <numColors> * elemenata <- beginGraphics */ struct pixelVector currentPixel; /* Tekua pozicija na ekranu */ c /* Osnovne funkcije(primitive) */ void beginGraphics(void); /* Inicijalizacija grafikog moda */ c void updateGraphics(void); void endGraphics(void); /* Kraj rada sa grafikom */ void clearDisplay(void); /* Brisanje ekrana u tekuu boju */ c void setColor(int color); /* Namesti tekuu boju */ c void setPixel(struct pixelVector pixel); /* Idi na poziciju pixel i * oboj je u tekuu boju */ c void movePixel(struct pixelVector pixel); /* Idi na poziciju pixel */
11
void linePixel(struct pixelVector pixel); /* Nacrtaj liniju od tekue c * pozicije do pixel-a */ void polyPixel(int n,struct pixelVector poly[]); /* Nacrtaj poligon = * mnogougao (n-tougao) */ void setrgb(int i,float r,float g,float b); /* Definii i-tu boju * kao (r,g,b) */ void flip(void); /* Iz grafikog u tekstualni mod i obrnuto c * bez brisanja sadraja ekrana */ /* Stil linije: * width - irina * lineStyle - LineSolid, LineOnOffDash, LineDoubleDash * capStyle - kraj linije: CapNotLast, CapButt, CapRound, CapProjecting * joinStyle - nain povezivanja: JoinMitter, JoinRound, JoinBevel c * Za detalje pogledati literaturu za Xlib */ void setLineStyle(unsigned int width,int lineStyle, int capStyle,int joinStyle); #define SET 0 #define OR 1 #define AND 2 #define XOR 3 void setLineType(int type); bool keyPressed(void); /* Da li je pritisnut taster */ bool displayExposed(void); /* Da li je pokvaren prikaz (interno) */ int getChar(void); /* Proitaj karakter ili -1, ako nita nije pritisnuto */ c #endif /* __PRIMITIVES_H */ /* Kraj fajla primitives.h */
12
y
(xmax-1, ymax-1)
y
sirina
Slika 2.1: Apsolutni i koordinatni sistem ekrana (prozora) gramima, dulima, njutnima, veberima, teslama, svetlosnim godinama, ili u bilo kojoj drugoj jedinici, moramo da deniemo koecijent transformacije iz KS prozora u KS pogleda. Zato se denie xyscale kao xmax;1 (da bi prozor stao u pogled ceo po irini). Sada dakle moemo densirina isati funkciju transformacije iz KS prozora u KS pogleda kao:
visina
(2.1)
#include "primitives.h" /* Broj */ #define pi 3.1415926535 /* je najvea mogua preciznost */ c c #define epsilon 0.000001
13
void startGraphics(float aHoriz); /* beginGraphics na viem nivou */ void stopGraphics(void); /* = endGraphics */ int fx(float x); /* x = fx (x) */ int fy(float y); /* y = fy (y ) */ void moveTo(struct vector2D pt); /* movePixel */ linePixel */ void lineTo(struct vector2D pt); /* void polyFill(int n,struct vector2D polygon[]); /* polyPixel */ /* Glavni deo programa - umesto main */ int graphMain(int argc,char *argv[]); #endif /* __WINDOW2VPORT_H */ /* Kraj fajla <window2vport.h> */
void startGraphics(float aHoriz){ beginGraphics(); horiz = aHoriz; vert = horiz*nYpixels/nXpixels; xyscale = (nXpixels-1)/horiz; } void stopGraphics(void){ endGraphics(); } int fx(float x){ return (int)(x*xyscale+nXpixels*0.5-0.5); } int fy(float y){ return (int)(-y*xyscale+nYpixels*0.5-0.5); }
14 void moveTo(struct vector2D pt){ struct pixelVector pixel; pixel.x = fx(pt.x); pixel.y = fy(pt.y); movePixel(pixel); } void lineTo(struct vector2D pt){ struct pixelVector pixel; pixel.x = fx(pt.x); pixel.y = fy(pt.y); linePixel(pixel); }
void polyFill(int n,struct vector2D polygon[]){ int i; struct pixelVector *pixelPolygon; if(n>2){ pixelPolygon = (struct pixelVector*) safeCalloc((unsigned)n,sizeof(struct pixelVector)); for(i=0;i<n;i++){ pixelPolygon[i].x = fx(polygon[i].x); pixelPolygon[i].y = fy(polygon[i].y); } polyPixel(n,pixelPolygon); safeFree(pixelPolygon); } } int main(int argc,char *argv[]){ float horizontalSize; int programResult; printf("nnUnesite sirinu prozora: "); scanf("%f",&horizontalSize); startGraphics(horizontalSize); programResult = graphMain(argc,argv); stopGraphics(); return programResult; } /* Kraj fajla <window2vport.c> */
2.2.3 Krive
Sada verovatno mislite: Dobro, imamo ta ke, linije, poligone, prozore i poglede, imamo virc tualni prostor, ali ta se dogodilo sa krivim linijama ?!. E, pa, postoji vie na ina da se i one c prikau. Mogu da se crtaju PIXEL po PIXEL, to najbolje aproksimira tu krivu na ekranu, a mogu i da se interpretiraju kao n-tougao ili n povezanih linija, gde je n veliki broj. Ovaj drugi na in je c laki za implementaciju, zgodniji za geometrijske transformacije, a koriste ga mnogi eminentni programi za graku (kao to je A UTODESK R A UTO CAD R ), pa cu se opredeliti za njega (primer: program 2.2.3.1 koriste i taj princip crta krug kao 100-ugao). c
15
void circle(float r){ float theta,thinc; int i; struct vector2D pt; theta = 0; thinc = 2*pi/100; /* Idi na poetnu taku */ c c pt.x = r; pt.y = 0.0; moveTo(pt); /* Nacrtaj stranice 100-ugla */ for(i=0;i<100;i++){ theta += thinc; pt.x = r*cos(theta); pt.y = r*sin(theta); lineTo(pt); } } int graphMain(int argc,char *argv[]){ float r; struct vector2D pt; printf("nnUnesite poluprecnik kruga: "); scanf("%f",&r); pt.x = 0; pt.y = 0; moveTo(pt); pt.x = 1; pt.y = 1; lineTo(pt); circle(r); while(getChar() != q); return 0; }
16
Glava 3
2D Prostor
3.1 Geometrija 2D prostora
3.1.1 Prave
Kao za jedan od osnovnih elemenata u graci, za pravu, mora se na i pogodna analiti ka reprezentacija. c c Uobi ajeni oblik y = kx + n (ili ax + by + c = 0) ovde nije najzgodniji. Mnogo je lake prikazati c ! ! pravu kao linearnu kombinaciju vektora poloaja dveju poznatih ta aka te prave (;1 i ; ): c p p2
;( ! p
to je ekvivalentno sa
) = (1
! p ! ; );1 + ;2 2 R p ;1 + (;2 ; ;1 ): ! p p ! ! p
(3.1)
;( ! p
)=
(3.2)
do ( ! ! p q gde je = razdaljina od p1p1 dop;2 ) , a ; ( ) proizvoljna ta ka na pravoj. Vektor ; (3.3) predstavlja c ! ! razdaljina od ; p ;1 bazni vektor (BASE VECTOR). ! vektor pravca (DIRECTION VECTOR), a vektor p ! ! ! } ! ! } p q ! r s Sada moemo da reimo problem preseka dve prave, ;1 ( ) = ; + ; i ;2 ( ) = ; + ; koji se svodi na
; ( ) = ;1 + ; ! ! ! p p q ; = ;2 ; ;1 ! p p ! ! q
(3.3)
;1 ( ! }
odnosno na
)=
;2 ( ! }
(3.4)
; + ; =; + ;: ! ! ! ! p q r s
Rastavljanjem (3.5) na x i y ose dobija se:
(3.5)
xp + xq = xr + xs yp + yq = yr + ys
to je ekvivalentno sa
(3.6)
xq ; xs = xr ; xp : yq ; ys = yr ; yp
17
(3.7)
18
GLAVA 3. 2D PROSTOR
Slika 3.1: Vektor pravca Mnoenjem prve jedna ine sistema (3.7) sa ys , a druge sa c se
(
odakle je
=
(3.9)
Presek pravih je
; + ;: ! ! p q
(3.10)
Funkcija koja ra una presek dve prave u dvodimenzionalnom prostoru je LINE I NTERSECT 2D() c !!! iz fajla GRAPH U TILITIES . H /. C (dodatak A na strani 45). Argumenti funkcije su vektori ; , ; , ; p q r ; i pokaziva na vektor preseka tih pravih (jedna ine (3.10) i (3.9)). ! i s c c
! Ako pogledamo jo jednom jedna inu prave (3.3), primeti emo da ; predstavlja, kao to sam c c q ! ! ve rekao, vektor pravca prave ; ( ) (vidi sliku 3.1). Ako je ugao izmedju x-ose i vektora ; , c p q ! ! ! koordinate vektora ; su j; j cos i j; j sin , pa ugao moemo da izra unamo iz q q c q
qy qx
= tan
(3.11)
To radi funkcija ANGLE () iz fajla GRAPH U TILITIES . H /. C (dodatak A na strani 45), kojoj se kao ! q argumenti daju koordinate vektora ; , a vra a ugao (3.11). c
f (x y) ax + by + c:
(3.12)
19
pi+1
pi
! q (x y ) = ; + ; p1 ! ; = ;2 ; ;1 = (xq = x2 ; x1 yq = y2 ; y1 ) : ! p p ! ! q
x = x1 + y = y1 + xq yq :
(3.13)
yxq ; xyq = y1 xq + yq xq ; x1 yq ; xq yq
to je ekvivalentno sa
(3.15)
xq y ; yq x ; (y1 xq ; x1 yq ) = 0
odnosno
(3.16)
xq (y ; y1 ) ; yq (x ; x1 ) = 0:
Zamenom xq
=
(3.17)
x2 ; x1 i yq = y2 ; y1 dobija se
( 2
(3.18)
pa je dakle
! ! c analiti ki oblik funkcije prave kroz ta ke ; i ; . Ta ke za koje je f (x y ) = 0 pripadaju toj pravoj, c c p1 p2 a dve ta ke (x1 y1 ) i (x2 y2 ) su sa iste strane akko su f (x1 y1 ) i f (x2 y2 ) istog znaka1 . c Ako imamo konveksan n-tougao zadat svojim uzastopnim temenima (vidi sliku 3.2): ;i ! p
(
f (x y)
(3.19)
xi yi ) i = ;;;;! o n;1
(3.20)
y) ax
1 isto vai i za konveksne krive, samo jje njima druga ija funkcija, npr: f (x c krive drugog reda
2 + by 2 + cxy + dx + ey + f za
20
GLAVA 3. 2D PROSTOR
moemo da odredima ta je unutar n-tougla, a ta van njega. Funkcija koja odgovara i-toj stranici n-tougla glasi
! ! uz napomenu da je ; = ; . Ta ka (x y ) je unutar n-tougla akko je fi (x y ) > 0 i = 0 n ; 1 pn p0 c ako su temena zadata u pozitivnom matemati kom smeru (suprotno od kazaljke na satu), a ako c su zadata u suprotnom smeru (u smeru kazaljke na satu), akko je fi (x y ) < 0. To ce kasnije biti veoma zna ajno za odredivanje ta je u pozadini u trodimenzionalnom koordinatnom sistemu. c
3.2 2D transformacije
Kad sam spominjao Apsolutni KS i KS prozora, rekao sam da je prozor (i njegov KS) denisan u odnosu na Apsolutni KS. Ali zato bismo se ograni ili na samo jedan poloaj prozora. Bolje c bi bilo kad bismo mogli da etamo taj prozor kroz na virtuelni prostor i razgledamo stvari iz svih uglova. Za to ce biti neophodne razno ravanske (za sada) transformacije, koje se svode na kombinacije translacije, rotacije i skaliranja (menjanja razmere). Deniimo ih: Translacija ta ke c
fi (x y)
;;;;!
(3.21)
(3.22)
ili vektorski
;0 = ; + ; ! P T P ! !
x0 y0
=
(3.23)
ili matri no c
x y
dx dy
(3.24)
x0 = sxx y0 = sy y
ili matri no c
(3.25)
x0 y0
ili
sx
0
sy
x y
(3.26)
; = S (sx sy ); ! ! P P
(3.27)
gde je S (sx sy ) matrica iz jedna ine (3.26). c Rotacija je ve malo komplikovanija. Sa slike 3.3se vidi da je c
x = r cos y = r sin
a takode i da je
(3.28)
x0 = r cos( y0 = r sin(
+ +
)= )=
r cos r sin
cos cos
; r sin
r cos
sin sin
(3.29)
3.2. 2D TRANSFORMACIJE
21
P(x,y)
P(x,y)
(3.30)
x0 y0
ili gde je R(
cos sin
; sin
cos
x y
(3.31)
;0 = R( ); ! ! P P
)
(3.32)
Da bi se transformacije mogle lake kombinovati, potrebno je sve prikazati preko proizvoda ili preko zbira. Poto se skaliranje i rotacija ne mogu (ili vrlo teko mogu?) prikazati pomo u zbira c nekakvih matrica ili vektora, pokuajmo da translaciju prikaemo kao proizvod. Name e se da c vektor ta ke proirimo jo jednim, tre im poljem sa vredno u 1, a matrice transformacija da c c c proirimo na 3x3. Tada dobijamo homogene koordinate ta aka: c
2
PH = 4
i unikovane transformacije: Translacija:
x y
1
3 5
(3.33)
TH (dx dy ) = 4
Skaliranje:
2
1 0 0
0 1 0
dx dy
1
3 5
(3.34)
SH (sx sy ) = 4
sx
0 0
sy
0
0 0 1
3 5
(3.35)
22
GLAVA 3. 2D PROSTOR
Objekat
Shear X
Slika 3.4: Transformacija smicanja (SHEAR)
Shear Y
Rotacija:
RH (
)=
4 sin
0
cos
; sin
cos 0
0 0 1
3 5:
(3.36)
O igledno je da ovime nisu iscrpljene sve mogu e transformacije. Postoji jo i transformacija c c smicanja (SHEAR) po x i po y osi (vidi sliku 3.4):
2
SHx (a) = 4
i
2
1 0 0
0 0 1
3 5
1 0
(3.37)
SHy (b) = 4 b
3.2.1 Kompozicije 2D Transformacija
1 0
0 1 0
0 0 1
3 5:
(3.38)
Da bi se utedelo vreme, umesto da se na objekat (ta ku) primenjuje vie matrica transformacija c za redom, bolje je izra unati rezultuju u matricu i samo nju i primeniti. Na primer, problem c c rotiranja objekta oko neke ta ke P nije elementaran (ve predviden matricama T (dx dy ), S (sx sy ), c c R( ), SHx (a) i SHy (b)), ve se moe prikazati kao kombinacija tri elementarne transformacije: c 1. Translacija za vektor ; P - ta ka P ide u koordinatni po etak (vidi sliku 3.5 za po etni izgled c c c i sliku 3.6 za izgled posle translacije) 2. Rotacija za neki ugao (vidi sliku 3.7) 3. Translacija za vektor (vidi sliku 3.8)
; !
Kompozicija ovih matrica se vri u obrnutom poretku od izvravanja transformacija (jer se novi ; ! ; ! poloaj ta ke ra una kao P 0 = M3 3 P , a operacija mnoenja matrica nije komutativna), pa je c c tako rezultuju a matrica c
R = T (x y) R(
T (;x ;y)
(3.39)
3.2. 2D TRANSFORMACIJE
23
T(-
) x,-y P(x,y)
P(x,y)
;y)
P(x,y)
= 30 )
24
GLAVA 3. 2D PROSTOR
P(x,y)
y)
v Najzad smesten na svoju finalnu poziciju D
A Prozor u WCSu x x u
C b) c) d) u
a)
T (;xmin ymin ) - slika 3.9 pod b) min S umax ;umin vmax ;vmin - slika 3.9 pod c) xmax ;x ymax ;ymin T (umin vmin ) - slika 3.9 pod d) MW 2V
=
pa je rezultuju a matrica c
v ;v T (umin vmin ) S umax ; umin ymax ; ymin xmax ; xmin max min
T (;xmin ;ymin ):
(3.40)
3.2. 2D TRANSFORMACIJE
25
* Projekat: Osnovi raunarske grafike c * Organizacija: Matematika gimnazija u Beogradu c * Datum: 1999/02/18 * Autor: Filip S. Bri IVc c c * Email: brcha@geocities.com * URL: http://www.geocities.com/SiliconValley/Campus/3732/Grafika.html */ #ifndef __MATRIX2D_H #define __MATRIX2D_H #include "window2vport.h" /* tip trans2D i njemu odgovarajui "malloc()" i "free()" */ c typedef double** trans2D; trans2D initTrans2D(); void finishTrans2D(trans2D); /* 2D matrine transformacije koordinatnog poetka: */ c c void translate2D(float dx,float dy,trans2D T); /* Translacija za (dx~ dy ) */ void scale2D(float sx,float sy,trans2D T); /* (1~ 1) 7! (sx~ sy ) */ void rotate2D(float theta,trans2D T); /* Koordinatne ose se rotiraju za 6 void compose2D(trans2D A,trans2D B,trans2D C); /* C = A B */ #endif /* __MATRIX2D_H */ /* Kraj fajla <matrix2D> */
*/
/* Alociranje memorije za trans2D */ trans2D initTrans2D(){ return dmatrix(1,3,1,3); /* Iz "liballocUtil.so" by Fusion Systems */ } void finishTrans2D(trans2D T){ assert(T!=NULL); return free_dmatrix(T,1,3,1,3); /* Iz "liballocUtil.so" by Fusion Systems */ }
26
GLAVA 3. 2D PROSTOR
/* 2D matrine transformacije koordinatnog poetka: */ c c /* Translacija za (dx~ dy ) */ void translate2D(float dx,float dy,trans2D T){ int i,j; assert(T!=NULL); for(i=1;i<=3;i++){ for(j=1;j<=3;j++) T[i][j] = 0.0; T[i][i] = 1.0; } T[1][3] = -dx; T[2][3] = -dy; } /* (1~ 1) 7! (sx~ sy ) */ void scale2D(float sx,float sy,trans2D T){ int i,j; assert(T!=NULL); for(i=1;i<=3;i++) for(j=1;j<=3;j++) T[i][j] = 0.0; T[1][1] = sx; T[2][2] = sy; T[3][3] = 1.0; } */ /* Koordinatne ose se rotiraju za 6 void rotate2D(float theta,trans2D T){ int i; float c,s; assert(T!=NULL); for(i=1;i<=3;i++){ T[i][3] = 0.0; T[3][i] = 0.0; } T[3][3] = 1.0; c = cos(theta); s = sin(theta); T[1][1] = c; T[2][2] = c; T[1][2] = s; T[2][1] = -s; } /* C = A B */ void compose2D(trans2D A,trans2D B,trans2D C){ int i,j,k; float ab; assert(A!=NULL); assert(B!=NULL); assert(C!=NULL); for(i=1;i<=3;i++) for(j=1;j<=3;j++){
27
#include "matrix2D.h" /* Maksimalan broj taaka, linija, c #define maxVertices 400 #define maxLines 400 #define maxFacets 400 #define maxList 2000
FACET a
i elemenata liste */
struct linePoints{ int front,back; /* Poetna i krajnja taka linije */ c c }; /* Prvi slobodan element liste FACETa */ int firstFreeListElement; /* Trenutan broj taaka, linija i FACETa */ c int nVertices,nLines,nFacets; /* Take u pozicijama ACTUAL , OBSERVER i SETUP */ c struct vector2D actual[maxVertices],observer[maxVertices],setup[maxVertices]; /* Linije van FACETa */
28
GLAVA 3. 2D PROSTOR
struct linePoints line[maxLines]; /* i-ti FACET: * boja: facetColor[i] ~ * take: facetList[facetFirst[i]+j], j = 0 (facetSize i] ; 1) c */ int facetColor[maxFacets]; /* Boje FACETa */ int facetFirst[maxFacets]; /* Poetci FACETa */ c int facetList[maxList]; /* Lista taaka u FACETima */ c int facetSize[maxFacets]; /* Veliine FACETa */ c /* KS gledaoca - OBSERVER CS (OCS) */ float alpha; /* Ugao, u odnosu na x-osu, pod kojim se gleda */ struct vector2D eye; /* Pozicija gledaoca (oka) */ struct vector2D eyeScale; /* Odnos x, odn. y koordinata sistema */ trans2D toObserver; /* Transformacija iz ACTUAL u OBSERVER KS */ /* Transformacija v u (*w) preko transformacije A */ void transform(struct vector2D v,trans2D A,struct vector2D *w); /* Jo jedna zamena za main() */ int sceneMain(int argc,char *argv[]); #endif /* __MODEL2D_H */ /* Kraj fajla <model2D.h> */
/* Transformacija v u (*w) preko transformacije A * ulaz: v,A * izlaz: w */ void transform(struct vector2D v,trans2D A,struct vector2D *w){ w->x = A[1][1]*v.x+A[1][2]*v.y+A[1][3]; w->y = A[2][1]*v.x+A[2][2]*v.y+A[2][3]; } int graphMain(int argc,char *argv[]){ int result; firstFreeListElement = 0; nVertices = nLines = nFacets = 0; toObserver = initTrans2D(); result = sceneMain(argc,argv); /* Nova zamena za main() */ finishTrans2D(toObserver); return result;
29
#include "model2D.h" /* Nalaenje transformacije iz ACTUAL u OBSERVER KS */ void findA2O(void); /* Definicija OBSERVER KSa */ void look2D(void); /* Transformacija taaka iz ACTUAL u OBSERVER KS */ c void observe(void); /* Crtanje linija i FACETa */ void drawIt(void); void redraw(void); #endif /* __DISPLAY2D_H */ /* Kraj fajla <display2D.h> */
GLAVA 3. 2D PROSTOR
DISPLAY 2D. C /* Fajl: <display2D.c> */ /* * Projekat: Osnovi raunarske grafike c * Organizacija: Matematika gimnazija u Beogradu c * Datum: 1999/02/18 * Autor: Filip S. Bri IVc c c * Email: brcha@geocities.com * URL: http://www.geocities.com/SiliconValley/Campus/3732/Grafika.html */ #include "display2D.h"
ACTIVE
OBSERVER
KS */
A = initTrans2D(); B = initTrans2D(); C = initTrans2D(); if(!toObserver) toObserver = initTrans2D(); translate2D(eye.x,eye.y,A); rotate2D(alpha,B); compose2D(B,A,C); scale2D(eyeScale.x,eyeScale.y,A); compose2D(C,A,toObserver); finishTrans2D(C); finishTrans2D(B); finishTrans2D(A); } /* Definicija OBSERVER KSa */ void look2D(void){ printf("nnInicijalizacija observer sistema"); printf("nnUnesite x i y koordinate oka i nagib glave[deg]: "); scanf("%f %f %f",&eye.x,&eye.y,&alpha); printf("nnUnesite odnos x i odnos y koordinata sistema: "); scanf("%f %f",&eyeScale.x,&eyeScale.y); alpha *= pi/180; findA2O(); } /* Transformacija tanv caka iz ACTIVE u OBSERVER KS */ void observe(void){ int i; for(i=0;i<nVertices;i++) transform(actual[i],toObserver,&observer[i]); } /* Crtanje linija i void drawIt(void){ int i,j,vertex;
FACET a
*/
31
void redraw(void){ if(displayExposed()){ updateGraphics(); vert=horiz*nYpixels/nXpixels; xyscale=(nXpixels-1)/horiz; findA2O(); observe(); clearDisplay(); drawIt(); } } /* Kraj fajla <display2D.c> */
DEFINE P OINT ( X , Y ) - postavljanje ta ke na SETUP poziciju. Prvi poziv denie ta ku c c pod brojem 0, drugi ta ku broj 1, tre i ta ku broj 2, : : : ,n-ti poziv ta ku n ; 1 c c c c ADD L INE ( P 1, P 2) BEGIN FACET ()
ADD P OINT ( P ) - dodavanje ta ke sa indeksom P u listu temena teku eg FACET a. c c Logi no, mora biti pozvana posle BEGIN FACET (), a pre END FACET () c ADD C OLOR ( C ) - dodeljivanje boje FACET u. Kao i ADD P OINT ( P ), mora biti pozvana izmedu BEGIN i END FACET ()
- kraj denicije
FACET a
32
GLAVA 3. 2D PROSTOR
END O BJECT ( S 2 A ) - kraj denicije objekta i njegovo postavljanje u ACTUAL poziciju pomo u c transformacije S 2 A.
Detalji implementacije i zavisnosti funkcija mogu da se vide u programima 3.3.4.1 na strani 32 i 3.3.4.2 na strani 32. 3.3.4.1 Denicija funkcija za deniciju objekata
CONSTRUCTION 2D. H /* Fajl: <construction2D.h> */ /* * Projekat: Osnovi raunarske grafike c * Organizacija: Matematika gimnazija u Beogradu c * Datum: 1999/02/18 * Autor: Filip S. Bri IVc c c * Email: brcha@geocities.com * URL: http://www.geocities.com/SiliconValley/Campus/3732/Grafika.html */ #ifndef __CONSTRUCTION2D_H #define __CONSTRUCTION2D_H
#include "display2D.h" bool bool bool bool bool bool bool bool beginObject(void); /* Poetak definicije objekta ---------+ */ c definePoint(float x,float y); /* Definicija take c | */ addLine(int front,int back); /* Dodavanje linije u listu linija | */ beginFacet(void); /* Poetak definicije FACETa ---+ | */ c addPoint(int i); /* Dodavanje take u listu temena poligona c | | */ setFacetColor(int c); /* Definicija boje poligona | | */ endFacet(void); /* Kraj definicije FACETa ---------+ | */ endObject(trans2D toActive); /* Kraj definicije objekta -------+ */
#endif /* __CONSTRUCTION2D_H */ /* Kraj fajla <construction2D.h> */ 3.3.4.2 Implementacija funkcija za deniciju objekata
CONSTRUCITION 2D. C /* Fajl: <construction2D.c> */ /* * Projekat: Osnovi raunarske grafike c * Organizacija: Matematika gimnazija u Beogradu c * Datum: 1999/02/18 * Autor: Filip S. Bri IVc c c * Email: brcha@geocities.com * URL: http://www.geocities.com/SiliconValley/Campus/3732/Grafika.html */ #include "construction2D.h"
static bool defineObject = 0; /* Da li se trenutno definie objekat */ static bool defineFacet = 0; /* Da li se trenutno definie FACET */ static int setupPointCount; /* Trenutna setup taka */ c /* Poetak definicije objekta */ c
33
/* Definicija take */ c /* Prvi poziv: taka 0, c * Drugi poziv: taka 1, c * ... * n-ti poziv: taka n-1. c */ bool definePoint(float x,float y){ if((defineObject==false)|| ((setupPointCount+nVertices)>=maxVertices)) /* Nema vie mesta */ return false; setup[setupPointCount].x = x; setup[setupPointCount].y = y; setupPointCount++; return true; } /* Dodavanje linije u listu linija */ bool addLine(int front,int back){ if((defineObject==false)|| (nLines>=maxLines)|| /* Nema mesta za liniju */ ((front+nVertices)>= maxVertices)|| /* Nema mesta */ ((back+nVertices)>= maxVertices)|| /* za take */ c (front>=setupPointCount)|| /* Ne postoje */ (back>=setupPointCount)) /* take */ c return false; line[nLines].front = front+nVertices; line[nLines].back = back+nVertices; nLines++; return true; } /* Poetak definicije FACETa */ c bool beginFacet(void){ if((defineObject==false)|| (defineFacet==true)|| (nFacets>=maxFacets)) /* Nema mesta u listi */ return false; defineFacet = true; facetFirst[nFacets] = firstFreeListElement; facetColor[nFacets] = 1; /* Ako se ne definie boja, bie 1 */ c facetSize[nFacets] = 0; /* Nema taaka */ c return true; } /* Dodavanje take u listu temena poligona */ c bool addPoint(int i){ if((defineFacet==false)||
34
GLAVA 3. 2D PROSTOR
(nFacets>=maxFacets)|| /* Nema vie FACETa */ (firstFreeListElement>=maxList)|| /* Nema mesta u listi */ ((i+nVertices)>=maxVertices)|| /* Nemam gde da je upiem */ (i>=setupPointCount)) /* Ne postoji ta taka */ c return false; facetList[firstFreeListElement++] = i+nVertices; facetSize[nFacets]++; return true;
} /* Definicija boje poligona */ bool setFacetColor(int c){ if((defineFacet==false)|| (nFacets>=maxFacets)) /* Nema vie mesta */ return false; facetColor[nFacets] = c; return true; } /* Kraj definicije FACETa */ bool endFacet(void){ int i; if((defineFacet==false)|| (nFacets>=maxFacets)) return false; nFacets++; defineFacet = false; return true; } /* Kraj definicije objekta */ bool endObject(trans2D toActual){ int i; if(defineObject==false) return false; for(i=0;i<setupPointCount;i++) transform(setup[i],toActual,&actual[nVertices++]); defineObject = false; return true; } /* Kraj fajla <construction2D.c> */
35
NW
J=I
N
B C E G H F
NE
E
W SW
J H
E SE
Slika 3.11: Podela ravni produenjem stranica pravougaonika pravougaonika produe beskona no, cela ravan se deli na 9 delova (slika 3.11).Ako te delove c prikaemo kao uredene parove (ix iy ) gde ix iy 2 f;1 0 1g (tabela 3.1), vrlo lako se odreduju parametri ix i iy za proizvoljnu ta ku, a time i njen poloaj u odnosu na grani ni pravougaonik c c (CLIP RECTANGLE ). Za x koordinatu dobija se vrednost ix pomo u slede eg algoritma: c c if x then elif then else fi < -clipedX return -1 clipedX > x return 1 return 0
iy\ix
+1 0 -1
-1 NW W SW
0 N + S
+1 NE E SE
36
GLAVA 3. 2D PROSTOR
Istim algoritmom dobija se i iy . Kako sad pomo u toga odraditi 2D LINE CLIPPING? Prvo da vidimo ta se deava sa linijjama. c Ako su krrajevi neke linije ta ke p1 i p2 sa njima odgovaraju im parametrima (ix1 iy1 ) i (ix2 iy2 ), c c postoje tri razli ita slu aja: c c 1. Ako je ix1 = ix2 6= 0 ili iy1 = iy2 6= 0, onda je cela linija sigurno van pravougaonika i moe se ignorisati (linija AB na slici 3.11). 2. Ako je ix1 = iy1 = ix2 = iy2 = 0, onda je cela linija sigurno unutar pravougaonika, pa cela mora biti nacrtana (linija CD na slici 3.11). 3. Ako nije zadovoljen ni prvi, ni drugi slu aj, dolazi do uslonjavanja problema. Ako je c ix1 6= 0 i/ili iy1 6= 0, onda je ta ka p1 (x1 y1 ) van pravougaonika i mora da se nade c nova ta ka p1 0 c (x1 0 y1 0), koja ce biti na ivici pravougaonika. Proces nalaenja preseka dve prave, u ovom slu aju prave (p1 p2 ) sa najbliom stranicom pravougaonika, obraden c je u poglavlju 3.1 na strani 17. U slu aju da je ix1 = iy1 = 0, onda je p1 0 = p1 . Na isti na in c c se odreduje i ta ka p2 0. Ukoliko je p1 0 = p2 0, prava se ignorie (linija IJ na slici 3.11), a u c suprotnom, crta se prava (p1 0 p2 0) (linija EF prelazi u E 0F 0, a GH u GH 0 gde je G = G0). Ukoliko je potrebno ograni iti linije negde drugde na crteu, novi grani ni pravougaonik mora c c da sadri jo par informacija, i to koordinate centra, odn. preseka dijagonala (xc yc ) i ugao nagiba u odnosu na x-osu sistema, . Tada se mogu izvriti geometrijjske transformacije (poglavlje 3.2) pre poziva algoritma ?? za ra unanje ix odnosno iy . Nadalje se sve deava isto kao i kod c prethodno objanjenog, pojednostavljenog LINE CLIPPINGa. Postoji i suprotan algoritam od LINE CLIPPINGa. To je LINE BLANKING , kod kog se, upravo obratno, brie sve unutar pravougaonika, a van njega se ostavlja. Programi za CLIPPING i BLANKING su dati u fajlu CLIP 2D. H /. C u listinzima 3.4.1.1 na strani 36 i 3.4.1.2 na strani 37. 3.4.1.1 Denicija funkcija i promenljivih za LINE
CLIPPING / BLANKING
CLIP 2D. H /* Fajl: <clip2D.h> */ /* * Projekat: Osnovi raunarske grafike c * Organizacija: Matematika gimnazija u Beogradu c * Datum: 1999/02/18 * Autor: Filip S. Bri IVc c c * Email: brcha@geocities.com * URL: http://www.geocities.com/SiliconValley/Campus/3732/Grafika.html */ #ifndef __CLIP2D_H #define __CLIP2D_H
#include "window2vport.h" bool clipping,blanking; /* Da li treba da se vri clipping/blanking */ float clipedX,clipedY; /* granice pisanja */ float blankedX,blankedY; /* granice brisanja */ int pointMode(float coord,float clipBound); void setClippingMode(float boundX,float boundY); void setBlankingMode(float boundX,float boundY); bool clipLine(struct vector2D p1,struct vector2D p2); bool blankLine(struct vector2D p1,struct vector2D p2);
37
CLIP 2D. C /* Fajl: <clip2D.c> */ /* * Projekat: Osnovi raunarske grafike c * Organizacija: Matematika gimnazija u Beogradu c * Datum: 1999/02/18 * Autor: Filip S. Bri IVc c c * Email: brcha@geocities.com * URL: http://www.geocities.com/SiliconValley/Campus/3732/Grafika.html */ #include "clip2D.h"
/* * Funkcija koja vraa IX (ili IY) za zadatu c * X (ili Y) koordinatu i granicu prikazivanja */ int pointMode(float coord,float clipBound){ if(coord < -clipBound) return -1; /* manje od granice */ if(coord > clipBound) return +1; /* vie od granice */ return 0; /* unutar granica */ } void setClippingMode(float boundX,float boundY){ clipping = true; clipedX = boundX; clipedY = boundY; } void setBlankingMode(float boundX,float boundY){ blanking = true; blankedX = boundX; blankedY = boundY; } bool clipLine(struct vector2D p1,struct vector2D p2){ struct vector2D p1d,p2d; int ix1,iy1,ix2,iy2; float xx,yy; if(!clipping) /* ERROR: Nema granica ! */ return false; /* Inicijalizacija p1d i p2d */ p1d.x = p1.x; p1d.y = p1.y; p2d.x = p2.x; p2d.y = p2.y; /* Inicijalizacija ix1,iy1,ix2,iy2 */ ix1 = pointMode(p1d.x,clipedX); iy1 = pointMode(p1d.y,clipedY); ix2 = pointMode(p2d.x,clipedX); iy2 = pointMode(p2d.y,clipedY);
38
GLAVA 3. 2D PROSTOR
/* Ignorii prvi sluaj */ c if((ix1*ix2 != 1) && (iy1*iy2 != 1)){ if(iy1 != 0){ /* p1d je van granica y ose */ yy = clipedY*iy1; p1d.x = p1d.x + (p2d.x-p1d.x)*(yy-p1d.y)/(p2d.y-p1d.y); p1d.y = yy; ix1 = pointMode(p1d.x,clipedX); } if(ix1 != 0){ /* p1d je van granica x ose */ xx = clipedX*ix1; p1d.y = p1d.y + (p2d.y-p1d.y)*(xx-p1d.x)/(p2d.x-p1d.x); p1d.x = xx; } /* Sad isto za drugu taku */ c if(iy2 != 0){ /* p2d je van granica y ose */ yy = clipedY*iy2; p2d.x = p1d.x + (p2d.x-p1d.x)*(yy-p1d.y)/(p2d.y-p1d.y); p2d.y = yy; ix2 = pointMode(p2d.x,clipedX); } if(ix2 != 0){ /* p2d je van granica x ose */ xx = clipedX*ix2; p2d.y = p1d.y + (p2d.y-p1d.y)*(xx-p1d.x)/(p2d.x-p1d.x); p2d.x = xx; } /* Linija od p1d do p2d uz mogu blanking */ c if((fabs(p1d.x-p2d.x) > epsilon) || (fabs(p1d.y-p2d.y) > epsilon)){ /* Linija postoji */ if(blanking) return blankLine(p1d,p2d); else{ moveTo(p1d); lineTo(p2d); } } } return true;
} bool blankLine(struct vector2D p1,struct vector2D p2){ struct vector2D p1d,p2d; int ix1,iy1,ix2,iy2; if(!blanking) /* Nema granica */ return false; /* Nai ix1,iy1,ix2,iy2 */ d ix1 = pointMode(p1.x,blankedX); iy1 = pointMode(p1.y,blankedY); ix2 = pointMode(p2.x,blankedX); iy2 = pointMode(p2.y,blankedY); /* Ako su take sluaja jedan, nacrtaj liniju */ c c if((ix1*ix2 == 1) || (iy1*iy2 == 1)){ moveTo(p1); lineTo(p2); return true; }
39
if(ix1 != 0){ /* Taka p1 je van x granica, izraunaj drugu taku */ c c c p1d.x = blankedX*ix1; p1d.y = p1.y + (p2.y-p1.y)*(p1d.x-p1.x)/(p2.x-p1.x); iy1 = pointMode(p1d.y,blankedY); }else{ p1d.x = p1.x; p1d.y = p1.y; } if(iy1 != 0){ /* p1d je van y granica */ p1d.y = blankedY*iy1; p1d.x = p1.x + (p2.x-p1.x)*(p1d.y-p1.y)/(p2.y-p1.y); } /* Prvi deo linije je gotov, nacrtaj ga */ if((fabs(p1d.x-p1.x) > epsilon) || (fabs(p1d.y-p1.y) > epsilon)){ moveTo(p1); lineTo(p1d); } /* Isto za take p2 i p2d */ c if(ix2 != 0){ /* Taka p2 je van x granica, izraunaj drugu taku */ c c c p2d.x = blankedX*ix2; p2d.y = p1.y + (p2.y-p1.y)*(p2d.x-p1.x)/(p2.x-p1.x); iy2 = pointMode(p2d.y,blankedY); }else{ p2d.x = p2.x; p2d.y = p2.y; } if(iy2 != 0){ /* p2d je van y granica */ p2d.y = blankedY*iy2; p2d.x = p1.x + (p2.x-p1.x)*(p2d.y-p1.y)/(p2.y-p1.y); } /* Drugi deo linije je gotov, nacrtaj ga */ if((fabs(p2d.x-p2.x) > epsilon) || (fabs(p2d.y-p2.y) > epsilon)){ moveTo(p2); lineTo(p2d); } return true; } /* Kraj fajla <clip2D.c> */
f0 (x y) ay ; bx ; c
(3.41)
40
GLAVA 3. 2D PROSTOR
P 0 P 2
P1
P1
P 0
Slika 3.13: Deo retrogradno orjentisanog mnogougla
P 2
41
a = x1 ; x0 b = y1 ; y0 c = ay1 ; bx1
(3.42)
c kao to smo ve videli u poglavlju 3.1.1 na strani 17. Ako je f0 (x y ) > 0, ta ka (x y ) lei levo od c linije p0 p1 , ako je f0 (x y ) < 0, onda je (x y ) sa desne strane, a ukoliko je f0 (x y ) = 0, onda ta ka c (x y ) lei na pravoj p0 p1 . Sa slika 3.12 i 3.13 se lako zaklju uje da je dovoljno izra unati f0 (x2 y2 ), c c da se odredi sa koje strane lei ta ka p2 . Ako je ta ka p2 levo od p0 p1 , mnogougao je zadan c c u direktnom smeru, a ako je p2 desno, u retrogradnom. Za detalje implementacije pogledajte funkciju ORIENTATION 2D() iz fajla GRAPH U TILITIES . H /. C (dodatak A na strani 45).
fi ay ; bx ; c
gde su
(3.43)
(3.44)
Pogledajmo liniju od temena vk = f l1] k ] do vl = f l1] l]. Ako je fi (vk ) 0, onda vk moe da c se ubaci u f l2]. Ako ta ke vk i vl lee na suprotnim stranama linije (B i] B j ]), mora da se nade ta ka preseka (pogledaj poglavlje 3.1.1 na strani 17). Celokupan proces se enja se bolje razume c c sa slika 3.14, 3.15, 3.16 i 3.17.Ovaj algoritam moe da se primeni i za se enje poligona o stranice c ekrana o cemu je bilo re i u poglavlju 3.4.1 naravno, samo u kontekstu linija. Za dalje informacije c o implementaciji, pogledajte funkciju OVERLAP 2D() iz fajla GRAPH U TILITIES . H /. C (dodatak A na strani 45).
42
GLAVA 3. 2D PROSTOR
B A 2
1
Slika 3.14: Mnogouglovi A i B (osen en je trenutni presek) c
1
Slika 3.15: Prvi korak: Se enje o stranicu 3-1 mnogougla B c
1
Slika 3.16: Drugi korak: Se enje o stranicu 1-2 mnogougla B c
43
44
GLAVA 3. 2D PROSTOR
Dodatak A
p ~
46
int sign(float r); /* Orjentacija konveksnog mnogougla: * Argumenti su tri uzastopna temena * -1 - u smeru kazaljke na satu (retrogradno) * +1 - u matematikom smeru (direktno) c * 0 - degeneracija - linija ili taka c */ int orientation2D(struct vector2D p0, /* Prva taka */ c struct vector2D p1, /* Druga taka */ c struct vector2D p2); /* Trea taka */ c c /* Presek dva mnogougla: * mnogouglovi moraju da budu orjentisani u istom smeru * vraa false ako nema preseka c */ bool overlap2D(int numA,struct vector2D A[], /* Mnogougao A */ int numB,struct vector2D B[], /* Mnogougao B */ int *numC,struct vector2D C[]); /* Mnogougao C = A presek B */ #endif /* __GRAPH_UTILITIES_H */ /* Kraj fajla <graphUtilities.h> */
47
p ~
/* Presek dva mnogougla: * mnogouglovi moraju da budu orjentisani u istom smeru * vraa false ako nema preseka c */ bool overlap2D(int numA,struct vector2D A[], /* Mnogougao A */ int numB,struct vector2D B[], /* Mnogougao B */ int *numC,struct vector2D C[]){ /* Mnogougao C = A presek B */ int i,j,index1,index2,l1,l2,numCdash,orientation; struct vector2D f[2][maxPoly],end1,end2,v1,v2;
48
49
50
Dodatak B
52
int myLineStyle = LineSolid; int myLineCapStyle = CapButt; int myLineJoinStyle = JoinMiter; unsigned long *ToX; unsigned long myEventMask; XEvent myKeyEvent; XEvent myExposeEvent; void beginGraphics(void){ int i,r,g,b; XWindowAttributes xgwa; XSetWindowAttributes xswa; XEvent xev; int forked; /* Init Defaults */ nXpixels = myWindowGeometry_width; nYpixels = myWindowGeometry_height; /* Insure Connection */ myDisplay = XOpenDisplay(myDisplayName); myScreen = DefaultScreenOfDisplay(myDisplay); myColorMap = DefaultColormap(myDisplay,DefaultScreen(myDisplay)); blackColor = BlackPixel(myDisplay,DefaultScreen(myDisplay)); whiteColor = WhitePixel(myDisplay,DefaultScreen(myDisplay)); XSelectInput(myDisplay,DefaultRootWindow(myDisplay),0); /* Create a window */ numColors = DisplayCells(myDisplay,DefaultScreen(myDisplay)); if(numColors < 256) numColors = 256; ToX = (unsigned long*) safeCalloc(numColors,sizeof(unsigned long)); red = (float*) safeCalloc(numColors,sizeof(float)); green = (float*) safeCalloc(numColors,sizeof(float)); blue = (float*) safeCalloc(numColors,sizeof(float)); /* Initialize */ for(i=0;i<numColors;i++) ToX[i] = i; i=0; for(b=0;b<=1;b++) for(g=0;g<=1;g++) for(r=0;r<=1;r++) setrgb(i++,r,g,b); xswa.event_mask = StructureNotifyMask | ExposureMask; xswa.background_pixel = ToX[0]; xswa.border_pixel = ToX[1]; myEventMask = (StructureNotifyMask | ExposureMask | KeyPressMask | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask); xswa.do_not_propagate_mask = myEventMask & (KeyPressMask | KeyReleaseMask | ButtonPressMask |
53 ButtonReleaseMask | PointerMotionMask | Button1MotionMask | Button2MotionMask | Button3MotionMask | Button5MotionMask | ButtonMotionMask); xswa.colormap = myColorMap; myXWindow = XCreateWindow(myDisplay,DefaultRootWindow(myDisplay), myWindowGeometry_x,myWindowGeometry_y, myWindowGeometry_width,myWindowGeometry_height, 5, DefaultDepth(myDisplay,DefaultScreen(myDisplay)), InputOutput, DefaultVisual(myDisplay,DefaultScreen(myDisplay)), (unsigned long) (CWDontPropagate | CWBackPixel | CWEventMask | CWColormap), &xswa); XStoreName(myDisplay,myXWindow,myProgramName); myGC = XCreateGC(myDisplay,myXWindow,(unsigned long)0,(XGCValues*)NULL); XMapWindow(myDisplay,myXWindow); XWindowEvent(myDisplay,myXWindow,ExposureMask,&xev); XSync(myDisplay,0); XGetWindowAttributes(myDisplay,myXWindow,&xgwa); nXpixels = xgwa.width; nYpixels = xgwa.height; XSelectInput(myDisplay,myXWindow,myEventMask); XSync(myDisplay,0); XClearWindow(myDisplay,myXWindow); XSync(myDisplay,0); setColor(1); currentPixel.x = 0; currentPixel.y = 0; } void updateGraphics(void){ XWindowAttributes xgwa; assert(myDisplay!=NULL); XGetWindowAttributes(myDisplay,myXWindow,&xgwa); nXpixels = xgwa.width; nYpixels = xgwa.height; } void endGraphics(void){ assert(myDisplay!=NULL); XFreeGC(myDisplay,myGC); XFreeColormap(myDisplay,myColorMap); XUnmapWindow(myDisplay,myXWindow); XDestroyWindow(myDisplay,myXWindow); XCloseDisplay(myDisplay); safeFree(blue); safeFree(green); safeFree(red); safeFree(ToX); }
54
void clearDisplay(void){ assert(myDisplay!=NULL); XClearWindow(myDisplay,myXWindow); } void setColor(int color){ if(color > numColors) return; currentColor = color; } void setPixel(struct pixelVector pixel){ assert(myDisplay!=NULL); movePixel(pixel); XSetForeground(myDisplay,myGC,ToX[currentColor]); XDrawPoint(myDisplay,myXWindow,myGC,pixel.x,pixel.y); XFlush(myDisplay); } void movePixel(struct pixelVector pixel){ currentPixel = pixel; } void linePixel(struct pixelVector pixel){ assert(myDisplay!=NULL); XSetLineAttributes(myDisplay,myGC,myLineWidth,myLineStyle, myLineCapStyle,myLineJoinStyle); XSetForeground(myDisplay,myGC,ToX[currentColor]); XDrawLine(myDisplay,myXWindow,myGC, currentPixel.x,currentPixel.y, pixel.x,pixel.y); XFlush(myDisplay); movePixel(pixel); } void polyPixel(int n,struct pixelVector poly[]){ int i; XPoint *points; assert(myDisplay!=NULL); points = (XPoint*)safeMalloc((unsigned)n*sizeof(XPoint)); for(i=0;i<n;i++){ points[i].x = poly[i].x; points[i].y = poly[i].y; } XSetFillStyle(myDisplay,myGC,FillSolid); XSetLineAttributes(myDisplay,myGC,myLineWidth,myLineStyle, myLineCapStyle,myLineJoinStyle); XSetForeground(myDisplay,myGC,ToX[currentColor]); XFillPolygon(myDisplay,myXWindow,myGC,points,n,Complex,CoordModeOrigin); safeFree(points); XFlush(myDisplay); }
55 void setrgb(int i,float r,float g,float b){ XColor newColor; assert(myDisplay!=NULL); red[i] = r; green[i] = g; blue[i] = b; newColor.red = (int)(65535*r); newColor.green = (int)(65535*g); newColor.blue = (int)(65535*b); XAllocColor(myDisplay,myColorMap,&newColor); ToX[i] = newColor.pixel; } void flip(void){ } /* * lineStyle ::= { LineSolid | LineOnOffDash | LineDoubleDash } * capStyle ::= { CapNotLast | CapButt | CapRound | CapProjecting } * joinStyle ::= {JoinMiter | JoinRound | JoinBevel } */ void setLineStyle(unsigned int width,int lineStyle,int capStyle,int joinStyle){ myLineWidth = width; myLineStyle = lineStyle; myLineCapStyle = capStyle; myLineJoinStyle = capStyle; } /* * lineType ::= { SET(0) | OR(1) | AND(2) | XOR(3) } */ void setLineType(int type){ XGCValues xgcval; assert(myDisplay!=NULL); switch(type){ case 0: /* SET */ xgcval.function = GXcopy; break; case 1: /* OR */ xgcval.function = GXor; break; case 2: /* AND */ xgcval.function = GXand; break; case 3: /* XOR */ xgcval.function = GXxor; break; } XChangeGC(myDisplay,myGC,GCFunction,&xgcval);
56 }
bool keyPressed(void){ assert(myDisplay!=NULL); return XCheckWindowEvent(myDisplay,myXWindow,KeyPressMask,&myKeyEvent); } bool displayExposed(void){ assert(myDisplay!=NULL); return XCheckWindowEvent(myDisplay,myXWindow,ExposureMask,&myExposeEvent); } int getChar(void){ char c; int keyBufSize = 1; char keyBuf[2]; XComposeStatus compStat; KeySym keySym; assert(myDisplay!=NULL); if(!keyPressed()) return -1; XLookupString(&(myKeyEvent.xkey),keyBuf,keyBufSize,&keySym,&compStat); return keySym; } /* Kraj fajla <primitives.c> */
Bibliograja
[VanDam] Foley, Van Dam, Feiner, Hughes, Computer Graphics - Principles and practice, Second edition, Addison-Wesley Publishing Company, 1990
[KompGraf] Dragan Majki , Kompjuterska graka, Narodna tehnika Vojvodine, Novi Sad, 1987 c [Angell] [VTK] [OpenGL] Ian O. Angell, High-resolution Computer Graphics Using C, John Wiley & Sons, New York, 1990 Shroeder, Martin, Lorensen, The Visualization Toolkit - An Object-Oriented Approach To 3D Graphics, Prentice Hall, New Jersey, 1996 OpenGL Architecture Review Board, OpenGL Programming Guide - The Ofcial Guide to Learning OpenGL, Release 1, Addison-Wesley Publishing Company, 1993
57