【OpenGL C++】画一个空心汉字和一个圆,并填充汉字(中点画线法,中点画圆法,种子填充法)

内容:画一个空心汉字和一个圆

设计一个画任意直线和圆的算法,可选所学的任一图形扫描转换算法(中点或bresenham算法),不能使用任何画线/画圆的API;
使用画线算法实现空心汉字的绘制,汉字必须为4划以上;
使用你设计的画圆算法绘制这个空心字的外接圆;
设计一种填充算法实现汉字的填充;

1.中点画圆法

生成八分之一圆,其他部分可以通过一系列的简单反射变换得到。
(1)已知圆心在原点的圆上的一点的(x,y),函数circlePlotPoint()
根据对称性得到8个对称点,分别为(y,x),(y,-x),(x,-y),(-x,-y),(-y,-x),(-y,x),(-x,y);
(2)函数circleMidpoint()
如果此时点的位置为(X1,Y1),那么下一个点位置只可能是(X1+1,Y1)或者(X1+1,Y1-1),根据判别式d:
d<0,应取(X1+1,Y1)为下一个点,d=d+2*x+3;
d>=0应取(X1+1,Y1-1)为下一个点,d=d+(x-y)+5;

2.中点画线法

(1)强制起点在终点左侧,如果不是的话,则交换两点;
(2)函数MidPoint()
分为四种情况,斜率0=<k<=1、斜率1<k、斜率-1 =<k<0和斜率k<-1时,根据每种情况下的判别式d,判断下一个点的位置;
(3) 函数setPoint()
每画一个点,就将其对应的flag置为1,说明此点已填充,则边界上所有的点的flag都已经置为1,为填充时判断边界做了准备。

3.种子填充法

函数Flood()
(1)先将种子像素压入栈;
(2)如果栈不为空,栈顶像素出栈;
(3)按左上右下的顺序搜索与出栈像素相邻的4个像素,若像素的flag值是1,说明该像素已填充,结束本次循环;若像素的flag值是0,说明该像素未填充,将该像素入栈。

#include <gl/glut.h>
#include <math.h>
#include <windows.h>
#include <iostream>
#include <vector>
#include <stack>
#include <stdlib.h>

using namespace std;
int xc, yc, r;
int flag[2000][2000] = { 0 };
int winwidth = 500, winheight = 500;//窗口长宽

//声明一个类
class screenPt
{
public:
	
	screenPt()
	{
		x = y = 0;
	}

	void setCoords(GLint xCoordValue, GLint yCoordValue) {
		x = xCoordValue;
		y = yCoordValue;
	}
	GLint x, y;
};

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

//画点
void setPixel(GLint xCoord, GLint yCoord) {
	glBegin(GL_POINTS);
	glVertex2i(xCoord, yCoord);
	glEnd();
}

//八个对称点
void circlePlotPoints(GLint xc, GLint yc, screenPt circpt) {
	setPixel(xc + circpt.x, yc + circpt.y);
	setPixel(xc - circpt.x, yc + circpt.y);
	setPixel(xc + circpt.x, yc - circpt.y);
	setPixel(xc - circpt.x, yc - circpt.y);
	setPixel(xc + circpt.y, yc + circpt.x);
	setPixel(xc - circpt.y, yc + circpt.x);
	setPixel(xc + circpt.y, yc - circpt.x);
	setPixel(xc - circpt.y, yc - circpt.x);
}

/*中心画圆法*/
void circleMidpoint(GLint xc, GLint yc, GLint radius) {
	
	glClear(GL_COLOR_BUFFER_BIT);//清除窗口显示内容

	screenPt circpt;//创建一个对象
	GLint p = 1 - radius;
	circpt.setCoords(0, radius);

	//显示圆弧上的八个点
	circlePlotPoints(xc, yc, circpt);

	while (circpt.x < circpt.y) {
		circpt.x++;
		if (p < 0) {
			p += 2 * circpt.x + 3;
		}
		else {
			circpt.y--;
			p += 2 * (circpt.x - circpt.y) + 5;
		}
		//显示圆弧上的八个点
		circlePlotPoints(xc, yc, circpt);
	}

}


class Point {
public:
	Point();
	Point(GLint  _x, GLint _y) {
		x = _x;
		y = _y;
	}
	GLint x, y;
};

// 种子填充
void Flood(int a, int b)   {

	
	//      (x - 1, y);  //left
	//		(x, y - 1);  //up
	//		(x + 1, y);  //right
		//		(x, y + 1);  //down
    int dx[4] = { -1, 0, 1,0 };
	int dy[4] = { 0, -1, 0,1 };

	stack<Point> q;
	q.push(Point(a, b));

	while (q.size()) {
		auto t = q.top();
		q.pop();

		for (int i = 0; i < 4; i++) {

			int n = t.x + dx[i];
			int m = t.y + dy[i];
			//cout << m << "  " << n << endl;

			if (flag[n][m])
				continue;
			flag[n][m] = 1;

			glBegin(GL_POINTS);
			glColor3f(255, 255, 0);
			glVertex2f(n ,m );
			glEnd();

			q.push(Point(n, m));
			glFlush();
		}
	}
}

//画线之间的点    
void setPoint(GLint x,GLint y) {
	glBegin(GL_POINTS);
	glColor3f(249, 216, 118);//
	glVertex2f(x, y);//指定顶点的值
	flag[(int)(x )][(int)(y )] = 1;
	glEnd();
}


void MidPoint() {

	//将点的信息放到line中保存
	vector<Point> line;

	//第一部分连接点 4

	line.push_back(Point(240, 150));
	line.push_back(Point(255, 150));

	line.push_back(Point(255, 150));
	line.push_back(Point(265, 165));

	line.push_back(Point(250, 165));
	line.push_back(Point(265, 165));

	line.push_back(Point(240, 150));
	line.push_back(Point(250, 165));

	第2部分连接点 22

	line.push_back(Point(200, 185));
	line.push_back(Point(215, 185));

	line.push_back(Point(200, 185));
	line.push_back(Point(200, 220));

	line.push_back(Point(200, 220));
	line.push_back(Point(215, 220));

	line.push_back(Point(215, 210));
	line.push_back(Point(215, 220));
	
	line.push_back(Point(215, 185));
	line.push_back(Point(215, 190));

	line.push_back(Point(215, 190));
	line.push_back(Point(305, 190));

	line.push_back(Point(305, 185));
	line.push_back(Point(305, 190));
	
	line.push_back(Point(305, 185));
	line.push_back(Point(325, 185));

	line.push_back(Point(325, 185));
	line.push_back(Point(325, 220));

	line.push_back(Point(310, 220));
	line.push_back(Point(325, 220));

	line.push_back(Point(310, 210));
	line.push_back(Point(310, 220));

	line.push_back(Point(215, 210));
	line.push_back(Point(310, 210));

	第3部分连接点  36
	line.push_back(Point(180,240));
	line.push_back(Point(240, 240));

	line.push_back(Point(180, 240));
	line.push_back(Point(180, 250));

	line.push_back(Point(240, 240));
	line.push_back(Point(250, 225));

	line.push_back(Point(250, 225));
	line.push_back(Point(270, 225));

	line.push_back(Point(260, 240));
	line.push_back(Point(270, 225));

	line.push_back(Point(260, 240));
	line.push_back(Point(345, 240));

	line.push_back(Point(180, 250));
	line.push_back(Point(235, 250));

	line.push_back(Point(250, 250));
	line.push_back(Point(290, 250));

	line.push_back(Point(210, 290));
	line.push_back(Point(235,250));

	line.push_back(Point(210, 290));
	line.push_back(Point(230, 300));

	line.push_back(Point(190, 340));
	line.push_back(Point(230, 300));

	line.push_back(Point(190, 340));
	line.push_back(Point(195, 350));

	line.push_back(Point(195, 350));
	line.push_back(Point(245, 310));

	line.push_back(Point(245, 310));
	line.push_back(Point(320, 340));

	line.push_back(Point(320, 340));
	line.push_back(Point(325, 330));

	line.push_back(Point(265, 300));
	line.push_back(Point(325, 330));

	line.push_back(Point(265, 300));
	line.push_back(Point(310, 250));

	line.push_back(Point(310, 250));
	line.push_back(Point(345, 250));

	line.push_back(Point(345, 240));
	line.push_back(Point(345, 250));

	第四部分连接点 4
	line.push_back(Point(235, 285));
	line.push_back(Point(250, 250));
	
	line.push_back(Point(235, 285));
	line.push_back(Point(250, 290));

	line.push_back(Point(250, 290));
	line.push_back(Point(290, 250));

	
	//中点画线法
	for (int i = 0; i < line.size() - 1; i += 2) {

		double x0, y0, x1, y1;
		x0 = line[i].x;
		y0 = line[i].y;
		x1 = line[i + 1].x;
		y1 = line[i + 1].y;

		double A = y0 - y1;
		double B = x1 - x0;
		double k = -1 * (A / B);

		double t;
		double d;
		//强制起点在终点左侧,如果不是的话,则交换两点;
		if (x1 < x0) {

			t = x1;
			x1 = x0;
			x0 = t;

			t = y1;
			y1 = y0;
			y0 = t;
		}

		//斜率0=<k<=1
		if (k >= 0 && k <= 1) {
			d = (2 * A + B);
		
			while (x0 != x1) {
	
				setPoint(x0, y0);
				if (d <= 0) {
					x0 += 1;
					y0 += 1;
					d += (2 * (A + B));
				}
				else {
					x0++;
					d += (2 * A);
				}
				//glFlush();
			}
		}
		//斜率大于1
		if (k > 1) {
			d = (A + 2 * B);
		
			while (y0 != y1) {
				
				setPoint(x0, y0);
				if (d < 0) {
					y0 += 1;
					d += (2 * B);
				}
				else {
					
					y0 += 1;
					x0 += 1;
					d += (2 * (A + B));
				}
				//glFlush();
			}

		}
		//斜率大于等于-1 小于0时
		if (k >= -1 && k < 0) {
			d = (2 * A - B);
		
			while (x0 != x1) {
				
				setPoint(x0, y0);
				if (d < 0) {
					x0 += 1;
					d += (2 * A);
				}
				else {
					x0 += 1;
					y0 -= 1;
					d += (2 * (A - B));
				}
				//glFlush();
			}

		}

		//斜率小于-1时
		if (k < -1) {
			d = (int)(A - 2 * B);
			
			while (y0 != y1) {
				
				setPoint(x0, y0);
				if (d < 0) {
					y0 -= 1;
					x0 += 1;
					d += (2 * (A - B));
				}
				else {
					y0 -= 1;
					d -= (2 * B);
				}
				//glFlush();
			}
		}
	}

	//调用种子填充
	setPixel(210, 200);
	Flood(210,200);
	setPixel(245, 155);
	Flood(245, 155);
	setPixel(181, 241);
	Flood(181, 241);
}


void display() {

	circleMidpoint(250, 250, 120);
	MidPoint();
	//glFlush();
}


int main(int argc, char** argv) {

	glutInit(&argc, argv);//初始化

	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);//设置绘制模式

	glutInitWindowPosition(400, 150); //设置窗口的位置

	glutInitWindowSize(winwidth, winheight);

	glutCreateWindow("绘制并填充”安“"); //创建窗口并赋予title

	init();

	glutDisplayFunc(display);

	glutMainLoop();

}

结果:
在这里插入图片描述

  • 6
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值