基于Opengl的画圆—中心画圆算法

画圆之前,首先需要了解如下:

 


当F(x, y)= 0,表示点在圆上,当F(x, y)> 0,表示点在圆外,当F(x, y)< 0,表示点在圆内。如果M是P1和P2的中点,则M的坐标是(xi + 1, yi – 0.5),当F(xi +1, yi – 0.5)< 0时,M点在圆内,说明P1点离实际圆弧更近,应该取P1作为圆的下一个点。同理分析,当F(xi + 1, yi – 0.5)> 0时,P2离实际圆弧更近,应取P2作为下一个点。当F(xi +1, yi – 0.5)= 0时,P1和P2都可以作为圆的下一个点,算法约定取P2作为下一个点。

现在将M点坐标(xi + 1, yi – 0.5)带入判别函数F(x, y),得到判别式d:

d = F(xi + 1, yi –0.5)= (xi + 1)2 +(yi – 0.5)2 – R2

若d < 0,则取P1为下一个点,此时P1的下一个点的判别式为

d’ = F(xi + 2, yi –0.5)= (xi + 2)2 +(yi – 0.5)2 – R2

展开后将d带入可得到判别式的递推关系

d’ = d + 2xi + 3

若d > 0,则取P2为下一个点,此时P2的下一个点的判别式为

d’ = d + 2(xi -yi) + 5

 

 

代码如下:

#include<gl/glut.h>
#include<iostream>
#include<cmath>
int xc,yc,r;
int winwidth=800,winheight=640;//窗口长宽
//声明一个类
class screenPt
{
public:
	void setCoords(GLint xCoordValue,GLint yCoordValue){
		x=xCoordValue;
		y=yCoordValue;
	}
	screenPt();
	GLint getx() const{
		return x;
	}
	GLint gety() const{
		return y;
	}
	void incrementx(){
		x++;
	}
	void decrementy(){
		y--;
	}

private:
	GLint x,y;
};

void circlePlotPoints(GLint,GLint,screenPt);
screenPt::screenPt()
{
	x=y=0;
}
//画点
void setPixel(GLint xCoord,GLint yCoord){
	glBegin(GL_POINTS);
	glVertex2i(xCoord,yCoord);
	glEnd();	
}
/*中心画圆法*/
void circleMidpoint(GLint xc,GLint yc,GLint radius){
	glClear(GL_COLOR_BUFFER_BIT);//清除窗口显示内容

	setPixel(xc,yc);//画圆心
	screenPt circpt;//创建一个对象
	GLint p=1-radius;//
	circpt.setCoords(0,radius);
	
	circlePlotPoints(xc,yc,circpt);

	while(circpt.getx()<circpt.gety()){
		circpt.incrementx();
		if(p<0){
			p+=2*circpt.getx()+1;
		}else{
			circpt.decrementy();
			p+=2*(circpt.getx()-circpt.gety())+1;
		}
		circlePlotPoints(xc,yc,circpt);
	}

}

void circlePlotPoints(GLint xc,GLint yc,screenPt circpt){
	setPixel(xc+circpt.getx(),yc+circpt.gety());
	setPixel(xc-circpt.getx(),yc+circpt.gety());
	setPixel(xc+circpt.getx(),yc-circpt.gety());
	setPixel(xc-circpt.getx(),yc-circpt.gety());
	setPixel(xc+circpt.gety(),yc+circpt.getx());
	setPixel(xc-circpt.gety(),yc+circpt.getx());
	setPixel(xc+circpt.gety(),yc-circpt.getx());
	setPixel(xc-circpt.gety(),yc-circpt.getx());
}

void init(){
	glClearColor(1.0,1.0,1.0,1.0);//设置绘制窗口颜色为白色
	glClear(GL_COLOR_BUFFER_BIT);//清除窗口显示内容
	/*设置为投影类型模式和其他观察参数*/
	glPointSize(3.0f);
	glColor3f(1.0,0.0,0.0);//设置颜色为红
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluOrtho2D(0,winwidth,winheight,0);
}

void DrawCircle(){
	circleMidpoint(xc,yc,r);
	glFlush();
}

//鼠标拖动
void dragmouse(int x,int y){
		r=sqrt((y-yc)*(y-yc)+(x-xc)*(x-xc));
		printf("%d %d %d\n",xc,yc,r);
		DrawCircle();
		glFlush();
}

//鼠标监听,画点
void mymouse(int button,int state,int x,int y){
	if(button==GLUT_LEFT_BUTTON && state==GLUT_UP){
		r=sqrt((y-yc)*(y-yc)+(x-xc)*(x-xc));
		printf("%d %d %d\n",xc,yc,r);
		DrawCircle();
		glFlush();

	}
	if(button==GLUT_LEFT_BUTTON && state==GLUT_DOWN){
		xc=x;
		yc=y;
		
		
	}

}

int main(int argc,char** argv){
	glutInit(&argc,argv);//初始化
//	scanf("%d%d%d",&xc,&yc,&r);
	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);//设置绘制模式
	glutInitWindowPosition(500,300);
	glutInitWindowSize(winwidth,winheight);
	glutCreateWindow("画圆");//创建窗口
	init();

	glutDisplayFunc(DrawCircle);
	glutMouseFunc(mymouse);//鼠标监听回调函数
	glutMotionFunc(dragmouse);//鼠标拖动
	glutMainLoop();

}

运行结果:


第一个、二个为圆心坐标,第三个参数为半径。

为了清除的展示圆心位置,我在圆心处还多画了一个点。

上述的画圆心法也是使用OpenGL的鼠标事件监听来实现,非常简单而且方便地实现了画板又一个功能。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值