Tải bản đầy đủ (.pdf) (28 trang)

CÁC THUẬT TOÁN TRONG ĐỒ HỌA MÁY TÍNH

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (296.52 KB, 28 trang )

I.Thuật toán v ẽ dường tròn
Phương trình đường tròn có dạng:
(x-xc)2 + (y-yc)2 = r2
Pt đường tròn có tâm ở gốc tọa độ:
x2+y2 =r2
Do tính đôi xứng của đường tròn nên ta chỉ
cần vẽ cung V i hoặc 1/8
void put8pixel(int xc, int yc, int X, int y)
putpixel(x+xc, y+yc, color);
putpixel(y+xc, x+yc, color);
puipỉxel(y+xc, -x+yc, color);
putpixel(x+xc, -y+yc, color);
putpixel(-x+xc, -y+yc, color);
putpixel(-y+xc, -x+yc, color);
putpixel(-y+xc, x+yc, color);
putpixel(-x+xc, y+yc, color);
l.Thuâc toán Bresenham
1
Giả sử tại bước i đã vẽ được điểm (xi,yi)
Điểm cần vẽ kê tiếp (xi+1, yi+1) là:
(xi +1, yi) hay (xi +1, yi -1)
Giá trị y thực sự thuộc đường tròn ứng với xi là:
y 2 = 1-2 - (xi +1)2
Gọi dl = yi2 - y2 = yi2 -r2 +(xi +1)2
d2= y2 - (yi -1)2 = r2 - (xi +1)2 - (yi -1)2
Pi = dl-d2 = yi2 - r2 +(xi +1)2 -r2 + (xi +1)2 +(y i-l)2
= 2(xi +1)2 + yi2 +(yi -1)2 -2r2
Pi+1 - pi = 2 (xi+l +1)2 + yi+12 + (yi+1 -1)2 - 2r2 - 2(xi +1)2
- yi2 - (yi -1)2 + 2r2
= 4xi + 6 + 2(yi+12 -y i2 ) -2(yi+l-yỉ)
^ Pi+1 = pi+4xi + 6 + 2(yi+12 - yi2) -2(yi+1-yi)


V ậy:
+ nêu pi < 0 thì yi+1 = yi, khi đó pi+1 = p i+ 4xi+6
+Nêu pi >= thì yi+1 = yi-1, khi đó pi+1 = pi + 4(xi-yi)+10
Giá trị pi tại điểm đầu tiên (x l,y l) = (0,r) là:
P1 = 2+r2+(r-l)2 - 2r2=3-2r
void CircleBres(int xc, int yc, int r)
2
int x,y,p;
x=0; y=r; p=3-2*r;
while (x<=y) {
put8pixel(xc,yc,x,y);
if(p<0) p+ =4*x+6;
else
{ p+ = 4*(x-y) +10; y - ; }
X ++ ;
}}
2.Thuât toán Midpoint
Gọi F(x,y) = x2+y2-r2, ta CÓ:
F(x,y){<0 nếu (x,y) nằm Irong đường tròn
=0 nếu (x,y) thuộc đường tròn
>0 nếu (x,y) nằm ngoài đường tròn
Chọn điểm bắt đầu v ẽ là (0,r)
Giả sử đã v ẽ được điểm (xi,yi),
Điểm cần vẽ kê tiếp (x i+ l,y i+ l) là s hay p
3
V iệc chọn điểm s hau p dựa trên dấu của:
Pi=F(Midpoint) = F(xi+l,y i-l/2)
+ Nêu pi<0 = > chọn s
+ Nêu pi>=0 => chọn p
M ặt khác:

pi+1 - pi = F(xi+1 +1, yi+1 -1/2)- F(xi+1, yi-1/2)
= [(xi+1 +1)2 + (yi+1 - V ì )2 - r2] - [(x i+l)2 + (yi-l/2)2 - r2]
= 2xi + 3 (yi+12 - yi2) - (yi+1 - yi)
Vậy: + Nêu pi<0 thì yi+1 = yi, khi đó pi+1 = pi + 2xi + 3
+ Nếu pi>=0 thì y i+ l= yi -1, khi đó pi+1 = pi + 2(xi-yi) +5
Giá trị pi tại điểm đẳu tiên (xl, yl)=(0,r) là:
p l= F (x l+1, y l -1/2) = f(l, r-1/2) = 5 / 4 - r
void CircleMidpoint(int xc, int yc, int r)
int x,y,p;
x=0; y=r; p=5/4;
while (x<=yO
put8pixel(xc,yc,x,y);
4
if(p<0) p+ = 2*x +3;
else{ p+=2*(x-y0+5; y ; }
X ++ ;
} }
II.Thu ật toán tô màu theo đường biên:
Ý tưởng:
B ắt đầu từ điểm P(x,y) nằm bên trong vùng tô,
kiểm tra các điểm lân cận cảu p đà được tô màu
hay có phải là điểm biên hay không, nếu không
phải là điểm đã tô và không phỉa là điểm biên
thì ta sẽ tô màu nó. Quá trình này
được lặp laijcho
đến khi không còn lô được diểm nào nữa thì dừng.
Có hai cách chọn điểm lan cận, đó là chọn 4 hoặc
8 điểm lân cận dôi với điểm đang xét.
Thủ tục minh hoajthuaatj toán tô màu theo đường biên:
Void T01oang(int X, int y, int mauto, int mauvien)

{ int mau;
mau=getpixel(x,y);
5
if(mau != mauvien)& (mau != mauto)
{ Putpixel(x, y.mauto);
Toloang(x-l,y, mauto, mauvien);
Toloang(x, y+1, mauto, mauvien);
Toloang(x+l, y, mauto, mauvien);
Toloang(x, y-1, mauto, mauvien);}}
=>NhưỢc điểm của phương pháp đệ quy là
=>không thực hiện được khi vùng loang có diện
=>tích lớn( dẫn đến tràn Stack
1.Phương pháp đê quy:
Bư ớc 1: khởi tạo hang đợi (hoặc stack) với
phần lử đắu tiên là P(x,y) đã được tô
Bư ớc 2: khi hàng đợi (hoặc stack) không rỗng thì:
+ L ấy ra từ hang đỢi(hoặc stack) một điểm Q.
+ tìm các điểm lân cận của Q chưa tô thì tô
chúng và đưa chúng vào hang đỢi(hoặc stack)
Bước 3 này đưỢc lặp đi lặp lại cho
đến khi hang đợi (hoặc stack) rỗng
struct DS { int x,y;
6
struct DS*next; };
struct DS*dau;
void push(int x, inty)
{ struct DS*P;
P=(D S*) calloc(l,sizeof(DS));
P->x=x; P->y=; P->next=NULL;
if(dau !=NULl)

P->next= dau;
dau=P;}
Void pop(int *x, int*y)
{ struct DS*P;
P=dau; dau=dau->next;
*x=P ->x; *y = P->y;
free(P);}
void tolancan(int x, inty, int inauto, int mauvien)
{ int mau;
mau=getpixel(x,y);
if((mau != mauto)&&(mau !=mauvien))
{ putixel(x,y,mauto);
7
Void toloang_stack(int xO, int yO,
int mauto, int mauvien){ int x,y;
putpixel(xO,yO,mauto);
dau=NULL;
push(xo,yo);
while(dau != NULL)
{ pop(&x,&y);
tolancan(x-l, y, mauto, mauvien);
tolancan(x+l, y, mauto, mauvien);
tolancan(x, y+1, mauto, mauvien);
tolancan(x, y-1, mauto, mauvien);}}
push(x,y); I
Flood
Fill/boundary fill
Scan line fill/
scan conversion
Đơn giản Phức tạp hơn

Thuật toán rời
rạc hóa trong
không gian màn
hình
Thuật toán rời
rạc hóa trong
đối tượng
hoặc/và không
gian màn hình
8
Yêu cầu gọi hệ
thống
GetPixel/Val
Độc lập với
thiêt bị
Đòi hỏi điểm
seed
Không đòi hỏi
điểm seed
Yêu cầu stack rất
lớn
Yêu cắn stack
nhỏ
IlI.C ác thu ật toán xén hình
l.Thuât toán Cohen-sutherland
Chia m ặt phẳng thành 9 vùng: cửa sổ và 8
vùng xung quanh nó. Mỗi vùng được gán bởi một mã nhị phân 4
bit
Giả sử có điểm P(x,y), lúc đó gán mã cho điểm P:
Pleft={ 1, nếu Px < xmin

Pright={ 1, nếu Px>xmax
0, ngược lại
0, ngược lại
Pbottom={ 1, nêu Py<ymin
Ptop= { 1, nếu Py>ymax
0, ngược lại
0, ngƯỢc lại
9
Hàm tính mã
int ma(pointM){ intm =0;
m l=l
ml=2
ml=4
ml=8
return m;}
Xét đoan thẳng AB. ta có các trường hơp sau:
1.Nêu (M a(A)=0000) và (M a(B)=000)
{hay(Ma(A) or M a(B )=0000} thì
=>ClipD (F)=A B
2.Nêu (Ma(A) and M a(B))*0000) thì
=> ClipD(F) = 0
3.Nêu ((Ma(A) and M a(B))=0000) và
(M a(A)*0000 hoặc Ma(B)*OOỮO) thì
Giả sử M a(A)*0000 { nêu ma(A)=0
ta đổi vai trò A và B }
-Nêu A x=Bx(A B thẳng đứng ) thì
+Nêu Ay>ymax (A ở trên) thì Ay=ymax’
10
ngưỢc lại (A ở dưới) Ay=ymin
= > ClipD(F)=AB

-NgƯỢc lại (trường hợp Ax^Bx):
+Tính h ệ sô góc m=(By-Ay)/(Bx-Ax)
{đ ể tính giao của AB với HCN}
Vì A nằm ngoài hình chữ nhật nên:
+Nêu Ax<xmin thì thay A
bởi điểm giao của AB với cạnh trái(nối dài) của HCN
+Nêu Ax>xmax thì thay A
bởi điểm giao của Ab với cạnh phải(nối dài) cua HCN
+Nêu Ay<ymin thì thay A
bởi điểm giao của AB với cạnh dưới(nối dài) của HCN
+Nêu Ay>ymax thì thay A
bởi giao điểm của Ab với cạnh trên(nối dài) của HCN
Quá trình lặp lại này
dừng khi xảy ra một trong hai trường hỢp lhay 2
void ClipCohen(Point A, oint B, Point wmin, Point wmax)
{ int thoat,ve; double m;
thoat=0; v e=l;
11
while(thoat==0)
{ if((ma(A) I m a(B)==0) thoat=l;
else if((m a(A)& ma(B))!=0){thoat=l; ve=0}
else { if(m (A)==0) hoanvi(&A,&B);
if(A.x==B .x)
{ if(A.y>wmax.y) A.y=wmax.y;
else A.y=wmin.y;}
else{ m=(double)(B.y-A.y)/(b.x-A.x);
if(A.x<wmin.x){ A.y=A.y+(wmin.x-A.x)*m;
A,x=wmin.x; }
Else if(A.x>wmax.x){
A.y=A.y+(wmax.x-A.x)*m;

A.x=wmax.x; }
else
if(A.y<wm in.y){A.x= A.x+(wmin.y-A.y)/m;
A.y=wmin.y; }
else
if(A.y>wmax.y)
{ A.x=A.x+(wmax.y-A.y)/m;
12
A.y=wmax.y; } } } }//end while
if (ve) veduongthang(A.B);}
2.Thuât toán chia nhi phân
Chia mặt phẳng thành 9 vùng, mỗi vùng
được gán bởi một mã nhị phân 4 bit
-Ý tưởng của thuật toán như sau:
Lấy trung điểm của đoạn thẳng và kiểm tra
mã của nó đ ể loại dần các đoạn con không
chứa giao điểm, và cuối cùng cho điểm giữa
hội tụ về giao điểm của đoạn thẳng với hình chữ
nhật, kết quả là ta thu được đoạn con nằm trong
hình chữ nhật(nếu có)
-Mệnh đề :
Cho M trung điểm của đoạn AB,
M ã(A)*0000,
M ã(B)*0000,
M ã(M )*0000
Thì ta có: [mã(A) AND M ã(M)l*0000
hoặc[Mã(M) AND M â(B)]*0000.
13
-Ý nghĩa hình học của mệnh đề:
Nêu cả ba điểm A, B, M đều ở ngoài hình chữ

nhật thì có ít nhất một đoạn hoàn toàn nằm ngoài hình chữ nhật.
-Thuật toán:
1.Nêu (Mã(A) = 0000) và M ã(B)=0000) thì
=>ClipD(F) = AB
2.Nêu (Mã(A) AND M ã(B))*0D00 thì
=>C lipD (F)=0
3.Nêu (Mã(A)^OOOO) và Mã(B) = 0000) thì:
đỏi vai trò của A, B và áp dụng 4
4.Nêu (Mã(A) = 0000) và (Mã(B) *0000 ) thì:
P:=A; Q :=B;
Trong khi |xP - xQI + lyP - yQ|>=2 thì:
Lây trung điểm M của PQ
Nếu M ã(M )*0000 thì Q:=M.
NgưỢc lại: P:=M.
=>ClipD(F) = AP
5.Nếu (Mã(A) * 0000 * Mã(B)) và [Mã(A)
AND Mã(B)]= 0000 thì:
14
P:=A; Q :=B;
Lấy M: trung điểm PQ;
Khi (Mã(M)^OOOO) và (|xP-xQ| + |yP-yQ|>=2) thi:
Nếu (Mã(M) AND M ã(Q))*0000 thì Q:=M;
Ngược lại: P:M;
Lấy M: trung điểm PQ
Nếu M ã(M )*0000 thì C lipD (F)=0
NgưỢc lại, áp dụng 4 ta có:
ClipD(MP) = M AI
ClipD(MQ) = MB1
=>ClipD(F) = A1B1
Void XenHinhNhiPhan(Poỉnt A, Point B)

{ Point P,Q,M;
if((Ma(A)|Ma(B))==0) VeDuongThang(A,B);
if((M a(A)&M a(B))!=0) return;
if((Ma(A )!=0)& &(M a(B)=0)) HoanVi(&A,&B);
if((Ma( A )==0)& & (M a(B )!=0))
{ P=A; Q=B;
while((abs(P.x-Q.x)+abs(P.y-Q.y)).2)
15
{ M .x=(P.x+Q.x)/2;
M.y=(P.y+Q.y)/2;
If(Ma(M )==0) P=M;
Else Q =M ;}
VeDuongThang(A.P);}
if(((M a(A)!=0)&& (M a(B)!=0))&& ((M a(A)& Ma(B))==0))
{ P=A; Q=B;
M .x=(P.x+Q.x)/2; M.y=(P.y+Q.y)/2;
while((M a(M)!=0)&& ((abs(P.x-Q.x)+abs(P.y-Q.y))>2))
{ if((Ma(P)& M a(M)!=0) P=M;
else Q=M;
M .x=(P.x+Q.x)/2;
M .y=(P.y+Q .y)/2;}
if(M a(M )==0){ XenHinhNhiPhan(P,M);
XenHihNhiPhan(M,Q);}
IV.Biểu diễn các đôi tượng 3D
l.M ô hình khung kết nối
Mô hình khung kết nối (WF-WireFrame model)
thể hiện hình dáng của một đôi tƯỢng 3D bởi 2 danh sách:
16
-Danh sách các đỉnh (vertices): lưu tọa đọ các đỉnh.
-Danh sách các cạnh (edges) nối gữa các

đỉnh đó: lưu 2 đỉnh đầu và cuối của từng cạnh,
(hình vẽ)
Có nhiều cách đ ể lưu trữ một mo hình
WF trên máy tính. Có thể sử dụng cấu trúc sau:
const maxDinh= 30;
const maxCanh=50;
typedef slrucl loado3D
{ int x; int y; int z; }
typedef slrucl KieuCanh
{ int dau; int cuoi; }
typedef struct WireFrame
{ int sodinh;
toado3D dinh[maxDinh];
int socanh;
KieuCanh canh[maxCnah];
2.Mô hình mặt đa giác
17
Mô hình các m ặt đa giác(Polygon Mesh model)
thể hiện hình dáng của một đối tượng 3D bởi 2 danh sách
-Danh sách các đỉnh
-Danh sách các mặt: lưu thứ tự các đỉnh tạo nên mặt đó
(hình vẽ)
Chúng ta có thể đưa ra nhiều cấu trúc dữ
liệu khác nhau để lull trữ cho đa giác. Dưới
đây là một kiểu cấu trúc:
typedef struct loado3D
{ int x; int y; int z; }
struct Kieumal
{ int sodinhmat;
int chisodinh[MAX]; };

struct Mohinhmat
{ int sodinh;
toado3D dinhfMAX];
int somat;
Kieumat mat[MAX]; };
V.Biểu diễn đường và m át cong:
Ỉ.Dườnạ cong Benzier
Bài toán: Cho n+1 điểm pO, p Ị p2, ,pn
được gọi là các điểm kiểm soát (điểm điều khiển).
Xây dựng đường cong trơn đi qua 2 điểm p và pn
được giới hạn trong bao lồi do n+1 điểm trên tạo ra
Thuật toán Caste]jau
Đ ể xây dựng đường cong P(t), ta dựa trên
một dãy các điểm cho trước rồi tạo ra giá trị P(t)
ứng với mỗi giá trị t nào đó.
Phương pháp này tạo ra đường congdựa trên mộl
dãy các bước nội suy tuyến tính hay nội suy
khoảng giữa(In-Betweening).
với 3 điểm PO, P l, P2 ta có thể xây dựng
một Parabol nội suy từ 3 điểm này bằng cách chọn
một giá trị t e [0,1] rồi chia đoạn P0P1 theo tỉ lệ t,
ta được điểm P01, trên P0P1. Tương t ự , ta chia
tiếp P1P2 cũng theo tỉ lệ t, ta được P ll . Nôi P01 và P ll
lại lấy điểm trên P01P11 chia theo tỉ lệ t, ta được P02.
19
Tập điểm P02 chính là đường
cong P(t).
Ta biểu diễn bằng chương trình:
P01(t)= (l-t).P 0+t.P l (1)
P ll(t)= (l-t).P l+l.P 2 (2)

P 0 2(t)= (l-t).P 0 1+ t.P ll (3)
Trong đó t e [0. 1]
Thay (1), (2) vào (3) ta được:
P(t)= P02(t)= (1-02.P0 + 2t.(l-t).Pl
+ t2.p2
Đây là một đường cong bậc 2 theo
t nên nó là một Parabol
-Tổng quát hóa ta có thuật toán
Casteljau cho (n+1) điểm kiểm
soát:
Giả sử ta có tập điểm: P0,P1,P2,
,Pn
v ới mỗi giá trị t cho trước, ta tạo
ra điểm Pir(t) ở thê ệ thứ r, từ thê
hệ thứ (r-1) trước đó, ta có:
Pir(t)= (l-t).P ir-l(t)+t.P i+lr-l(t)
(r=0 ,l, ,n và i=0, ,n-r)
20
Thê hệ cuối cùng: POn(t)=X P i.(l-
t)n-i.ti.Cni
ĐƯỢc gọi là dường cong benzier
của các điểm P0,Pl,P2, ,Pn.
Các điểm pi, i= 0,l, ,n gọi là các
điểm kiểm soát hay các điểm beier.
Đa gics tạo bởi các điểm kiểm soát
gọi là đa giác kiểm soát hay đa giác
benziei.
Đường cong benzier dựa trên (n+1)
điểm kiểm soát P0,Pl,P2, ,Pn
được cho bưởi công thức:

POn ( t)=P(t)= Xpk.B nk(t)
Trong đó: P(t): là một điểm trong
mặt phẳng hoặc trong không gian.
B nk(t): gọi là đa thức Bernstrin,
được cho bởi coog thức:
B nk(t)=Cnk .(l-t)n-k.tk =(n!/k!(n-
k)! )(l-t)n-t.tk với n>=k
M ỗi đa thức Bernstein có b ậc là n.
thong thuowgf ta còn gọi các B
nk(t) là các hàm trộn.
21
Đường cong Benzier dực trên (n+1)
điểm kiểm soát pO,pl, ,pn được
cho bưởi coog thức:
POn ( 0 = P(t)= £P k.B nk(t)
Tương tự, đối với mặt benzier ta
có phương trình sau:
P(u,v)— X ỵ p I,k . Bim (u) Bkn(V)
Trong trường hỢp này khôi đa
diện kiểm soát sẽ có (m +l)(n +l)
đỉnh.
Minh hoa vẽ đường cong benzier
trong măt phẳng.
Typedef struct { int x; int y; }
CPoint;
int GiaiThua (ini n){ if(n O ) return
1 ;
else return 1 n* GiaiThua(n-l);
}
float hamMu(float a, int n)

{ if(n==0) return 1;
plsp return a*hamMn(a;n-1);
}
float BornStein(float t,int n, ini k){
float ckn,kq;
22
ckn=GiaiThua(n)/
(GiaiThua(k)*GiaiThua(n-k));
kq=ckn*HamM u(l-t,n-
k)*HamMu(t,k);
return kq;}
CPoint TPt(CPonit p[ ],float t,int n)
{CPoint Pt; float B;int K;
Pt.x=0; Pt.y=0;
For(k=0;k<=n;k++) { B=
BernStein(t,n,k);
Pt.x=Pt.x+P[k].x*B;
Pt.y=Pt.y+P[k].y*B;
} return Pt; }
Void DrawBenzier(int n, CPoint
P[ ])
{ CPoint PT; float int l;t=0;
m =100; dt=l/m;
Moveto(P[0].x,P[0].y);
Fo r(i= l;i<= m ;i++){ Pt=TPt(P,t,n);
Lineto(Pt.x,Pt.y); t=t+dt; }
Các mặt có quy tắc: (m ặt trụ)
23
M ặt trụ là mặt được tạo ra khi một
dường thẳng (đường sinh) được

quét dọc theo một đường cong
P0(u) (đường chuẩn), đường cong
P0(u) nằm trên một mặt phẳng
nào đó .
Gọi d là đường sinh,d=const.
P0(u) là đáy dưới.
Pl(u)là đáy trên.
Suy ra d= P0(u)- Pl(u)p(u,v)= (1-
v).P0(u)+v.Pl(u)
= P0(u)+(Pl(u) -P0(u)).v= P0(u)
+d.v
v ậy : p(u,v)= P0(u)+d.v
Pl mặt trụ : p(u,v)= PO(u)+d.v
Dạng quen thuộc của mặt trụ là
mặt trụ trònL trong m ặt phẳng
xoy, lấy P0(u) là đường tròn tâm o
bán kính r.
Ta có:d=(0,0,h)
PO(ii)=(r.rns(ii),r.sin(ii),f))
v ậy : {X(u,v)=r.cos(u)
Y(u,v)=r.sin(u)
24
Z(u,v)=h.v
với (0<=V <=1; 0< =u<=2 tt
thủ tụ c m ặ t trụ :
void DrawCylinder( float R,floal h){
Point3D P; Point2D P1 ; doule
Delta_u, De!ta_V,u,v;
Delta_u=0.06 ; D elta_v=0.03;
for(u=0;u<2*M _PI;u+;:: Delta_U)

{ for(v=0;v<2*M _PI;v+= Delta_V)
{ P.x=R*cos(u);
P.y=R*sin(u);
p.z=v*h;
Pl=Chieu(KieuChieu,P);
Putpixel(xc+Pl.x+Pl.y,ưhite);}}}
M ặt nón:
M ặt nón là mặt được tạo ra khi
một dường thắng di chuyển dọc
theo một đường cong phawmgr cho
trước. các duowgf thẳng luôn di
qua m ột điểm cố định gọi là đỉnh
của mặt nón.
P0(u) tròng với gốc tọa độ o .
25

×