You are on page 1of 41

Chương 3

Các thuật toán vẽ đường

 Thuật toán vẽ đoạn thẳng DDA

 Thuật toán vẽ đoạn thẳng Bresenham

 Thuật toán vẽ đoạn thẳng MidPoint

 Thuật toán vẽ đường tròn, đường cong


1
Các đối tượng đồ họa cơ sở

 Điểm
 Đường thẳng
 Tam giác
 Đường tròn
 Đường cong

2
Màn hình điểm

-Chúng ta cần tọa độ màn ảnh thực 2D để chỉ rõ vị trí các điểm ảnh.
-Các chi tiết của các hệ thống như vậy là biến đổi theo các API.
-Nhưng phổ biến nhất là sử dụng lưới giá trị nguyên cho các tâm
điểm ảnh, điểm ảnh trên ở vị trí trung tâm cách biên 0.5.

3
1
THUẬT TOÁN
VẼ ĐOẠN THẲNG

4
Khái niệm đoạn thẳng

 Input: điểm đầu A(x1, y1), điểm cuối B(x2, y2),


màu tô color C.
 Output: Xác định các điểm tạo thành một đoạn
thẳng nối hai điểm AB và có màu C.

5
Khái niệm đoạn thẳng
 Chuyển đổi đường quét (Rasterization)
 Biến đổi đường liên tục thành rời rạc (Sampling)
 Scan conversion = Sampling

 Yêu cầu chất lượng đường vẽ


 Hình dạng liên tục
 Độ dày và độ sáng đều
 Các pixel gần đường “lý tưởng” được hiển thị
 Vẽ nhanh
6
Khái niệm đoạn thẳng

 Phương trình đoạn thẳng đi qua hai điểm

y 2  y1
y x  x1   y1
x 2  x1

 Khai triển ta có dạng : y = mx + b , trong đó :

7
Khái niệm đoạn thẳng
Để đơn giản giải thuật chúng ta chỉ xét các đường
thẳng có hệ số góc dương và nhỏ hơn 1 để đảm bảo
sự thay đổi của x sẽ lớn hơn của y.

y1<y2 y1<y2
-1 > k > - 1<k<
x1<x2
0k1
x2<x1
0  k  -1
(x2, y2)

x2<x1 (x1, y1)


x1<x2
0<k1
0 > m  -1

y2<y1 y2<y1
1<k< -1 > k > -

8
Các thuật toán vẽ đoạn thẳng

 Thuật toán DDA (Digital Defferencial Analyzer)


 Thuật toán Bresenham
 Thuật toán Trung điểm (MidPoint)

9
1.1. Thuật toán DDA
 DDA- Digital Defferencial Analyzer = Finite defferences
- Xét các đường thẳng có hệ số góc dương và nhỏ hơn 1 để đảm bảo sự thay
đổi của x sẽ lớn hơn của y.
- Giả sử tại bước thứ i ta đã xác định được xi và yi. Ta cần xác định bước thứ
i+1
xi+1=xi +1
- Giá trị của y sẽ tương ứng từ phương trình sau:
yi+1= yi+ k(xi+1- xi);
 yi+1= yi+ k

- Vì k là số thực nên để thu yi+1 nguyên ta


buộc phải làm tròn trước khi đưa tọa độ
truy xuất lên màn hình.
Ví dụ (2,3) -> (12,9)

10
1.1. Thuật toán DDA

11
1.1. Thuật toán DDA

12
1.1. Thuật toán DDA

 Nhận xét thuật toán DDA


 Không có phép nhân
 Có phép chia và làm tròn số -> chậm

 Quy tắc tổng quát khi vẽ đồ họa:


 Cộng và trừ nhanh hơn nhân
 Nhân nhanh hơn chia
 Sử dụng bảng để đánh giá hàm rời rạc nhanh hơn tính toán
 Tính toán số nguyên nhanh hơn số thực
 Tránh các tính toán không cần thiết nhờ nhận ra các trường
hợp đặc biệt của đường vẽ

13
1.2. Thuật toán Bresenham (line)
yi+1
 Giả sử vừa vẽ điểm tại (xi, yi), bây giờ y = ax + b

phải xác định điểm sẽ vẽ thuộc một yi

trong 8 pixel liền kề: (xi+1, yi), (xi-1, yi), yi-1

(xi, yi-1), (xi, yi+1)... xi-1 xi xi+1

 Hình dạng đoạn thẳng phụ thuộc vào


các giá trị dx và dy
 dx=0 -> đ/thẳng song song trục y y1<y2 y1<y2
-1 > k > - 1<k<
 dy=0 -> đ/thẳng song song trục x x1<x2
x2<x1 0k1
 dx>0 -> tọa độ x biến thiên tăng dần 0  k  -1
(x2, y2)
 dx<0 -> tọa độ x biến thiên giảm dần
 Xét tương tự với dy x2<x1 (x1, y1)
x1<x2
0<k1 0 > k  -1
 Nếu abs(dx)>abs(dy): y=f(x)
 Nếu abs(dx)<abs(dy): x=f(y) y2<y1 y2<y1
1<k< -1 > k > -

14
1.2. Thuật toán Bresenham (line)

15
1.2. Thuật toán Bresenham (line)
 Xét đoạn thẳng có hệ số góc 0k1.
 Điểm vừa chọn là (x,y) -> điểm tiếp theo sẽ vẽ là
(x+1,y) hay (x+1, y+1).

 Việc chọn điểm S hay P phụ thuộc vào việc so sánh


d1 và d2 hay dấu của d1 - d2

16
1.2. Thuật toán Bresenham (line)
 Nhận xét rằng do Dx >0 nên dấu của biểu thức d1-d2
cũng chính là dấu của pi. Hay nói một cách khác, nếu
tại bước thứ i ta xác định được dấu của pi thì xem
như ta xác định được điểm cần chọn ở bước (i+1).

17
1.2. Thuật toán Bresenham (line)
void LineBres (int x1, int y1, int x2, int y2)
{
int Dx, Dy, p, Const1, Const2;
int x, y;
Dx = x2 - x1; Dy = y2 - y1;
p = 2*Dy - Dx; // Dy <<1 - Dx
Const1 = 2*Dy; // Dy <<1
Const2 = 2*(Dy-Dx); // (Dy-Dx) <<1
x = x1; y = y1;
putpixel(x, y, Color);

for(i=x1; i<x2; i++)


{
if (p<0) p += Const1;
else{
p += Const2;
y++;
}
x++;
putpixel(x, y, Color);
}
} // LineBres
18
1.2. Thuật toán Bresenham (line)

void breline (x1,y1,x2,y2)


{
int x, y, dx, dy, color; float D;
dx=x2-x1; dy=y2-y1; D=dx-2dy;
x=x1; y=y1;
while (x<=x2)
{
putpixel (x,y,color)
If (D>0) D=D-2dy;
Else {D=D +2dx-2dy; y=y+1}
x=x+1;
}
}

19
1.2. Thuật toán Bresenham (line)

 Thuật toán Bresenham chỉ làm việc trên số nguyên.

 Các thao tác trên số nguyên chỉ là phép cộng và phép dịch
bit (phép nhân 2) điều này là một cải tiến làm tăng tốc độ
đáng kể so với thuật toán DDA.

 Ý tưởng chính của thuật toán nằm ở chỗ xét dấu pi để quyết
định điểm kế tiếp.

 Sử dụng công thức truy hồi pi+1 - pi để tính pi bằng các phép
toán đơn giản trên số nguyên.

 Thuật toán này cho kết quả tương tự như thuật toán DDA.

20
1.3. Thuật toán trung điểm (line)
 Pitteway công bố 1967, Van Aken cải tiến 1984
 Giả sử ta đã chọn P để vẽ, xác định pixel tiếp theo tại P hay S
 Giao của đường thẳng với Xp+1 tại Q, M là trung điểm của P và S
 Ý tưởng: M nằm phía nào của đường thẳng, nếu M phía trên
đường thẳng thì chọn S, ngược lại chọn P.
 Nhiệm vụ: Xác định M ở đâu.

M”
yp+1/2
P

Q M’
M yp+1/2 yp+1/2

S
O=(xp, yp) xp+1 xp+2

21
1.3. Thuật toán trung điểm (line)
Thuật toán MidPoint đưa ra cách chọn yi+1 là yi hay yi+1 bằng cách
so sánh điểm thực Q(xi+1,y) với điểm MidPoint là trung điểm của S
và P. Ta có :
 Nếu điểm Q nằm dưới điểm MidPoint, ta chọn S.
 Ngược lại nếu điểm Q nằm trên điểm MidPoint chọn P.

22
1.3. Thuật toán trung điểm (line)

23
1.3. Thuật toán trung điểm (line)
procedure MidpointLine(x0, y0, x1, y1, color: integer)
{
int: dx, dy, x, y, d, incrS, incrP; while x<x1
dx := x1 – x0; {
dy := y1 – y0; if d<=0 //Select S
d := 2*dy-dx; {
incrS := 2*dy; d := d+incrS;
incrP := 2*(dy-dx); x := x+1
}
x :=x0;
else //Select P
y :=y0;
{
putpixel(x, y, color);
d := d+incrP;
x :=x+1;
y :=y+1
Nhận xét rằng thuật toán MidPoint cho kết }
quả tương tự như thuật toán Bresenham putpixel(x, y, color);
} {while}
}

24
Thuộc tính của đường vẽ

 Thuật toán vẽ đoạn thẳng nói trên đều vẽ đoạn


thẳng có độ rộng 1 pixel, nét liên tục
 Hai thuộc tính quan trọng của đường vẽ
 Độ rộng: vẽ đoạn thẳng từ (x0, y0) đến (x1, y1)
 Nếu dy>dx: các pixel được vẽ thêm tại tọa độ bên trái và
bên phải điểm vẽ (x-1 và x+1)
 Nếu dx>dy: vẽ thêm các pixel phía trên và dưới điểm vừa
vẽ
 Đường nét đứt:
 Sử dụng các pattern, mặt nạ với bit cao nhất bằng 1
 Dựa trên kết quả phép AND mặt nạ với mẫu để quyết định
có vẽ điểm ảnh tại vị trí hiện hành hay không.

25
2
CÁC THUẬT TOÁN
VẼ ĐƯỜNG TRÒN
 Một số tính chất đường tròn
 Thuật toán Bresenham
 Thuật toán trung điểm

26
Tính chất của đường tròn
 Tương tự như vẽ đoạn thẳng, đường
tròn đồ họa hình thành bởi các pixel
gần đường tròn toán học nhất
(Rasterization).
 Một vài tính chất cơ bản:
 Vẽ đường tròn tâm tại gốc tọa độ sau
đó dịch chuyển đến vị trí mong muốn
 Tính đối xứng: khi biết tọa độ 1 điểm
(-y, x) (y, x)
dễ dàng suy ra tọa độ của 7 điểm
còn lại
(-x, y) (x, y)
 Sử dụng phương trình để tính tọa độ 450
đường tròn -> dấu phảy động. (-x, -y)
 Các thuật toán tối ưu khác (x, -y)

(-y,-x) (y, -x)

27
2.1. Thuật toán Bresenham

 Ý tưởng
 Giả sử tại bước thứ i ta đã xác định được (xi,yi)
 Tại bước thứ i+1
 Ta có xi+1 = xi +1
 Gọi yi+1 là giá trị chính xác của tung độ tương ứng với điểm
có hoành độ là (xi +1)
 d1 là khoảng cách giữa yi và yi+1
 d2 là khoảng cách giữa yi+1 và (yi -1)
 Khi đó nếu d1 < d2 thì yi+1 = yi
 Ngược lại yi+1 = yi – 1

28
2.1. Thuật toán Bresenham

 Phương trình đường tròn


x2  y 2  R2
 Phương trình đường tròn có hàm mũ tại y nên nếu tính d1, d2
theo y thì sẽ có hàm căn làm chậm thuật toán, do vậy ta đặt:
d1'  yi2  yi21
d2'  yi21  ( yi  1)2
Đặt pi  d1  d2
' '

 Tính pi+1 theo pi

29
2.1. Thuật toán Bresenham

1. Chọn vị trí thứ nhất để vẽ có tọa độ (x1, y1)=(0, r)


2. Tính tham số thứ nhất: p1=3-2r
 Nếu p1<0: vị trí vẽ tiếp theo là (x1+1, y1). Ngược lại vẽ tại
tọa độ (x1+1, y1-1).
3. Tiếp tục tăng x để tính p tiếp theo từ p trước đó
 Nếu trước đó có pi<0: pi+1=pi+4xi+6
 Ngược lại, ta có: pi+1=pi+4(xi-yi)+10
 Nếu kết quả pi+1<0: điểm sẽ chọn tiếp theo là (xi-2, yi+1).
 Ngược lại, ta chọn: (xi+2, yi+1-1).
 Nếu pi<0 thì yi+1= yi, ngược lại yi+1= yi-1 yi
4. Lặp lại bước 3 cho đến khi x=y. y
yi-1

xi+1

30
2.2. Thuật toán trung điểm
 Ý tưởng thuật toán: Khi đã vẽ điểm P tại (xp, yp), phải
quyết định điểm vẽ tiếp theo là E hay SE
 Phương trình đường tròn
F ( x, y )  x 2  y 2  R 2 P=(xp, yp)
E
 F(x,y)=0 -> (x,y) trên đường tròn ME
M
 F(x,y)<0 -> (x,y) trong đường tròn
SE
 F(x,y)>0 -> (x,y) ngoài đường tròn MSE

 Nếu M trong vòng tròn -> E gần đường tròn


 Ngược lại -> SE gần đường tròn

31
Thuật toán trung điểm vẽ đường tròn
 Biến quyết định d: giá trị hàm tại điểm giữa M
d old  F ( x p  1, y p  12 )  ( x p  1) 2  ( y p  12 ) 2  R 2
 Nếu dold<0 thì chọn E, xp tăng 1, yp giữ nguyên.

d new  F ( x p  2, y p  12 )  ( x p  2) 2  ( y p  12 ) 2  R 2

d new  dold  (2 x p  3)  dold   E


P=(xp, yp)
E
 Nếu dold>0 thì chọn SE, xp tăng 1, yp giảm 1. ME
M

d new  F ( x p  2, y p  3 2 ) SE
MSE
 ( x p  2)  ( y p  )  R
2 3 2
2
2

d new  dold  (2 x p  2 y p  5)  dold   SE

32
2.2. Thuật toán trung điểm

 Vòng lặp của thuật toán


 Chọn pixel để vẽ dựa trên dấu biến quyết định d của vòng
lặp trước
 Cập nhật biến quyết định d bởi giá trị  tương ứng với
pixel SE hay E vừa chọn
 Giá trị khởi đầu
 Điểm vẽ đầu tiên có tọa độ (0, R) P=(xp, yp)
E
 Biến quyết định d có giá trị:
ME
M
d  F (1, R  12 )  1  ( R  R  14 )  R  54  R
2 2

SE
MSE
 Đặt biến quyết định mới h=d-1/4, ta có:
h  14  54  R
h  1 R
33
2.2. Thuật toán trung điểm
procedure MidpointCircle(radius, color: integer);
{Giả sử tâm đường tròn tại gốc tọa độ}
var
procedure CirclePoints(x, y,
x, y: integer; d: real;
color: interger); begin
begin x:=0;
y:=radius;
WritePixel(x,y, color);
d:=1-radius;
WritePixel(y,x, color); CirclePoints(x, y, color);
while y>x do
WritePixel(y,-x, color); begin
WritePixel(x,-y, color); if d<0 then {Chọn E}
begin
WritePixel(-x,-y, color); d:=d+2*x+3;
WritePixel(-y,-x, color); x:=x+1
end
WritePixel(-y,x, color); else { Chọn SE }
WritePixel(-x,y, color); begin
d:=d+2*(x-y)+5;
end; x:=x+1;
y:=y-1
end;
CirclePoints(x, y, color);
end {while}
end;
34
2.3. Thuật toán trung điểm (eclíp)

 Phương trình elíp có tâm tại gốc tọa độ


F ( x, y )  b 2 x 2  a 2 y 2  a 2 b 2  0
 Áp dụng giải pháp trung điểm vẽ đường tròn để vẽ
elíp
 Tính đối xứng của elíp: khi biết tọa độ 1 điểm có thể dễ
dàng suy ra tọa độ ba điểm khác.
Tangent
slope=-1
E Gradient vector

j component
Gradient vector

SE
Region 1
S SE
Region 2
i component

35
2.3. Thuật toán trung điểm (eclíp)

 Tìm ranh giới hai miền trong ¼ elíp


 Vị trí: Điểm P là tiếp điểm của tiếp tuyến có hệ số góc –1
 Xác định:
 Véc tơ vuông góc với tiếp tuyến tại tiếp điểm -> gradient
F F
gradF( x, y )  i j  2b 2 x.i  2a 2 y. j
x y
 Tại P1 các thành phần i và j của véc tơ gradient có cùng độ
lớn
Tangent
slope=-1
Miền 1: Thành
phần i lớn hơn E Gradient vector

j component
Gradient vector
thành phần j
SE
a y b x
2 2 Region 1
S SE
Region 2
i component

36
2.3. Thuật toán trung điểm (eclíp)

 Ý tưởng: Đánh giá hàm tại điểm giữa hai tọa độ pixel để chọn
vị trí tiếp theo để vẽ. Dấu của nó cho biết điểm giữa nằm trong
hay ngoài elíp.
 Với vùng 1:
 Tính biến quyết định d=F(x,y)=F(xp+1, yp-1/2)
 Nếu d<0: chọn E, x tăng 1, y không thay đổi.
E
d old  F ( x p  1, y p  12 )  b 2 ( x p  1) 2  a 2 ( y p  12 ) 2  a 2b 2
P1
d new  F ( x p  2, y p  12 )  b 2 ( x p  2) 2  a 2 ( y p  12 ) 2  a 2b 2 SE
Region 1
d new  d old  b (2 x p  3)  d old   E
2
Region 2
S SE

 Nếu d0: chọn SE, x tăng 1, y giảm 1


d new  F ( x p  2, y p  32 )  b 2 ( x p  2) 2  a 2 ( y p  32 ) 2  a 2b 2
d new  d old  b 2 (2 x p  3)  a 2 (2 y p  2)  d old   SE

37
2.3. Thuật toán trung điểm (eclíp)

 Với vùng 2:
 Tính biến quyết định d =F(x, y)=F(xp+1/2, yp-1)
 Nếu d<0: chọn SE, x tăng 1, y giảm 1.
 Nếu d0: chọn S, x không tăng, y giảm 1
 Tìm số gia như vùng 1
S = a2(-2yp+3) E

SE= b2(2xp+2)+a2(-2y+3) SE
P1
Region 1
S SE
Region 2

38
2.3. Thuật toán trung điểm (eclíp)

 Tìm giá trị khởi đầu của số gia d


 Miền 1:
 Giả sử a, b nguyên; điểm bắt đầu vẽ là (0, b)
 Điểm giữa thứ nhất: (1, b-1/2)
2
a
F (1, b  12 )  b  a (b  )  a b  b  a (b  14 )  b  a b 
2 2 1 2
2
2 2 2 2 2 2

4
 Miền 2:
 Phụ thuộc vào điểm giữa (xp+1, yp-1/2) của điểm tiếp theo điểm
cuối cùng của miền 1.
E
F ( x p  , y p  1)  b ( x  )  a ( y  1)  a b
1
2
2 1 2
2
2 2 2 2

P1
2 SE
b Region 1
 b x  b x   a 2 ( y  1) 2  a 2b 2
2 2 2
S SE
4 Region 2

39
2.3. Thuật toán trung điểm (eclíp)
procedure draw_ellipse(a, b, color: integer); EllipsePoints (x, y, color);
var x, y: integer; d1, d2: real; end {Vùng 1}
begin
d2=b2(x+1/2)2+a2(y-1)2 –a2b2;
x:=0; {Khởi động}
while y>0 do {Vùng 2}
y:=b;
begin
d1:=b2-a2b+a2/4; if d2<0 then { Chon SE }
EllipsePoints(x, y, color); begin
while (a2(y-1/2)>b2(x+1)) do {Vùng 1} d2:=d2+b2(2*x+2)+a2(-2*y+3);
begin x:=x+1;
if d1<0 then {Chọn E} y:=y-1
begin end
d1:=d1+b2(2*x+3); else
x:=x+1 begin
d2:=d2+a2(-2*y+3);
end
y:=y-1
else {Chọn SE}
end
begin
EllipsePoints (x, y, color);
d1:=d1+b2(2*x+3)+a2(-2*y+2); end {Vùng 2}
x:=x+1; end
y:=y-1
end;
40
Bài tập chương 3

Kết hợp việc sử dụng OpenGL để cài đặt các giải thuật
sau đây:

1. Cài đặt các thuật toán DDA, Bresenham, trung điểm


(MidPoint) vẽ đoạn thẳng qua hai điểm cho trước.
2. Cài đặt hàm vẽ hình chữ nhật, đường gấp khúc, đa
giác từ hàm vẽ đoạn thẳng (từ các hàm trên) với các
tọa độ đỉnh cho trước.
3. Cài đặt thuật toán Bresenham để vẽ đường tròn có
tâm là gốc tọa độ, bán kính R. (gố tọa độ và R được
cho trước)

41

You might also like