Please wait...

Top Bar -->

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

date_range 2017-03-11

Bài viết này, chúng ta tiếp tục vận dụng linh hoạt ý tưởng của thuật toán Bresenham để đi nghiên cứu cách vẽ đường elip trong đồ họa máy tính .

1.Đặt vấn đề:

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

2.Giải thuật:

*Ý tưởng:

  • Tính khoảng cách từ điểm thực đến 2 điểm vẽ được, xem khoảng cách nào ngắn hơn.
  • Vẽ 1 nửa elip, sau đó lấy đối xứng qua các đường phân giác.

*Phân tích:

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

Theo kiến thức toán học, phương trình Elip có dạng:

hay

Trong đó: a là độ dài trục chính , b là độ dài trục phụ

Phương trình tiếp tuyến Elip tại điểm (x0, y0) :

và hệ số góc của tiếp tuyến tại điểm đó :

Đầu tiên, theo ý tưởng bài toán, chúng ta sẽ đi vẽ từng nửa elip. Ở mỗi nửa elip, chúng ta lại phải vẽ theo hai nhánh khác nhau. Đó là một nhánh từ trên xuống, và một nhánh từ dưới lên. Hai nhánh này cắt nhau tại giao điểm mà ở đó hệ số góc của tiếp tuyến với Elip bằng -1 (như hình sau) .

 

*Q: Wait ! Trước khi đi vào phân tích để tìm công thức tổng quát , liệu các bạn có thắc mắc “Tại sao lại phải vẽ elip theo 2 nhánh không? Tại sao không vẽ liền một mạch luôn? “.

=> A: Trước khi lý giải cái tại sao đó. Chúng ta hãy xem hình sau:

Thực chất của việc chia hai nhánh vẽ elip là chúng ta đi tìm các điểm kế tiếp theo hướng tính y theo x (hay tính x theo y) cho trước. Nhìn vào hình trên, với giao điểm màu đỏ làm ranh giới, chúng ta dễ dàng thấy được  nhánh vẽ từ trên xuống : khi x tăng lên 1 đơn vị thì y chỉ tăng lên rất ít ; và ngược lại với nhánh vẽ từ dưới lên: khi y tăng lên 1 đơn vị thì x chỉ tăng lên rất ít. Nếu như chúng ta chọn cách vẽ liền một mạch thì việc tăng lên không đồng đều của tọa độ x và y sẽ khiến đường elip không min, đứt gãy, rất xấu. Do đó, muốn vẽ được đường elip mịn nét, chúng ta sẽ phải chia elip thành 2 nhánh để vẽ.

*Xét nhánh 1 , vẽ từ trên xuống:

*Xét nhánh 2 , vẽ từ dưới lên : (làm tương tự nhánh 1)

3.Code minh họa:

#include<iostream>
#include<winbgim.h>
#include<math.h>
#include<conio.h>
using namespace std;
int color=15;
void Ve4diem(int xc,int yc,int x, int y,int color)//ve 4 diem doi xung
{
	putpixel(xc+x,yc+y,color);
	putpixel(xc-x,yc+y,color);
	putpixel(xc-x,yc-y,color);
	putpixel(xc+x,yc-y,color);
	delay(50);
}
void Elipse(int x_center,int y_center,int a,int b,int color)// ve elipse
{
	float p,a2,b2;
	int x,y;
	a2=pow(a,2);
	b2=pow(b,2);
	x=0;
	y=b;
	
	p=2*((float)b2/a2)-(2*b)+1;
	
	//ve nhanh thu 1(tu tren xuong )
	while(((float)b2/a2)*x<=y)
	{
		Ve4diem(y_center,y_center,x,y,color);
		if(p<0)
		{
			p=p+2*((float)b2/a2)*(2*x+3);
		}
		else{
			p= p- 4*y + 2*((float)b2/a2)*(2*x+3);
			y--;
		}
		x++;
	}
	//ve nhanh thu 2(tu duoi len )
	y=0;
	x=a;
	p=2*((float)a2/b2)-2*a+1;
	while(((float)a2/b2)*y<=x)
	{
		Ve4diem(y_center,y_center,x,y,color);
		if(p<0)
		{
			p=p	+2*((float)a2/b2)*(2*y+3);
		}
		else
		{
			p=p- 4*x + 2*((float)a2/b2)*(2*y+3);
			x=x-1;
		}
		y=y+1;
	}
}
int main()
{
	int x,y;
	cout<<"\nNhap toa do tam Elip \nx: "; cin>>x;
	cout<<"\ny: "; cin>>y;
	initwindow(640,480);
	Elipse(x,y,300,150,color);
	getch();
	return 0;
}

4.Hình ả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 !