C语言——中点画圆算法和Bresenham画圆算法(easyx图形库)

一、中点画圆法

首先是中点画圆法,考虑圆心在原点,半径为R的圆在第一象限内的八分之一圆弧,从点(0, R)到点(R/ , R/ )顺时针方向确定这段圆弧。假定某点Pi(xi, yi)已经是该圆弧上最接近实际圆弧的点,那么Pi的下一个点只可能是正右方的P1或右下方的P2两者之一,如图所示:

构造判别函数:F(x, y)= x2 + y2 – R2

当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’ = F(xi + 2, yi – 1.5)= (xi + 2)2 + (yi – 1.5)2 – R2

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

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

特别的,在第一个象限的第一个点(0, R)时,可以推倒出判别式d的初始值d0:

d0 = F(1, R – 0.5) = 1 – (R – 0.5)2 – R2 = 1.25 - R

根据上面的分析,可以写出中点画圆法的算法。考虑到圆心不在原点的情况,需要对计算出来的坐标进行了平移,下面就是通用的中点画圆法的源代码:

#include<stdio.h>
#include<graphics.h>
#include<conio.h>
#define x0 400
#define y0 300                    //定义全局变量x0,y0:坐标轴中心(x0,y0)
void Middle_point_draw_circle(int x1, int y1, int r) 
{
	int d0, x = 0, y = r;//d0是判别式的值
	d0 = 1.25 - r;   //判别式的初始值,1.25可以改为1
	while (x < y) 
	{
		if (d0 >= 0) 
		{
			d0 = d0 + 2 * (x - y) + 5;            //d0一定要先比x,y更新
			x += 1;                //因为d0表达式中的x,y是上一个点
			y -= 1;
			putpixel(((x + x1) + x0), (y0 - (y + y1)), RED);         //(x,y)
			putpixel(((-x + x1) + x0), (y0 - (y + y1)), RED);        //(-x,y)
			putpixel(((y + x1) + x0), (y0 - (x + y1)), RED);         //(y,x)
			putpixel(((-y + x1) + x0), (y0 - (x + y1)), RED);        //(-y,x)
			putpixel(((x + x1) + x0), (y0 - (-y + y1)), RED);        //(x,-y)
			putpixel(((-x + x1) + x0), (y0 - (-y + y1)), RED);       //(-x,-y)
			putpixel(((y + x1) + x0), (y0 - (-x + y1)), RED);        //(y,-y)
			putpixel(((-y + x1) + x0), (y0 - (-x + y1)), RED);       //(-y,-x)
			Sleep(50);
		}
		else 
		{
			d0 = d0 + 2 * x + 3;
			x += 1;
			y = y;
			putpixel(((x + x1) + x0), (y0 - (y + y1)), RED);         //(x,y)
			putpixel(((-x + x1) + x0), (y0 - (y + y1)), RED);        //(-x,y)
			putpixel(((y + x1) + x0), (y0 - (x + y1)), RED);         //(y,x)
			putpixel(((-y + x1) + x0), (y0 - (x + y1)), RED);        //(-y,x)
			putpixel(((x + x1) + x0), (y0 - (-y + y1)), RED);        //(x,-y)
			putpixel(((-x + x1) + x0), (y0 - (-y + y1)), RED);       //(-x,-y)
			putpixel(((y + x1) + x0), (y0 - (-x + y1)), RED);        //(y,-y)
			putpixel(((-y + x1) + x0), (y0 - (-x + y1)), RED);       //(-y,-x)
			Sleep(50);
		}
	}
}
void main() 
{
	int x1, y1, r;
	printf("请输入中点画圆算法圆心坐标(x1,y1)和圆的半径r:\n");
	scanf("%d %d %d", &x1, &y1, &r);
	initgraph(x0 * 2, y0 * 2);		    //初始化图形窗口大小
	setbkcolor(WHITE);
	cleardevice();
	setcolor(BLACK);
	line(x0, 0, x0, y0 * 2);			//坐标轴X
	line(0, y0, x0 * 2, y0);			 //坐标轴Y
	Middle_point_draw_circle(x1, y1, r);             //中点画圆算法
	_getch();                                        //等待一个任意输入结束
	closegraph();                                    //关闭图形窗口
}


运行结果:

 二、Bresenham算法

 中点画圆法中,计算判别式d使用了浮点运算,影响了圆的生成效率。如果能将判别式规约到整数运算,则可以简化计算,提高效率。于是人们针对中点画圆法进行了多种改进,其中一种方式是将d的初始值由1.25 – R改成1 – R,考虑到圆的半径R总是大于2,因此这个修改不会响d的初始值的符号,同时可以避免浮点运算。还有一种方法是将d的计算放大两倍,同时将初始值改成3 – 2R,这样避免了浮点运算,乘二运算也可以用移位快速代替,采用3 – 2R为初始值的改进算法,称为Bresenham算法。

源代码展示:

#include<stdio.h>
#include<graphics.h>
#include<conio.h>
#define x0 400
#define y0 300                    //定义全局变量x0,y0:坐标轴中心(x0,y0)
void Middle_point_draw_circle(int x1, int y1, int r) 
{
	int d0, x = 0, y = r;//d0是判别式的值
	d0 = 3 - 2*r;   //判别式的初始值
	while (x < y) 
	{
		if (d0 >= 0) 
		{
			d0 = d0 + 4 * (x - y) + 10;            //d0一定要先比x,y更新
			x += 1;                //因为d0表达式中的x,y是上一个点
			y -= 1;
			putpixel(((x + x1) + x0), (y0 - (y + y1)), RED);         //(x,y)
			putpixel(((-x + x1) + x0), (y0 - (y + y1)), RED);        //(-x,y)
			putpixel(((y + x1) + x0), (y0 - (x + y1)), RED);         //(y,x)
			putpixel(((-y + x1) + x0), (y0 - (x + y1)), RED);        //(-y,x)
			putpixel(((x + x1) + x0), (y0 - (-y + y1)), RED);        //(x,-y)
			putpixel(((-x + x1) + x0), (y0 - (-y + y1)), RED);       //(-x,-y)
			putpixel(((y + x1) + x0), (y0 - (-x + y1)), RED);        //(y,-y)
			putpixel(((-y + x1) + x0), (y0 - (-x + y1)), RED);       //(-y,-x)
			Sleep(50);
		}
		else 
		{
			d0 = d0 + 4 * x + 6;
			x += 1;
			y = y;
			putpixel(((x + x1) + x0), (y0 - (y + y1)), RED);         //(x,y)
			putpixel(((-x + x1) + x0), (y0 - (y + y1)), RED);        //(-x,y)
			putpixel(((y + x1) + x0), (y0 - (x + y1)), RED);         //(y,x)
			putpixel(((-y + x1) + x0), (y0 - (x + y1)), RED);        //(-y,x)
			putpixel(((x + x1) + x0), (y0 - (-y + y1)), RED);        //(x,-y)
			putpixel(((-x + x1) + x0), (y0 - (-y + y1)), RED);       //(-x,-y)
			putpixel(((y + x1) + x0), (y0 - (-x + y1)), RED);        //(y,-y)
			putpixel(((-y + x1) + x0), (y0 - (-x + y1)), RED);       //(-y,-x)
			Sleep(50);
		}
	}
}
void main() 
{
	int x1, y1, r;
	printf("请输入中点画圆算法圆心坐标(x1,y1)和圆的半径r:\n");
	scanf("%d %d %d", &x1, &y1, &r);
	initgraph(x0 * 2, y0 * 2);		    //初始化图形窗口大小
	setbkcolor(WHITE);
	cleardevice();
	setcolor(BLACK);
	line(x0, 0, x0, y0 * 2);			//坐标轴X
	line(0, y0, x0 * 2, y0);			 //坐标轴Y
	Middle_point_draw_circle(x1, y1, r);             //中点画圆算法
	_getch();                                        //等待一个任意输入结束
	closegraph();                                    //关闭图形窗口
}


运行结果:

发布了29 篇原创文章 · 获赞 83 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/l59565455/article/details/87473897