CHƯƠNG 2 : CÁC GIẢI THUẬT SINH THỰC THỂ CƠ SỞ
2. CÁC GIẢI THUẬT XÂY DỰNG THỰC THỂ CƠ SỞ
2.10. Giải thuật sinh đa giỏc (Polygon)
a. Thuật giải vẽ đường bao đa giỏc
Việc biểu diễn đa giỏc thụng qua: - Tập cỏc đoạn thẳng
- Tập cỏc điểm thuộc đa giỏc Cỏc loại đa giỏc:
Hỡnh 2.14 Cỏc loại đa giỏc
Đa giỏc lồi: là đa giỏc cú đường thẳng nối bất ký 2 điểm bờn trong nào của đa giỏc đều nằm
trọn trong đa giỏc. Đa giỏc khụng lồi là đa giỏc lừm.
Cỏc đường thẳng bao đa giỏc - cạnh của đa giỏc. Cỏc điểm giao của cạnh - đỉnh của đa giỏc. Thụng tin cần thiết để xỏc định đa giỏc:
- Số cạnh
- Toạ độ cỏc đỉnh của đa giỏc Giải thuật:
Polygon (arrayx, arrayy,n) { if (n<3//khụng phải đa giỏc exit;
for (i=1 ; i<= n-1; i++)
line(arrayx[i],arrayy[i], arrayx[i+1], arrayy[i+1]); line(arrayx[i+1],arrayy[i+1], arrayx[1], arrayy[1]); }
b. Cỏc thuật toỏn tụ miền kớn đa giỏc
Lợi thế của hiển thị raster là: khả năng lưu trữ, copy, tụ màu một vựng...Cú hai dạng vựng tụ thường gặp đú là: tụ bằng một màu thuần nhất (solid fill), tụ theo mẫu tụ (fill pattern) nào đú.
Cũn thiết bị vector thỡ hạn chế do cỏc vựng tụ màu tạo ra bởi một tập cỏc đoạn thẳng sỏt nhau - làm chậm quỏ trỡnh làm tươi.
+ Giải thuật đường biờn (Boundary - fill Algorithm) - Bắt đầu từ 1 điểm (x,y) trong vựng cần được tụ màu:
+ Xỏc định màu điểm: getpixel(x,y,c)
- Bước tiếp: kiểm tra thuộc tớnh màu cỏc điểm lõn cận
+ điểm lõn cận đó tụ màu (exit)
+ trựng với màu đường biờn(exit) + Nếu khụng thỡ tụ màu
Cỏc phương phỏp xỏc định điểm lõn cận
Hỡnh 2.15 Phương phỏp tịnh tiến giải thuật
Giải thuật tụ màu đường biờn:
#include <graphics.h> #include <conio.h>
void FloodFill (int x, int y, int in_color, int new_color){ if (getpixel(x, y) == in_color){
putpixel(x, y, new_color);
FloodFill(x-1, y, in_color, new_color); FloodFill(x+1, y, in_color, new_color); FloodFill(x, y-1, in_color, new_color); FloodFill(x, y+1, in_color, new_color); }
}
void main(){
int gr_drive = DETECT, gr_mode; initgraph(&gr_drive, &gr_mode, ""); circle(getmaxx() / 2, getmaxy() / 2, 15); FloodFill(getmaxx() / 2, getmaxy() / 2, 0, 4); getch(); closegraph(); }
+Giải thuật dũng quột (scanline) cho việc tụ màu vựng
Giải thuật dựa trờn ý tưởng sử dụng một đường quột trờn trục y của màn hỡnh đi từ ymax đến ymin của vựng cần được tụ màu.
Với mỗi giỏ trị y = yi đường thẳng quột cắt cỏc đường biờn của vựng cần tụ tạo ra đoạn
thẳng y = yi với x ∈[xmin, xmax]. Trờn đoạn thẳng đú chỳng ta tụ màu cỏc điểm tương ứng đi từ xmin
đến xmax cú cỏc điểm tụ (xi, yi) ∈y = yi.
- Đơn giản nhất vớ dụ tụ màu hỡnh chữ nhật:
void scanline_rectg(x1,y1,x2,y2,c){ int i,j; for(i=y1; i>=y2; i--)
for(j=x1; j<= x2;j++) putpixel(i,j,c); }
- Phộp tụ màu 1 đa giỏc bất kỳ sẽ phức tập hơn rất nhiều so với hỡnh chữ nhật
Giả sử vựng tụ được cho bởi 1 đa giỏc n đỉnh: pi (xi,yi), i=0,1,....,n-1. Đa giỏc này cú thể là
đa giỏc lồi, đa giỏc lừm hay đa giỏc tự cắt....
Cỏc bước túm tắt chớnh của thuật toỏn:
- Tỡm ytop, ybottom lần lượt là giỏ trị lớn nhất, nhỏ nhất của tập cỏc tung độ của cỏc đỉnh của
đa giỏc đó cho.
ytop = max{yi,(xi,yi) ∈P}, ybottom = min{yi,(xi,yi) ∈P}.
- Ứng với mỗi dũng quột y=k, với k thay đổi từ ybottom đến ytop lặp:
+ Tỡm tất cả cỏc hoành độ giao điểm của dũng quột y=k với cỏc cạnh của đa giỏc + Sắp xếp cỏc hoành độ giao điểm theo thứ tự tăng dần: xo,x1,....
+ Tụ màu cỏc đoạn thẳng trờn đường thẳng y=k lần lượt được giới hạn bởi cỏc cặp (xo,x1), (x2,x3), ......, (x2k,x2k+1).
Chỳng ta sẽ gặp 1 số vấn đề sau:
- Ứng với mỗi dũng quột khụng phải lỳc nào tất cả cỏc cạnh của đa giỏc cũng tham gia cắt dũng quột. Do đú để cải thiện tốc độ cần phải cú một cỏch nào đú để hạn chế được số cạnh cần
tỡm giao điểm ứng với mỗi dũng quột.
- Nếu số giao điểm tỡm được giữa cỏc cạnh đa giỏc và dũng quột là lẻ (điều này chỉ xảy ra khi dũng quột sẽ đi qua cỏc đỉnh của đa giỏc) khi đú ta sẽ tớnh số điểm là 2 thỡ cú thể tụ khụng
chớnh xỏc. Ngoài ra, việc tỡm giao điểm của dũng quột với cỏc cạnh nằm ngang là trường hợp đặt biệt...
Hỡnh 2.16 Giải thuật scanline cho một đa giỏc bất kỳ
Để giải quyết cỏc vấn đề trờn ta cú cỏc phương phỏp sau:
+ Danh sỏch cỏc cạnh kớch hoạt (AET - Active Edge Table)
Mỗi cạnh của đa giỏc được xõy dựng từ 2 đỉnh kề nhau Pi(xi,yi) và Pi+1(xi+1,yi+1) gồm cỏc thụng tin sau:
ymin: giỏ trị nhỏ nhất trong 2 đỉnh của cạnh
x y yqmax yq yqmin yq
xIntersect: hoành độ giao điểm của cạnh với dũng quột hiện đang xột DxPerScan: giỏ trị 1/m (m là hệ số gúc của cạnh)
DeltaY: khoảng cỏch từ dũng quột hiện hành tới đỉnh ymax
Danh sỏch cỏc cạnh kớch hoạt AET: danh sỏch này dựng để lưu cỏc tập cạnh của đa giỏc cú thể cắt ứng với dũng quột hiện hành và tập cỏc điểm giao tương ứng. Nú cú một số đặc điểm:
Cỏc cạnh trong danh sỏch được sắp xếp theo thứ tự tăng dần của cỏc hoành độ giao điểm để cú thể tụ màu cỏc đoạn giao một cỏch dễ dàng.
Thay đổi ứng với mỗi dũng quột đang xột, do đú danh sỏch này sẽ được cập nhật liờn tục
trong quỏ trỡnh thực hiện thuật toỏn. Đầu tiờn ta cú danh dỏch chứa toàn bộ cỏc cạnh của đa giỏc gọi là ET (Edge Table) được sắp xếp theo thứ tự tăng dần của ymin, rồi sau mỗi lần dũng quột thay
đổi sẽ di chuyển cỏc cạnh trong ET thoả điều kiện sang AET.
Một dũng quột y=k chỉ cắt 1 cạnh của đa giỏc khi và chỉ khi k>=ymin và Δy>0. Chớnh vỡ vậy mà với cỏc tổ chức của ET (sắp theo thứ tự tăng dần của ymin) điều kiện để chuyển cỏc cạnh từ ET sang AET sẽ là k>=ymin; và điều kiện để loại một cạnh ra khỏi AET là Δy<=0
+ Cụng thức tỡm giao điểm nhanh
Nếu gọi xk,xk+1 lần lượt là cỏc hoành độ giao điểm của một cạnh nào đú với cỏc dũng quột y=k và y=k+1 ta cú:
xk+1 - xk = 1/m ((k+1) - k) = 1/m hay xk+1 = xk + 1/m
Như vậy nếu lưu hoành độ giao điểm ứng với dũng quột trước lại, cựng với hệ số gúc của cạnh, ta xỏc định được hoành độ giao điểm ứng với dũng quột kế tiếp theo cụng thức trờn. Nờn
thụng tin của cạnh cú 2 biến: DxPerScan , xIntersect. + Trường hợp dũng quột đi ngang qua một đỉnh:
Tớnh 1 giao điểm nếu chiều của 2 cạnh kề của đỉnh đú cú xu hướng tăng hay giảm
Tớnh 2 giao điểm nếu chiều của 2 cạnh kề của đỉnh đú cú xu hướng thay đổi, nghĩa là tăng- giảm hay giảm-tăng.
Hỡnh 2.17 Qui tắc tớnh: một giao điểm (A) và hai giao điểm (B)
+ Giải thuật tụ vựng kớn theo mẫu (Pattern filling) object (ảnh mẫu)
A[m,n]
Vấn đề: xỏc định điểm ở mẫu và nhiều điểm tương ứng với chỳng trờn màn hỡnh. Phương phỏp 1:
Tỡm điểm neo ở đầu trỏi nhất hàng đầu tiờn của đa giỏc.
Pi Pi Pi Pi Pi-1 Pi-1 Pi-1 Pi-1 Pi+1 Pi+1 Pi+1 Pi+1 A B
Nhược điểm: khụng cú điểm định vị trớ phõn biệt một cỏch rừ ràng cho mẫu tụ trong một đa giỏc bất kỳ.
Phương phỏp 2: sử dụng cho SRGP
Lấy điểm neo ở gốc toạ độ, giả sử ta coi cả màn hỡnh được lỏt bởi màu tụ cỏc thực thể là cỏc
đường biờn cho cỏc vựng tụ, vậy nếu ngoài cỏc thực thể cỏc màu tụ khụng được phộp thể hiện.
Hỡnh 2.18 Phương phỏp lấy điểm neo Túm tắt chương:
Cỏc đối tượng đồ hoạ cơ sở cung cấp cỏc cụng cụ cơ bản nhất cho việc xõy dựng cỏc ảnh đồ hoạ của cỏc đối tượng phức tạp. Cỏc đoạn thẳng, đường cong, vựng tụ, ký tự....là cỏc đối tượng đồ hoạ cơ sở được hầu hết tất cả cỏc cụng cụ lập trỡnh đồ hoạ hỗ trợ.
Để cú thể hiển thị cỏc đối tượng đồ hoạ trờn thiết bị hiển thị dạng điểm mà điển hỡnh là màn
hỡnh, cần phải cú một quỏ trỡnh chuyển cỏc mụ tả hỡnh học của cỏc đối tượng này trong hệ toạ độ thế giới thực về dóy cỏc pixel tương ứng gần với chỳng nhất trờn toạ độ thiết bị. Quỏ trỡnh này cũn
được gọi là quỏ trỡnh chuyển đổi bằng dũng quột. Yờu cầu quan trọng nhất đối với quỏ trỡnh này
ngoài việc phải cho kết quả xấp xỉ tốt nhất cũn phải cho tốc độ tối ưu.
Ba cỏch tiếp cận để vẽ đoạn thẳng gồm thuật toỏn DDA, thuật toỏn Bresenham, thuật toỏn Midpiont đều tập trung vào việc đưa ra cỏch chọn một trong hai điểm nguyờn kế tiếp khi đó biết
điểm nguyờn ở bước trước. Thuật toỏn DDA đơn giản chỉ dựng thao tỏc làm trũn nờn phải dựng
cỏc phộp toỏn trờn số thực, trong khi đú thuật toỏn Bresenham và Midpiont đưa ra cỏch chọn phức tạp hơn nhưng cho kết quả tốt hơn. Tương tự dựng hai giải thuật Bresenham và Midpiont để vẽ
đường trũn và ellpise và một số đường cong khỏc.
Cỏc thuật toỏn tụ màu vựng gồm thuật toỏn loang (đệ qui) hay thuật toỏn dũng quột. Cú thể tụ cựng một màu hay tụ theo mẫu.
Bài tập:
1. Chỉ định cỏc vị trớ mành nào sẽ được chọn bởi thuật toỏn Bresenham lỳc chuyển quột một
đường thẳng từ toạ độ pixel (1,1) sang toạ độ pixel (8,5).
2. Dựng giải thuật Bresenham viết hàm sinh đoạn thẳng (xột tất cả cỏc trường hợp của hệ số gúc).
3. Dựng giải thuật Midpiont viết hàm sinh đoạn thẳng (xột tất cả cỏc trường hợp của hệ số gúc). x y neo neo x y
4. Dựng giải thuật Midpiont viết hàm sinh đường trũn (toạ độ tõm (xc,yc) và bỏn kớnh r). 5. Dựng giải thuật Midpiont viết hàm sinh đường ellipse (toạ độ tõm (xc,yc) và bỏn kớnh rx
và ry ).
6. Từ hàm vẽ đường thẳng thiết kế và cài đặt hàm vẽ cỏc hỡnh sau: hỡnh chữ nhật, đa giỏc,
ngụi nhà....
7. Viết giải thuật tỡm giao điểm hai đoạn thẳng.
8. Viết chương trỡnh tụ màu Floodfill (sử dụng đệ qui với 4-connected).
9. Đưa ra lưu đồ thuật toỏn tụ màu theo dũng quột.
10. Viết thuật toỏn tụ màu scan-line.
Bài tập trắc nghiệm:
1. Xõy dựng giải thuật tổng quỏt để vẽ đường thẳng ta cú xột hệ số k (hệ số gúc của đường) sẽ cú tất cả cỏc trường hợp của k:
a. 4 b. 3 c. 2 d. 1
2. Để biểu diễn đoạn thẳng thụng qua phương trỡnh tham số như sau:
a. y=f(x) hay y=kx+b
b. f(x,y)=0 hay ax + by +c =0
c. x(v)=x1 +v(x2-x1) và y(v) = y1 +v(y2-y1) cú v ∈ [0,1] d. P(u) = P1 + u(P2-P1) cú u ∈ [0,1]
3. Khi xõy dựng giải thuật vẽ đường trũn đầy đủ ta chỉ cần viết phương trỡnh cho 1/8 đường trũn, rồi gọi đối xứng 8 cỏch. Khi đú xảy ra hiện tượng overstrike. Vậy điểm xảy ra hiện tượng đú là: (r là bỏn kớnh của đường trũn)
a. (0,r) và ⎟ ⎠ ⎞ ⎜ ⎝ ⎛ r r 2 1 , 2 1 b. (r,0) hoặc (0,r) và ⎟ ⎠ ⎞ ⎜ ⎝ ⎛ r r 2 1 , 2 1 c. (0,r) và (-r,0) d. (r,0) và (0,r)
4. Giải thuật sau là giải thuật gỡ? Và đó dựng bao nhiờu điểm lõn cận?
void Function (int x, int y, int c1, int c2){ if (getpixel(x, y) == c1){ putpixel(x, y, c2); Function (x-1, y, c1, c2); Function (x+1, y, c1, c2); Function (x+1, y+1, c1, c2); Function (x-1, y-1, c1, c2); Function (x, y-1, c1, c2);
Function (x, y+1, c1, c2); }
}
Giải thuật scanline, số
điểm lõn cận là:
Giải thuật tụ màu
đường biờn, số điểm
lõn cận là:
Giải thuật tụ màu loang, số điểm lõn
cận là:
Giải thuật tụ màu theo mẫu, số màu lõn cận là:
A B c d 5. Giải thuật vẽ đường thẳng sau vẽ cho trường hợp k là:
void Midline(int x1,int y1,int x2,int y2,int c){ int x=x1,y=y1,dx=x2-x1,dy=y2-y1,p=2*dx-dy; while(y<y2) { putpixel(x+320,240-y,c); if(p<=0){ p=p+2*dx; } else{ p=p+2*dx-2*dy; x++; } y++; } } a. 0<= k<=1 b. k>1 c. k<=-1 d. -1<k<0
6. Giải thuật vẽ đường thẳng sau vẽ cho trường hợp k là:
void Midline(int x1,int y1,int x2,int y2,int c){ int x=x1,y=y1,dx=x2-x1,dy=y2-y1,p=2*dy+dx; while(x<x2) { putpixel(x+320,240-y,c); if(p<=0){ p=p+2*dy+2*dx; y--; } else{ p=p+2*dy; } x++; }} a. k>=0 và k<=1 b. k>1 c. k<=-1
7. Giải thuật sau là giải thuật nào?
void Function(int xt, int yt, int r, int c){ int x, y, d; x = 0; y = r; d = 3 - 2 * r; while (x <= y){ putpixel(xt + x, yt + y, c); putpixel(xt - x, yt + y, c); putpixel(xt + x, yt - y, c); putpixel(xt - x, yt - y, c); putpixel(xt + y, yt + x, c); putpixel(xt - y, yt + x, c); putpixel(xt + y, yt - x, c); putpixel(xt - y, yt - x, c); if (d < 0) d += 4 * x + 6; else{ d += 4 * (x-y) + 10; y--; } x++; }}
a. Giải thuật Bresenham xõy dựng đường trũn b. Giải thuật Midpoint xõy dựng đường trũn c. Giải thuật Bresenham xõy dựng đường ellipse d. Giải thuật Midpiont xõy dựng đường ellipse
8. Chương trỡnh sau đưa gỡ ra hỡnh?
#include <graphics.h> #include <conio.h>
void Function(int xc, int yc, int r, int c){ int x, y, d; x = 0; y = r; d = 3 - 2 * r; while (x <= y){ putpixel(xc + x, yc + y, c); putpixel(xc - x, yc + y, c); putpixel(xc - x, yc - y, c); putpixel(xc + y, yc - x, c); putpixel(xc - y, yc - x, c); if (d < 0) d += 4 * x + 6; else{ d += 4 * (x-y) + 10; y--; } x++; } } void main(){
int gr_drive = DETECT, gr_mode; initgraph(&gr_drive, &gr_mode, "");
getch(); closegraph(); }