Thuật tốn vẽ đường trịn

Một phần của tài liệu Giao trinh đồ họa máy tính 2012 (Trang 42)

2.2.1 Nguyên lý chung

Trong hệ tọa độ Descartes, phương trình đường trịn bán kính R cĩ dạng: Với tâm O(0,0) : x2 + y2 = R2

Với tâm C(xc, yc): (x-xc)2+ (y-yc)2=R2 Trong hệ tọa độ cực :

x = xc+ R.cosθ y = yc + R.sinθ với θ ∈ [0, 2π].

Do tính đối xứng của đường trịn C nên ta chỉ cần vẽ 1/8 cung trịn, sau đĩ lấy đối xứng qua 2 trục tọa độ và 2 đường phân giác thì ta vẽ được cả đường trịn.

Với đường trịn tâm (xc, yc) ta cĩ thể vẽ đường trịn tâm (0,0) sau đĩ tịnh tiến theo vecto (xc, yc).

Cho x = 0, 1, 2, ..., int(R x sqrt(2)/2) với R>1. - Tại mỗi giá trị x, tính int(y = sqrt(R2-x2)). - Vẽ điểm (x,y) cùng 7 điểm đối xứng của nĩ.

Cách làm này khơng hiệu quả do gặp phải các phép tốn nhân và lấy căn làm hạn chế tốc độ, ngồi ra đường trịn vẽ ra theo cách này cĩ thể khơng liền nét (trừ trường hợp R lớn) khi x gần R (do chỉ cĩ một giá trị y duy nhất cho một giá trị x). Chúng ta cĩ thể khắc phục điều này bằng cách điều chỉnh đối tượng thay đổi là x (rồi tính y theo x) hay y (rồi tính x theo y) tùy vào giá trị tuyệt đối của hệ số gĩc đường trịn là lớn hơn hay nhỏ hơn 1, nhưng cách làm này địi hỏi thêm các phép tính tốn và kiểm tra nên làm cho thuật tốn phức tạp thêm.

Hình 2.15

Một cách tiếp cận khác là vẽ các điểm (R cos (θ), R sin (θ)), với θ chạy từ 00 đến 900. Cách này sẽ khắc phục hạn chế đường khơng liền nét của thuật tốn trên, tuy nhiên điểm hạn chế chính của thuật tốn này đĩ là chọn bước nhảy cho θ như thế nào cho phù hợp khi bán kính thay đổi.

2.2.2 Thuật tốn trung điểm (MidPoint) vẽ đường trịn

Xét đường trịn tâm tại gốc tọa độ, bán kính R. Xét cung 1/8 thứ hai đường trịn C(1/8), sau đĩ lấy đối xứng

Hình 2.16

Như vậy nếu cĩ (x, y) thuộc (C1/8) thì các điểm : (y, x), (y,-x), (x,-y), (-x,-y), (-y,- x), (-y,x), (-x,y) sẽ thuộc (C).

Chọn điểm bắt đầu để vẽ là điểm (0,R). Dựa vào hình vẽ, nếu (xi, yi) là điểm nguyên đã tìm được ở bước thứ i, thì (xi+1, yi+1) ở bước thứ (i+1) là sự lựa chọn giữa S và P. Như vậy:

xi+1=xi+1 yi+1ϵ{yi, yi-1}

Tương tự như thuật tốn MidPoint vẽ đoạn thẳng, việc quyết định chọn một trong hai điểm S và P sẽ được thực hiện thơng qua việc xét dấu của một hàm nào đĩ tại điểm MidPoint là điểm nằm giữa chúng.

Hình 2.17

Đặt F(x,y)=x2+y2-R2, ta cĩ

F(x,y) <0 nếu (x,y) nằm trong đường trịn F(x,y) =0 nếu (x,y) thuộc đường trịn F(x,y) > 0 nếu (x,y) nằm ngồi đường trịn Gọi M là trung điểm PS

Xét pi=F(M)=F(xi+1, yi-0.5)= (xi+1)2+ (yi-0.5)2-R2 pi+1=F(xi+1+1, yi+1-0.5)= (xi+1+1)2+ (yi+1-0.5)2-R2 Ta cĩ :

+ Nếu pi<0, điểm M nằm trong đường trịn. Lúc này điểm thực Q gần S hơn nên ta chọn S, tức là yi+1=yi

pi+1=F(xi+2, yi-0.5)= (xi+2)2+ (yi-0.5)2-R2 =pi+ 2xi+3

+ Nếu pi>=0, điểm M nằm ngồi đường trịn. Lúc này điểm thực Q gần P hơn nên ta chọn P, tức là yi+1=yi-1

pi+1=F(xi+2, yi-1.5)= (xi+2)2+ (yi-1.5)2-R2 =pi+ 2xi-2yi+5

Tính giá trị p1 ứng với điểm ban đầu (x1, y1) = (0, R) P1=F(1, R-0.5)= 5/4 –R

Cài đặt minh họa thuật tốn MidPoint vẽ đường trịn // Ve 8 diem doi xung

void Put8Pixel(int x, int y) { putpixel(x, y, Color); putpixel(y, x, Color); putpixel(y, -x, Color); putpixel(x, -y, Color); putpixel(-x, -y, Color); putpixel(-y, -x, Color);

putpixel(-y, x, Color);

putpixel(-x, y, Color); } // Put8Pixel

void CircleMidPoint (int R) { int x, y; x = 0; y = R; Put8Pixel(x, y); p = 1 - R; // 5/4-R while (x < y) { if (p < 0) p += 2*x + 3; else { p += 2*(x -y) + 5; y--; } x++; Put8Pixel(x, y); } } // CircleMidPoint (adsbygoogle = window.adsbygoogle || []).push({});

2.3 Thuật tốn vẽ đường elip2.3.1 Nguyên lý chung 2.3.1 Nguyên lý chung

Cho elip tâm (h, k), độ dài trục chính là a, độ dài trục phụ là b Phương trình đường elip được xác định như sau :

(x-h)2/a2+(y-k)2/b2=1.

Phương trình elip với tâm tại gốc tọa độ

x2/b2+y2/b2=1

Elip được chia thành 4 phần đối xứng qua 2 trục tọa độ, do vậy ta chỉ cần vẽ cung ¼ elip sau đĩ thực hiện lấy đối xứng để thu được các phần cịn lại.

Để vẽ elip tâm (h,k) ta cĩ thể thực hiện vẽ elip tâm tại gốc tọa độ sau đĩ tịnh tiến theo véc tơ (h,k).

Tại mỗi bước ta cho x tăng từ 0 đến a sau đĩ tính giá trị y tương ứng qua biểu thức trên, sau đĩ lấy giá trị nguyên gần với giá trị y thực nhất.

Phương pháp này khơng hiệu quả do phải làm nhiều phép tốn lấy bình phương và phép khai căn. Tốc độ thuật tốn chậm.

2.3.2 Thuật tốn trung điểm (MidPoint) vẽ elip

Xét elip tâm tại gốc tọa độ. Phương trình đường elip:

F(x,y)=b2x2+a2y2−a2b2=0

Xét vẽ cung ¼ elip, sau đĩ lấy đối xứng để thu được các phần cịn lại 0<=x<=a

0<=y<=b

Chia cung ¼ elip này thành 2 vùng với điểm chia P là tiếp điểm của tiếp tuyến cĩ hệ số gĩc là -1.

Hình 2.18

Véc tơ gradient vuơng gĩc với tiếp tuyến tại tiếp điểm được xác định như sau: GradF(x,y) = (∂F/∂x)i+(∂F/∂y)j=2b2x.i+2a2y.j

Ta cĩ tiếp tuyến với cung trịn (độ dốc) = -1

Vector gradient cĩ độ dốc là 1, do đĩ tại P các thành phần i và j của vecto gradient cĩ cùng độ lớn.

Trong mỗi vùng thành phần nào của vecto gradient lớn hơn thì xác định trung điểm theo hướng đĩ. Thành phần nhỏ hơn sẽ biến thiên theo từng đơn vị.

Trong vùng 1 thành phần j lớn hơn thành phần i của gradient. a2(yp-0.5)>b2(xp+1).

Trong vùng 2 thì ngược lại. + Xét trên phần 1:

Bắt đầu từ (0,b),

Tại mỗi bước x tăng lên một đơn vị, y biến đổi theo x

bước thứ i (xi,yi), Ở bước i+1 chọn tiếp A(xi+1, yi) hoặc B(xi+1,yi-1). Chọn điểm gần với đường elip nhất dựa trên việc xét dấu của hàm F tại trung điểm M của AB.

Tham số quyết định:

pi =F(M)= F(xi+1,yi-1/2) = b2(xi+1)2 + a2(yi-1/2)2 -a2b2 pi+1 = F(xi+1+1,yi+1-1/2) = b2(xi+1+1)2 + a2(yi+1-1/2)2 -a2b2 - Nếu pi <0 chọn A

xi+1=xi+1 yi+1=yi

pi+1 = b2(xi+1+1)2 + a2(yi+1-1/2)2 -a2b2 = b2(xi+2)2 + a2(yi-1/2)2 -a2b2 = pi + b2(2xi +3) - Nếu pi >=0 chọn B xi+1=xi+1 yi+1=yi -1 pi+1 = b2(xi+2)2 + a2(yi-1.5)2 -a2b2 = pi + b2(2xi +3) + a2(-2yi +2) - Tính P1 khởi tạo tại (0,b)

p1 = F(1,b-1/2) = b2 + a2(b-1/2)2 -a2b2 p1 = b2 - a2b +a2/4 (adsbygoogle = window.adsbygoogle || []).push({});

+ Xét trên phần 2:

Ta lấy toạ độ của Pixel sau cùng trong phần 1 của đường cong để tính giá trị ban đầu cho phần 2.

Tại mỗi bước y giảm từng đơn vị, x biến đổi theo y. Tại bước j ta cĩ điểm (xj,yj).

C(xj,yj-1) hoặc D(xj+1, yj-1). Chúng ta sẽ lựa chọn điểm gần với đường elip nhất. Để quyết định chọn điểm nào chúng ta cĩ thể dựa vào dấu của hàm F tại trung điểm M của đoạn CD Tham số quyết định: qj =F(M)= F(xj+1/2,yj-1) = b2(xj+1/2)2 + a2(yj-1)2 -a2b2 qj+1 = F(xj+1+1/2,yj+1-1) = b2(xj+1+1/2)2 + a2(yj+1-1)2 -a2b2 - Nếu qj <0 chọn D yj+1=yj-1 xj+1=xj +1 qj+1 = b2(xj+1+1/2)2 + a2(yj+1-1)2 -a2b2 = b2(xj+1.5)2 + a2(yj-2)2 -a2b2 =qj + b2(2xj +2) +a2 (-2yj +3) - Nếu qj >=0 chọn C yj+1=yj -1 xj+1= xj qj+1 = b2(xj+1+1/2)2 + a2(yj+1-1)2 -a2b2 = b2(xj+1/2)2 + a2(yj-2)2 -a2b2 =qj + a2(- 2yj+3) - Tính q1 khởi tạo q1 = f(xp+1/2,yp -1) = b2(xp+1/2)2 + a2(yp-1)2 -a2b2 #include <graphics.h> #include <conio.h>

#define ROUND(a) ((long)(a+0.5))

void plot(int xc, int yc, int x, int y, int color){ putpixel(xc+x, yc+y, color);

putpixel(xc-x, yc+y, color); putpixel(xc+x, yc-y, color); putpixel(xc-x, yc-y, color); }

long x, y, fx, fy, a2, b2, p; x = 0; y = b; a2 = a * a; //a2 b2 = b * b; // b2 fx = 0; fy = 2 * a2 * y; // 2a2y plot(xc, yc, x,y, color);

p = ROUND(b2-(a2*b)+(0.25*a)); // p=b2 - a2b + a2/4 while (fx < fy){ x++; fx += 2*b2; //2b2 if (p<0) p += b2*(2*x +3); // p=p + b2 (2x +3) else{ y--; p+= b2*(2*x +3) + a2*(-2*y +2); // p = p + b2(2x +3) + a2 (-2y +2) fy -= 2*a2; // 2a2 }

plot(xc, yc, x, y, color); }

p = ROUND(b2*(x+0.5)*(x+0.5) + a2*(y-1)*(y-1) - a2*b2);//b2(x+1/2)2+a2(y- 1)2 - a2b2

while (y>0){ y--;

fy -= 2*a2; // 2a2 if (p>=0)

p+=a2*(3 - 2*y); p =p + a2(3-2y) else{

x++;

fx += 2*b2; // 2b2

p += b2*(2*x+2) + a2*(-2*y +3); //p=p + b2(2x +2) +a2(-2y +3) }

plot(xc, yc, x, y, color); }

}

int gr_drive = DETECT, gr_mode; initgraph(&gr_drive, &gr_mode, ""); Mid_Ellipse(getmaxx() / 2, getmaxy() / 2, 150, 80, 4); getch(); closegraph(); }

2.4 Các thuật tốn tơ màu

Một vùng tơ bao gồm đường biên và vùng bên trong. Đường biên là một đường khép kín ví dụ như đa giác.

Các thuộc tính của vùng tơ bao gồm:

+ Thuộc tính của đường biên : chính là các thuộc tính như thuộc tính của đoạn thẳng.

+ Thuộc tính của vùng bên trong : bao gồm màu tơ và mẫu tơ. Hình 2.19

Các vùng tơ là một trong những đối tượng đồ họa cơ sở được hầu hết các cơng cụ lập trình đồ họa hỗ trợ. 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) hay tơ theo một mẫu tơ (fill-pattern) nào đĩ.

Một vùng tơ thường được xác định bởi một đường khép kín nào đĩ gọi là đường biên. Một trong những dạng đường biên đơn giản nhất đĩ là đa giác.

Để tơ màu một vùng tơ, người ta thường chia làm hai cơng đoạn : cơng đoạn thứ nhất là xác định các điểm nào để tơ và cơng đoạn cịn lại đơn giản hơn đĩ là quyết định tơ các điểm đĩ bằng giá trị màu nào. Cơng đoạn thứ hai chỉ thực sự phức tạp nếu ta tơ theo một mẫu tơ nào đĩ khơng phải là tơ thuần một màu.

Cĩ hai cách tiếp cận chính để tơ màu một vùng tơ đối với thiết bị hiển thị dạng điểm đĩ là : tơ theo dịng quét (scan-line fill) và tơ dựa theo đường biên (boundary fill).

Phương pháp tơ theo dịng quét sẽ xác định các phần giao của các dịng quét kế tiếp nhau với đường biên của vùng tơ, sau đĩ sẽ tơ màu các điểm thuộc về phần giao này. Cách tiếp cận này thường được dùng để tơ màu các đa giác, đường trịn, ellipse, và một số đường cong đơn giản khác. Phương pháp tơ dựa theo đường biên sẽ bắt đầu từ một điểm ở bên trong vùng tơ và từ đĩ loang dần ra cho tới khi ta gặp các điểm biên. Cách tiếp cận này thường được dùng cho các vùng tơ cĩ dạng đường biên phức tạp hơn. (adsbygoogle = window.adsbygoogle || []).push({});

2.4.1 Thuật tốn tơ màu dựa theo dịng quét

Giả sử vùng tơ được cho bởi một đa giác N đỉnh : Pi(xi, yi),i=0,…,N-1. Đa giác này cĩ thể là đa giác lồi, đa giác lõm, và cả đa giác tự cắt, …

Hình sau minh họa ý tưởng chính của thuật tốn. Với mỗi dịng quét, ta sẽ xác định phần giao của đa giác và dịng quét rồi tơ màu các pixel thuộc đoạn giao đĩ. Để xác định các đoạn giao ta tiến hành việc tìm giao điểm của dịng quét với các cạnh của đa giác, sau đĩ các giao điểm này sẽ được sắp theo thứ tự tăng dần của hồnh độ giao điểm. Các đoạn giao chính là các đoạn thẳng được giới hạn bởi từng cặp giao điểm một, ví dụ như (0,1), (2,3), ….

Hình 2.20: Thuật tốn Scan-line với một dịng quét nào đĩ. Ta cĩ thể tĩm bắt các bước chính của thuật tố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 :

+ Sắp xếp các hồnh độ giao điểm theo thứ tự tăng dần : x0, 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

(x0,x1), (x2, x3), ….

Nếu chỉ dừng ở mức này và chuyển sang cài đặt, chúng ta sẽ gặp một số vấn đề sau :

+ Nhận xét rằng, ứ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.

+ Việc tìm giao điểm của cạnh đa giác với mỗi dịng quét sẽ gặp các phép tốn phức tạp như nhân, chia, … trên số thực nếu ta dùng cách giải hệ phương trình tìm giao điểm. Điều này sẽ làm giảm tốc độ thuật tốn khi phải lặp đi lặp lại nhiều lần thao tác này khi dịng quét quét qua đa giác.

+ 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ẻ thì việc nhĩm từng cặp giao điểm kế tiếp nhau để hình thành các đoạn tơ cĩ thể sẽ khơng chính xác. Điều này chỉ xảy ra khi dịng quét đi ngang qua các đỉnh của đa giác. Nếu tính số giao điểm tại đỉnh dịng quét đi ngang qua là hai thì cĩ thể sẽ cho kết quả tơ khơng chính xác như trong trường hợp của hình dưới. Ngồ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à một trường hợp đặc biệt cần phải cĩ cách xử lí thích hợp.

Để giải quyết các vấn đề trên, cần phải xây dựng một cấu trúc dữ liệu và thuật tốn thích hợp đối với chúng.

Danh sách các cạnh kích hoạt AET (Active Edge Table) Hình 2.21

Cạnh đa giác (EDGE)

Mỗi cạnh của đa giác được xây dựng từ hai đỉnh kề nhau Pi(xi,yi) và Pi+1(xi+1,yi+1) gồm các thơng tin sau :

ymin: giá trị tung độ nhỏ nhất trong 2 đỉnh của cạnh.

xIntersect : hồ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 theo thứ tự tăng dần của các hồ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 tốn. Để hỗ trợ cho thao tác này, đầu tiên người ta sẽ tổ chức một danh sách chứa tồn bộ các cạnh của đa giác gọi là ET (Edge Table) được sắ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 thỏa điều kiện sang AET.

+ Một dịng quét y = k chỉ cắt một cạnh của đa giác khi và chỉ khi: k>= ymin

delta Y>0

Chính vì vậy mà với cách 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à deltaY <= 0

Cơng thức tìm giao điểm nhanh (adsbygoogle = window.adsbygoogle || []).push({});

Nếu gọi xk, xk+1 lần lượt là các hồ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 hồ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 cĩ thể dễ dàng xác định hồnh độ giao điểm ứng với dịng quét kế tiếp một cách đơn giản theo cơng thức trên. Điều này rút gọn đáng kể thao tác tìm giao điểm của cạnh ứng với dịng quét. Chính vì vậy mà trong thơng tin của một cạnh chúng ta cĩ hai biến DxPerScan và xIntersect.

Hình 2.23

Giải quyết trường hợp dịng quét đi ngang qua đỉnh

Người ta đưa ra quy tắc sau để tính số giao điểm khi dịng quét đi ngang qua đỉnh :

+ Tính một giao điểm nếu chiều của hai cạnh kề của đỉnh đĩ cĩ xu hướng tăng hay giảm.

+ Tính hai giao điểm nếu chiều của hai cạnh kề của đỉnh đĩ cĩ xu hướng thay đổi, nghĩa là tăng-giảm hay giảm-tăng.

Khi cài đặt để khỏi phải xét điều kiện này cho phức tạp, khi xây dựng dữ liệu cho mỗi cạnh trước khi đưa vào ET, người ta sẽ xử lí các cạnh cĩ đỉnh tính hai giao điểm bằng cách loại đi một pixel trên cùng của một trong hai cạnh như hình dưới

Hình 2.25: Cạnh Pi-1Pi được lưu trong ET chỉ là Pi-1Pi*

Cài đặt minh họa sau sử dụng chung một danh sách EDGELIST cho cả ET và AET. AET được quản lí nhờ vào hai con trỏ FirstId và LastId.

Cài đặt minh họa thuật tốn tơ màu scan-line

#include <stdio.h> #include <conio.h> #include <stdlib.h> #include <graphics.h> #include <dos.h> #define MAXVERTEX 20 #define MAXEDGE 20 #define TRUE 1 #define FALSE 0 typedef struct { int x; int y; }POINT; typedef struct{ int NumVertex;

POINT aVertex[MAXVERTEX]; }POLYGON;

typedef struct { int NumPt;

float xPt[MAXEDGE]; }XINTERSECT;

typedef struct {

int yMin; // Gia tri y nho nhat cua 2 dinh

Một phần của tài liệu Giao trinh đồ họa máy tính 2012 (Trang 42)