光栅图形学(二)——圆弧的扫描转换算法

版权声明:欢迎转载和交流。 https://blog.csdn.net/Hachi_Lin/article/details/88309871

1、圆弧的特征

  圆被定义为到给定中心位置 ( x 0 , y 0 ) (x_0,y_0) 的距离为 r r 的点集。圆心为 ( x 0 , y 0 ) (x_0,y_0) 的圆有4条对称轴 x = x 0 , y = y 0 , y = x + y 0 x 0 , y = x + x 0 + y 0 x = x_0,y = y_0,y = x + y_0 - x_0,y = -x +x_0 + y_0 。若已知圆弧上一点 ( x , y ) (x,y) ,可以得到其关于4条对称轴的其它7个点,这种性质称为八对称性。因此,只要扫描1/8圆弧,就可以用八对称性求出整个圆弧的像素集。
  显示圆弧上8个对称点的算法如下:

void CirclePoints(int x,int y,int color)
{
	drawpixel(x, y,int color); drawpixel(y - (y0 - x0), x + (y0 - x0),int color);
	drawpixel(y - (y0 - x0), x0 + y0 - x,int color); drawpixel(x, 2 * y0 - y,int color);
	drawpixel(2 * x0 - x, 2 * y0 - y,int color); drawpixel(x0 + y0 - y, x0 + y0 - x,int color);
	drawpixel(x0 + y0 - y, x + (y0 - x0),int color); drawpixel(2 * x0 - x, y,int color);
}

2、中点画圆法

  构造函数 F ( x , y ) = ( x x 0 ) 2 + ( y y 0 ) 2 R 2 F(x,y) = (x-x_0)^2 + (y-y_0)^2-R^2 ,对于圆上的点, F ( x , y ) = 0 F(x,y)=0 ;对于圆外的点, F ( x , y ) > 0 F(x,y)>0 ;对于圆内的点, F ( x , y ) < 0 F(x,y)<0 。与中点画线法一样,构造判别式:
d = F ( M ) = F ( x p + 1 , y p 0.5 ) = ( x p + 1 x 0 ) 2 + ( y p 0.5 y 0 ) 2 R 2 d = F(M)=F(x_p+1,y_p-0.5)=(x_p+1-x_0)^2+(y_p - 0.5-y_0)^2-R^2
  (1)若 d < 0 d<0 ,则应取 P 1 P_1 为下一像素,而且下一像素的判别式为 d 1 = F ( x p + 2 , y p 0.5 ) = ( x p + 2 x 0 ) 2 + ( y p 0.5 y 0 ) 2 R 2 = d + 2 ( x p x 0 ) + 3 d_1 = F(x_p+2,y_p - 0.5) = (x_p+2-x_0)^2+(y_p - 0.5-y_0)^2-R^2 = d + 2 * (x_p - x_0) + 3
  (2)若 d 0 d\ge 0 ,则应取 P 2 P_2 为下一像素,而且下一像素的判别式为 d 2 = F ( x p + 2 , y p 0.5 ) = ( x p + 2 x 0 ) 2 + ( y p 1.5 y 0 ) 2 R 2 = d + 2 ( x p x 0 ) 2 ( y y 0 ) + 4 d_2 = F(x_p+2,y_p - 0.5) = (x_p+2-x_0)^2+(y_p - 1.5-y_0)^2-R^2 = d + 2 * (x_p - x_0) - 2 * (y - y0) + 4
  这里讨论的是按顺时针方向生成第二个八分圆(如图),则第一个像素是 ( 0 , R ) (0,R) ,判别式 d d 的初始值为 d 0 = ( x 0 + 1 , y 0 + R 0.5 ) = 1.25 R d_0=(x_0+1,y_0 +R - 0.5)=1.25-R
在这里插入图片描述
为了摆脱浮点运算,使用 4 d 4d 代替 d d

  • 中点画圆算法程序
MidPointCircle(int x0, int y0, int color)
{
	drawpixel(x0, y0, color);        //画圆心
	int x, y;
	int d, b;
	x = x0; y = r + y0; d = 5 - 4*r; b = y0 - x0;
	Circlepoints(x, y, color);        
	while (x + (y0 - x0) <= y)
	{
		if (d < 0)
			d += 8*(x - x0) + 12;
		else {
			d += 8*x - 8*y + 8*b + 16;
			y--;
		}
		x++;
		Circlepoints(x,y,color);
	}
}

3、极坐标画圆法

给定圆心 ( x 0 , y 0 ) (x_0,y_0) ,可通过下列方程组表示圆
{ x = x 0 + r cos θ y = y 0 + r sin θ \begin{cases} x = x_0 + r \cos \theta \\ y = y_0 + r \sin \theta \end{cases}
使用上述方法以单位角度为步长,可以在圆周上以等距的点来绘制圆,其中 θ 0 = 90 \theta_0 = 90

  • 极坐标画圆算法程序
PolarCircle(int x0, int y0, int color)
{
	drawpixel(x0, y0, color);        //画圆心
	int angle = 90;
	int x, y, change;    
	while (angle >= 45)
	{
		//角度转弧度
		change = angle*pi/180;
		x = int(0.5 + x0+r*cos(change));
		y = int(0.5 + y0+r*sin(change));
		Circlepoints(x , y, color);
		angle--;
	}
}

4、代码实现(VS2017 + OpenGL)

// Circle_Algorithm.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include "pch.h"
#include "pch.h"
#include <iostream>
#include <math.h>
#include <gl\glut.h>
#include <gl\GL.h>
#include <gl\GLU.h>
using namespace std;
#define pi 3.1415926

void init(void)
{
	glClearColor(1.0, 1.0, 1.0, 0.0);  // Set display-window color to white.
	glMatrixMode(GL_PROJECTION);       // Set projection parameters.
	gluOrtho2D(0.0, 200.0, 0.0, 150.0);
}


//窗口大小改变时调用的登记函数
void ChangeSize(GLsizei w, GLsizei h) {
	if (h == 0)
		h = 1;
	glViewport(0, 0, w, h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	if (w <= h)
		glOrtho(0.0f, 250.0f, 0.0f, 250.0f*h / w, 1.0, -1.0);
	else
		glOrtho(0.0f, 250.0f*w / h, 0.0f, 250.0f, 1.0, -1.0);
}

void CirclePoint(int x0, int y0, int x, int y) {
	glColor3f(0.0, 0.0, 1.0);  //设置像素点颜色为蓝色
	//按顺时针画圆
	glVertex2f(x, y); glVertex2f(y - (y0 - x0), x + (y0 - x0));
	glVertex2f(y - (y0 - x0), x0 + y0 - x); glVertex2f(x, 2 * y0 - y);
	glVertex2f(2 * x0 - x, 2 * y0 - y); glVertex2f(x0 + y0 - y, x0 + y0 - x);
	glVertex2f(x0 + y0 - y, x + (y0 - x0)); glVertex2f(2 * x0 - x, y);
}

//中点画圆算法
void MidPointCircle(int x0, int y0, int r)
{
	glColor3f(0.0, 0.0, 1.0);  //设置像素点颜色为蓝色
	glPointSize(2.0f);         //设置像素点大小
	glVertex2f(x0, y0);        //画圆心
	int x, y;
	int d,b;
	x = x0; y = r + y0; d = 5 - 4 * r; b = y0 - x0;
	CirclePoint(x0, y0, x, y);
	while (x + b <= y)
	{
		if (d < 0)
			d += 8*(x - x0) + 12;
		else {
			d += 8*x - 8*y + 8*b + 16;
			y--;
		}
		x++;
		CirclePoint(x0, y0, x, y);
	}

}

//极坐标画圆算法
void PolarCircle(int x0, int y0, int r)
{
	glColor3f(0.0, 0.0, 1.0);  //设置像素点颜色为蓝色
	glPointSize(2.0f);         //设置像素点大小
	glVertex2f(x0, y0);        //画圆心
	int angle = 90;
	int x, y, change;
	while (angle >= 45)
	{
		//角度转弧度
		change = angle * pi / 180;
		x = int(0.5 + x0 + r * cos(change));
		y = int(0.5 + y0 + r * sin(change));
		CirclePoint(x0, y0, x, y);
		angle--;
	}
}

void display()
{
	int x1_1 = 20, y1_1 = 20, x2_1 = 160, y2_1 = 80;
	int x1_2 = 20, y1_2 = 40, x2_2 = 160, y2_2 = 100;
	int x1_3 = 20, y1_3 = 60, x2_3 = 160, y2_3 = 120;
	glClear(GL_COLOR_BUFFER_BIT);
	glBegin(GL_POINTS);
	MidPointCircle(80, 60, 60);
	glEnd();
	glBegin(GL_POINTS);
	MidPointCircle(80, 80, 60);
	glEnd();
	glFlush();
}


int main(int argc, char **argv)
{
	glutInit(&argc, argv); //GLUT初始化
	glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); //指出显示窗口使用单个缓存且使用由红绿蓝三种颜色模型
	glutInitWindowPosition(500, 500);            //设置显示窗口位置
	glutInitWindowSize(400, 400);                //设置显示窗口大小
	glutCreateWindow("Line Algorithm");           //设置显示窗口的标题
	glutDisplayFunc(display);                    //将图赋值给显示窗口
	glutReshapeFunc(ChangeSize);
	init();
	glutMainLoop();              //必须是程序的最后一个
	return 0;
}
  • 运行结果
    在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Hachi_Lin/article/details/88309871
今日推荐