Kỹ thuật Đồ hoạ máy tính
65
Chơng 4
Kỹ thuật xử lý hình khuất
$12. Phần hiển thị của hình
Phần này chúng ta giải quyết bài toán sau:
Giả sử đối tợng quan sát nằm trong vùng nhìn thấy, khi đó nó có ảnh trên mặt
phẳng chiếu . Nếu bây giờ chúng ta thu nhỏ mặt phẳng chiếu, hãy xác định phần
hình ảnh của đối tợng có trong mặt phẳng chiếu, chúng ta chú ý rằng vấn đề này rất
phù hợp với yêu cầu đặt ra khi mô tả đối tợng trên máy tính. Nếu chúng ta coi màn
hình là mặt phẳng chiếu hay một vòng hình chữ nhật (cửa sổ) trên màn hình là mặt
phẳng chiếu (Trong Pascal, C ta gọi vùng chiếu đó là ViewPort)
Không giảm tổng quát ta giả sử cửa sổ trên mặt phẳng chiếu có kích thớc [Xmin,
Xmax] x [Ymin,Ymax]
1. Thuật toán Cohen Sutherland
Thuật toán Cohen Sutherland giải quyết bài toán làm thế nào để xác định phần đoạn
thẳng có trong mặt phẳng chiếu. Nói một cách khác làm thế nào để xác định phần
đờng thẳng cho trớc có trong Viewport
Theo Cohen Sutherland một cửa sổ sẽ chia màn hình thành 9 phần mỗi phần ứng với
một mã số gồm 4 bit
Mn hình cửa sổ
Đờng thẳng
X
O
Y
Y
max
Y
min
Xmin
Xmax
Kỹ thuật Đồ hoạ máy tính
66
Một điểm P bất kỳ thuộc mặt phẳng chiếu sẽ ứng với một mã gọi là Kod(P)
Kod(P)=b
4
b
3
b
2
b
1
Trong đó các b
i
đợc xác định nh sau:
()1
b=1
b=1
b=1
b=1
1
2
3
4
nếu P nằm ở bên trái của cửa sổ
nếu P nằm ở bên phải của cửa sổ
nếu P nằm ở phần bên d ới của cửa sổ
nếu P nằm ở phần bên trên của cửa sổ
Nếu không thoả mãn điều kiện trên thì
bi
i
==014,,.
Một điểm P(x,y) bất kỳ Kod(P)đợc xác định theo (1) nh sau:
b
1
=1 nếu x<x
min
b
2
=1 nếu x>x
max
b
3
=1 nếu y>y
max
b
4
=1 nếu y<y
min
Với cách tính này ta suy ra:
b
1
l bit dấu của x-x
min
b
2
l bit dấu của x
max
-x
b
3
l bit dấu của y
max
-y
b
4
l bit dấu của y-y
min
(Chú ý trong máy tính bit dấu bằng 1 thì có dấu -)
Chúng ta quy ớc nếu điểm Pbiên của cửa sổ thì Kod(P)=0
Với cách xác định mã ở trên của điểm P ta suy ra P cửa sổ viewport khi
Kod(P)=0000
Do đó
i. đoạn thẳng P
1
P
2
thuộc cửa sổ khi
Kod(P
1
)=Kod(P
2
)=0000
ii. đoạn thẳng sẽ nằm hoàn toàn bên ngoài cửa sổ khi
1001 1000 1010
0001 Viewport 0010
0000
0101 0100 0110
Kỹ thuật Đồ hoạ máy tính
67
( Kod(P
1
) And Kod(P
2
) )0000
iii. còn lại đoạn thẳng sẽ nằm cả trong lẫn ngoài cửa sổ nghĩa là khi
((Kod(P
1
) And Kod(P
2
) ) = 0000) And (( Kod(P
1
) 0000) Or (Kod(P
2
) 0000))
Xác định điểm giao của đoạn thẳng với các cạnh của cửa sổ sau đó vứt bỏ phần
không thuộc cửa sổ thuật toán có thể minh hoạ bằng hình sau:
Có thể mô tả thuật toán Cohen-Sutherland nh sau:
Giả sử điểm P
1
có toạ độ là (x
1
,y
1
) và P
2
có toạ độ là (x
2
,y
2
)
và cửa sổ nhìn có toạ độ là (x
min
, y
min)-
(x
max,
y
max
)
1. Tính Kod(P1) và Kod(P2)
2. Nếu Kod(P1)=Kod(P2)=0000 thì P1P2 nằm trong nhẩy đến 5
3. Nếu (Kod(P1) And Kod(P2))<>0000 thì P1P2 nằm ngoài nhẩy đến 6
4. Ngợc lại không thoả mãn 2 điều kiện trên thực hiện
- Nếu Kod(P1)=0000 thì ta hoán vị P1 với P2 để Kod(P1)<>0000 và lấy b4b3b2b1=
Kod(P1)
- Nếu b1=1 thì y1=y1+(xmin-x1)*(y2-y1)/(x2-x1); x1=xmin
- Nếu b2=1 thì y1=y1+(xmax-x1)*(y2-y1)/(x2-x1); x1=xmax
- Nếu b3=1 thì x1=x1+(ymin-y1)*(x2-x1)/(y2-y1); y1=ymin
- Nếu b4=1 thì x1=x1+(ymax-y1)*(x2-x1)/(y2-y1); y1=ymax
- Quay lại bớc 1
5. Vẽ đoạn thẳng P1P2
6. Kết thúc
ở trên chúng ta có thực hiện phép chia cho (x2-x1) và phép chia cho (y2-y1) cho nên
trớc tiên chúng ta phải xét các trờng hợp x2=x1 và trờng hợp y2=y1, hai trờng
hợp này đơn giản tự làm.
Chơng trình minh họa :
Program Cohen_Sutherland;
uses crt,graph;
type
code=array[1 4] of Byte;
P
2
P'
2
Bỏ
P
4
P"
1
Bỏ
Bỏ
Bỏ
P'
3
P'
1
P
3
P
1
Kü thuËt §å ho¹ m¸y tÝnh
68
var
a1,b1,a2,b2 : Real;
n,i, xmin,ymin,xmax,ymax,gd,gm:integer;
b: code;
(****************************************)
Procedure Special_Line(x1,y1,x2,y2: Real);
Var
tg: Real;
Begin
If (x1=x2) And (x1>xmin) And (x1<xmax) Then
Begin
If y1>y2 Then
Begin
tg:=y1; y1:=y2; y2:=tg;
End;
If (y1<ymax) And (y2>ymin) Then
Begin
If y1<ymin Then y1:=ymin;
If y2>ymax Then y2:=ymax;
End;
Line(Round(x1),Round(y1),Round(x2),Round(y2));
End;
If (y1=y2) And (y1>ymin) And (y1<ymax) Then
Begin
If x1>x2 Then
Begin
tg:=x1; x1:=x2; x2:=tg;
End;
If (x1<xmax) And (x2>xmin) Then
Begin
If x1<xmin Then x1:=xmin;
If x2>xmax Then x2:=xmax;
End;
Line(Round(x1),Round(y1),Round(x2),Round(y2));
End;
End;
(*****************************)
Procedure Kod(x,y:real;var b:code );
Begin
For i:=1 To 4 Do b[i]:=0;
if(x < xmin) then b[1]:=1;
if(x > xmax) then b[2]:=1;
if(y < ymin) then b[3]:=1;
if(y > ymax) then b[4]:=1;
End;
Kü thuËt §å ho¹ m¸y tÝnh
69
(****************************************)
Procedure Cohen_Sutherland_Clipping(x1,y1,x2,y2:Real);
var
c1,c2: code;
chon,tong1,tong2,mu2: Byte;
tgx,tgy : Real;
Begin
Repeat
Kod(x1,y1,c1); Kod(x2,y2,c2);
tong1:=0; tong2:=0; mu2:=1;
For i:=1 To 4 Do
Begin
tong1:=tong1+c1[i]*mu2;
tong2:=tong2+c2[i]*mu2;
mu2:=mu2*2;
End;
If tong1+tong2=0 Then
Begin
chon:=1;
line(Round(x1),Round(y1),Round(x2),Round(y2));
End
Else If (tong1 And tong2)<>0 then
Begin
chon:=2;
End
Else
Begin
chon:=3;
If tong1=0 then
Begin
tgx:=x1; x1:=x2; x2:=tgx;
tgy:=y1; y1:=y2; y2:=tgy;
End;
Kod(x1,y1,b);
if b[1]=1 then
Begin
y1:=y1+(xmin-x1)*(y2-y1)/(x2-x1); x1:=xmin
End;
if b[2]=1 then
Begin
y1:=y1+(xmax-x1)*(y2-y1)/(x2-x1); x1:=xmax
End;
if b[3]=1 then
Begin
x1:=x1+(ymin-y1)*(x2-x1)/(y2-y1); y1:=ymin
Kỹ thuật Đồ hoạ máy tính
70
End;
if b[4]=1 then
Begin
x1:=x1+(ymax-y1)*(x2-x1)/(y2-y1); y1:=ymax
End;
End;
Until (chon=1) Or (chon=2);
End;
(****************************************)
Begin
clrscr;
write('nhap toa do cua so xmin,ymin: ');
readln(xmin,ymin);
write('nhap toa do cua so xmax,ymax: ');
readln(xmax,ymax);
write('Nhap (a1,b1): '); readln(a1,b1);
write('Nhap (a2,b2): '); readln(a2,b2);
gd:=detect;
initgraph(gd,gm,'c:\tp\bgi');
setbkcolor(Black);
setcolor(red);
rectangle(xmin,ymin,xmax,ymax);
settextjustify(1,1);
outtextxy(320,450,'HIEN THI MOT DOAN THANG TRONG MOT CUA SO
CHO TRUOC');
outtextxy(320,470,'THEO THUAT TOAN COHEN-SUTHERLAND');
setcolor(WHITE);
setlinestyle(1,0,0);
line(Round(a1),Round(b1),Round(a2),Round(b2));
setlinestyle(0,0,0);
If (a1<>a2)And(b1<>b2) Then Cohen_Sutherland_Clipping(a1,b1,a2,b2)
Else Special_Line(a1,b1,a2,b2);
readln;
closegraph;
End.
2. Thuật toán Liang-Barsky
Thuật toán xác định phần đờng thẳng của Cohen Shutherland tơng đối đơn giản và
thuận tiện, tuy nhiên nó có nhợc điểm khi ngời lặp lại quá trình xác định giao
điểm của đoạn thẳng với cửa sổ phải tiến hành nhiều phép nhân, chia điều này sẽ
dẫn đến hậu quả là thời gian xử lý chậm, gặp nhiều sai số. Hai nhà toán học Liang
và Barsky đã đa ra một thuật toán khác để khắc phục nhợc điểm trên. Giả sử đoạn
thẳng cho dới dạng tham số đi qua 2 điểm P1(x
1
,y
1
), P2(x
2
,y
2
) có dạng:
x=x +tdx
y=y +tdy
1
1
()1
Kỹ thuật Đồ hoạ máy tính
71
với dx=x
2
-x
1
; dy=y
2
-y
1
t[0,1]
Giả sử cửa sổ giới hạn bởi hai điểm ở góc trên bên trái và góc dới bên phải
(x
min
,y
min
) , (x
max
,y
max
) khi đó đoạn thẳng thuộc vào cửa sổ khi và chỉ khi
xx+tdxx
yy+tdyy
min 1 max
min 1 max
x-x tdxx-x
y-y tdyy-y
min 1 max 1
min 1 max 1
t.p
k
q
k
, k=1,2,3,4 (2)
Với p
1
=-dx q
1
=x
1
-x
min
p
2
=dx q
2
=x
max
-x
1
p
3
=-dy q
3
=y
1
-y
min
p
4
=dy q
4
=y
max
-y
1
Từ (2) ta suy ra:
1. Nếu có k (bằng 1 hoặc 3) để p
k
=0 thì đoạn thẳng song song với một cạnh nào đó
của cửa sổ
2. Nếu với k mà p
k
0 thì ta xác định t1 và t2
t1=Max{0,Max(qk/pk)} với các pk<0
t2=Max{(1,Min(qk/pk)} với các pk>0
khi đó xác định đợc đoạn thẳng (xw1,yw1)-(xw2,yw2) nằm trong cửa sổ
xw1=x1+t1*dx; yw1=y1+t1*dy
xw2=x1+t2*dx; yw2=y1+t2*dy
Ta có thuật toán Liang Barsky
1. đặt t1=0; t2=1;
2. Tính pk và qk theo công thức trên với k=1,2,3,4
3. Nếu có pk=0 thì đoạn thẳng song song với 1 trong 2 cạnh của cửa sổ
4. Nếu pk<>0 (với k=1,2,3,4) thì
- Cho k chạy từ 1 đến 4
- đặt t=qk/pk
- nếu pk<0 thì đặt t1=max(t1,t)
- nếu pk>0 thì đặt t2=min(t2,t)
5. Nếu t1<=t2 thì toạ độ giao của đoạn thẳng với cửa sổ là
+ xw1=x1+t1*dx ; yw1=y1+t1*dy
+ xw2=x1+t2*dx ; yw2=y1+t2*dy
+ vẽ đoạn thẳng (xw1,yw1)-(xw2,yw2)
6. Nếu t1>t2 thì P1P2 nằm ngoài cửa sổ và kết thúc
Chơng trình minh họa :
Program Liang_Barsky;
Uses Crt,Graph;
Kü thuËt §å ho¹ m¸y tÝnh
72
Var
gd,gm,k : integer;
xmin,xmax,ymin,ymax : integer;
a1,b1,a2,b2,dx,dy : Real;
p,q : Array[1 4] Of Real;
(*****************************)
Procedure Special_Line(x1,y1,x2,y2: Real);
Var
tg: Real;
Begin
If (x1=x2) And (x1>xmin) And (x1<xmax) Then
Begin
If y1>y2 Then
Begin
tg:=y1; y1:=y2; y2:=tg;
End;
If (y1<ymax) And (y2>ymin) Then
Begin
If y1<ymin Then y1:=ymin;
If y2>ymax Then y2:=ymax;
End;
Line(Round(x1),Round(y1),Round(x2),Round(y2));
End;
If (y1=y2) And (y1>ymin) And (y1<ymax) Then
Begin
If x1>x2 Then
Begin
tg:=x1; x1:=x2; x2:=tg;
End;
If (x1<xmax) And (x2>xmin) Then
Begin
If x1<xmin Then x1:=xmin;
If x2>xmax Then x2:=xmax;
End;
Line(Round(x1),Round(y1),Round(x2),Round(y2));
End;
End;
(*****************************)
Procedure Liang_Barsky_Clipping(x1,y1,x2,y2: Real);
Var
xw1,yw1,xw2,yw2,t,t1,t2: Real;
Begin
t1:=0; t2:=1;
dx:=x2-x1; dy:=y2-y1;
p[1]:=-dx; p[2]:=dx; p[3]:=-dy; p[4]:=dy;
Kỹ thuật Đồ hoạ máy tính
73
q[1]:=x1-xmin; q[2]:=xmax-x1; q[3]:=y1-ymin; q[4]:=ymax-y1;
For k:=1 To 4 Do
Begin
t:=q[k]/p[k];
If p[k]<0 then If t1<t Then t1:=t;
If p[k]>0 then If t2>t then t2:=t;
End;
If t1<=t2 then
Begin
xw1:=x1+t1*dx; yw1:=y1+t1*dy;
xw2:=x1+t2*dx; yw2:=y1+t2*dy;
Line(Round(xw1),Round(yw1),Round(xw2),Round(yw2));
End;
End;
(*****************************)
Begin
Clrscr;
write('Nhap (xmin,ymin): '); readln(xmin,ymin);
write('Nhap (xmax,ymax): '); readln(xmax,ymax);
write('Nhap (a1,b1): '); readln(a1,b1);
write('Nhap (a2,b2): '); readln(a2,b2);
gd:=detect;
Initgraph(gd,gm,'C:\tp\bgi');
setcolor(White);
setlinestyle(1,0,0);
Line(Round(a1),Round(b1),Round(a2),Round(b2));
setlinestyle(0,0,0);
If (a1<>a2) And (b1<>b2) Then Liang_Barsky_Clipping(a1,b1,a2,b2)
Else Special_Line(a1,b1,a2,b2);
settextjustify(1,1);
outtextxy(320,450,'HIEN THI MOT DOAN THANG TRONG MOT CUA SO
CHO TRUOC');
outtextxy(320,470,'THEO THUAT TOAN LIANG_BARSKY');
rectangle(xmin,ymin,xmax,ymax);
Readln;
Closegraph;
End.
$13. Vùng nhìn thấy
Trong khi quan sát các vật thể trong không gian chúng ta gặp hai tình huống sau:
1. Từ vị trí quan sát chúng ta có thể nhìn thấy một phần hay không nhìn thấy vật thể.
Điều này phụ thuộc vào vị trí và góc nhìn của ngời quan sát đối với vật thể