Please wait...

Top Bar -->

Bài 7: Thuật toán vẽ đường Ellipse Midpoint

date_range 2017-03-12

Trong đồ họa máy tính, khi muốn vẽ đường Elip , ngoài việc áp dụng thuật toán Bresenham (như bài 6), chúng ta còn có thể áp dụng một thuật toán nữa – đó chính là thuật toán Midpoint. Và thuật toán Midpoint , chúng ta cũng đã tìm hiểu khi dùng để vẽ đường thẳng ( tại bài 5) . Nếu bạn nào chưa  đọc thì hãy vào xem phần này nha !

Đặt vấn đề

Vẽ elip bằng thuật toán Midpoint.

Giải thuật

Để đơn giản, chúng ta sẽ chọn vẽ hình Elip có tâm ở gốc tọa độ.

Phương trình của đường Elip:

f(x,y) = b2x2 + a2y2  – a2b2    

  • < 0 nếu (x,y) nằm bên trong elip.
  • = 0 nếu (x,y) nằm trên elip.
  • > 0 nếu (x,y) nằm bên ngoài elip.

*Ý tưởng và phân tích giải thuật:

  • Chia Elip làm 2 phần tại điểm Q nơi có hệ số góc của tiếp tuyến với Elip bằng -1 (véc tơ gradient bằng 1) ( lý do tại sao lại phải chia làm 2 phần thì bài 6 mình đã giải thích rồi nhé). Tại vùng thứ nhất, x biến thiên nhanh hơn y và tại vùng thứ hai , y biến thiên nhanh hơn x. Nhớ lại công thức hệ số góc của đường cong :

dx/dy = fx/fy = (2b2x) /( 2a2y)

trong đó: fx và fy là đạo hàm riêng phần của f(x,y) theo x, theo y.

  • Trong phần thứ nhất:

Giả sử đã vẽ được điểm (xi,yi) , điểm tiếp theo trên elip được chọn trong bước nhảy i+1 là T hoặc S.  Trung điểm I của TS sẽ quyết định điểm nào được chọn. Giá trị của f(x,y) tại điểm I:

di = f(xi + 1, yi – ½) = b2(xi + 1)2 + a2(yi – ½)2 – a2b2

+Nếu di ≥ 0 thì trung điểm I nằm ngoài đường elip  => điểm được chọn là S.

+Nếu di < 0 thì trung điểm I nằm trong đường elip =>  điểm được chọn là T.

Ta lại có:

di+1 = f(xi+1 + 1, yi+1 – ½) = b2(xi+1 +1)2 + a2(yi+1 – ½)2 – a2b2

Suy ra:

di+1 – di = b2[(xi+1 +1)2 – (xi +1)2] +a2[(yi+1 – ½)2 – (yi – ½)2]

Vì xi+1 = xi+1 nên

di+1 – di = 2b2xi+1 + b2 + a2[(yi+1 – ½)2 – (yi – ½)2]

+ Nếu điểm được chọn là T (di < 0) thì yi+1 = yi . 

Ta có :

di+1 = di + 2b2xi+1 + b2 (= di + fx + b2)

= di + 2b2 (xi + 1) + b2

= di + b2 (2xi + 3)

+ Nếu điểm được chọn là S (di ≥ 0) thì yi+1 = yi – 1

Ta có:

di+1 = di + 2b2xi+1 + b2 – 2a2yi+1 (= di + fx + b2 – fy)

       = di + 2b2 (xi + 1) + b2 – 2a2 (yi – 1)

= di + b2 (2xi + 3) + a2 (-2yi + 2)

Với điểm đầu tiên (0,b) ta có:

d1 = f(0,b) = b2 + a2(b – ½)2 – a2b2 = b2 ─ a2b + a2/4

  • Trong phần thứ hai:

Chúng ta tính toán như phần 1. Giả sử ta phải xác định điểm  (xj+1,yj+1) tiếp theo trên elip  trong bước j+1. Điểm được chọn là U hoặc V. Trung điểm K của UV sẽ quyết định việc chọn điểm U hay điểm V. Giá trị của f(x,y) tại điểm K:

ej = f(xj + ½, yj – 1) = b2(xj + ½)2 + a2(yj – 1)2 – a2b2

+ Nếu ej ≥ 0 điểm được chọn là U.

+ Nếu ej < 0 điểm được chọn là V.

Ta lại có:

ej+1 = f(xj+1 + ½, yj+1 – 1) = b2(xj+1 + ½)2 + a2(yj+1 – 1)2 – a2b2

Suy ra:

ej+1 – ej = b2[(xj+1 + ½)2 – (xj + ½)2] + a2[(yj+1 – 1)2 – (yj – 1)2]

= b2[(xj+1 + ½)2 – (xj + ½)2] – 2a2yj+1 + a2  

(Chú ý : yj+1 = yi – 1)

+ Nếu điểm được chọn là U (tức ej ≥ 0) thì xj+1 = xj

Ta có:

ej+1 = ej – 2a2yj+1 + a2 (= ej – fy + a2)

= ej – 2a2(yj -1) + a2

= ej – a2(3 – 2yj)

+ Nếu điểm được chọn là V (tức ej < 0 )thì xj+1 = xj+1

Ta có:

ej+1 = ej + 2b2xj+1 – 2a2yj+1 + a2 (= ej + fx – fy + a2)

= ej + 2b2(xj + 1)– 2a2(yj -1) + a2

= ej + b2(2xj + 2)+ a2(3 -2yj )

Giá trị khởi tạo ban đầu trong phần 2 phụ thuộc vào vị trí cuối cùng của phần 1 , giả sử là (xk,yk). Khi đó:

e1 = f(xk + ½, yk – 1) = b2(xk + ½) + a2(yk – 1)2 – a2b2

Lưu đồ thuật toán

*Q: Tại sao lại so sánh  2A2y < 0 ???

=> A:  Do ở phần ý tưởng thuật toán, chúng ta chia elip làm 2 phần để vẽ và lấy điểm Q có hệ số góc của tiếp tuyến với elip bằng -1 làm giao điểm. Theo công thức hệ số đã nêu ở trên:  dx/dy = fx/fy = (2b2x) /( 2a2y). Tại điểm đầu tiên có tọa độ  (0,b), chúng ta thay x=0 và y=b vào công thức trên được hệ số góc= 0/( 2a2b) lớn hơn -1 . Nên ta chọn vẽ theo nhánh 1 . Như vậy, việc so sánh  2A2y < 0 là để chọn nhánh vẽ elip thôi.

Code minh họa

#include<graphics.h>
#include<conio.h>//de dung man hinh dô hoa
#include<iostream>
#define ROUND(a) (int)(a+0.5)
using namespace std;

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);
}
void elipMidpoint(int xc,int yc, int a, int b, int color)
{
	int x, y, fx, fy, a2, b2, p;
	x = 0;
	y = b;
	a2 = a*a;
	b2 = b*b;
	fx = 0;
	fy = 2 * a2 * y;
	plot(xc, yc, x, y, color);
	p = ROUND(b2 -(a2*b) + (0.25*a2));//p=b2 - a2*b +a2/4
	while(fx<fy)
	{
		x++;
		fx += 2*b2;
		delay(50);
		if(p<0)
		{
			p += b2*(2*x + 3);//p=p + b2*(2x +3)
		}
		else
		{
			y--;
			p += b2*(2*x +3) + a2*(2- 2*y);//p=p +b2(2x +3) +a2(2-2y)
			fy -= 2*a2;
		}
		plot(xc, yc, x, y, color);
	}
	p = ROUND(b2*(x +0.5)*(x +0.5) + a2*(y-1)*(y-1) - a2*b2);
	//
	while(y>0)
	{
		y--;
		fy -= 2*a2;
		delay(50);
		if(p >=0)
		{
			p += a2*(3-2*y); //p=p +a2(3-2y)
		}
		else
		{
			x++;
			fx += 2*b2;
			p += b2*(2*x +2) +a2*(3- 2*y);//p=p+ b2(2x +2) + a2(3-2y)
		}
		plot(xc, yc, x, y, color);
	}
}
int main()
{
	int gd=DETECT, gm;
	initgraph(&gd,&gm,"");
	elipMidpoint(getmaxx()/2, getmaxy()/2,150,80,15);
	getch();
	closegraph();
	return 0;
}
	

Hình minh họa

Cảm ơn các bạn đã đọc bài viết . Mong bài viết giúp ích cho việc học tập của các bạn !