橡皮筋与多边形填充

参考文献:

https://blog.csdn.net/lhs322/article/details/79729356
https://blog.csdn.net/u013044116/article/details/49737585/
https://blog.csdn.net/zjccoder/article/details/41146259

主要功能
要OpenGL 实现
通过橡皮筋交互输入不同颜色、大小的多边形
清屏重置多边形,撤销多边形,对多个多边形进行填充,改变多边形线条的粗细,颜色
实现了存储多边形,以及显示存储的多边形

实现代码如下

#include<stdio.h>
#include<gl/glut.h>
#include"datastruct.h"

static const  int screenwidth = 1000;  //自定义窗口宽度
static const int screenheight = 1000; //自定义窗口高度
vector<point> p; //多边形点集向量
vector<polygon> s; //多边形类向量,用来保存已经画完的多边形
int move_x,move_y; //鼠标当前坐标值,在鼠标移动动态画线时使用
bool select = false, exam=true,functiondemo=false; //多边形封闭状态判断变量,当为true时即按下鼠标右键,将多边形封闭
float red=1.0,green=0.0,blue=0.0;  //用此来改变线段的颜色
float lineWidth;
int MaxY=0,MinY=1000;
int POINTNUM;
int colorNum=0;


/**
使用说明:
 按上键表示增加线条的宽度,下键减小线条的宽度
 F2: 对多边形填充颜色
 F1: 清屏
 F3: 撤销刚画的一条边
 F4: 撤销刚画的一个三角形
 CTRL+a  :改变多边形填充的颜色  红色
 CTRL+z  : 改变多边形填充的颜色  蓝色
 CTRL+x  : 改变多边形填充的颜色  绿色
**/

void init()
{
	glClearColor(1.0,1.0,1.0,0.0);
	glMatrixMode(GL_PROJECTION);             //表示给物体加物理贴图,或透视效果
	gluOrtho2D(0.0,screenwidth,0.0,screenheight);
}

void fillKColor(int mn){
	int i;
	for(int k=0;k<mn;k++){       //k表示多变行的个数
		POINTNUM = s[k].p.size();

		for( i = 0;i < POINTNUM; i++ )
		{
			if( s[k].p[i].y > MaxY )
			{
				MaxY = s[k].p[i].y;
			}

			if( s[k].p[i].y < MinY )
			{
				MinY = s[k].p[i].y;
			}
		}
		/*******初始化AET表,即初始化活跃边表***********************************************************/
		AET *pAET = new AET;
		pAET->next = NULL;
		/******初始化NET表,即初始化边表************************************************************/
		NET *pNET[1024];
		for( i = MinY;i <= MaxY; i++ )
		{
			pNET[i] = new NET;
			pNET[i]->next = NULL;
		}

		//glClear(GL_COLOR_BUFFER_BIT);        //赋值的窗口显示.
		//glColor3f(0.0,0.0,0.0);             //设置直线的颜色红色
		glBegin(GL_POINTS);
		/******扫描并建立NET表,即建立边表*********************************************************/
		for( i = MinY; i <= MaxY; i++ )
		{
			for( int j = 0;j < POINTNUM; j++ )
			{
				if( s[k].p[j].y == i)
				{                    
					if( s[k].p[ (j-1+POINTNUM) % POINTNUM ].y > s[k].p[j].y )
					{
						NET *p=new NET;
						p->x = s[k].p[j].x;
						p->ymax = s[k].p[ (j-1+POINTNUM) % POINTNUM ].y;   //下面表示的是斜率需要用浮点型来计算float()
						p->dx = ( float(s[k].p[ (j-1+POINTNUM)%POINTNUM ].x-s[k].p[j].x )) /float( ( s[k].p[ (j-1+POINTNUM) % POINTNUM ].y - s[k].p[j].y ));
						p->next = pNET[i]->next;
						pNET[i]->next = p;
					}

					if( s[k].p[ (j+1+POINTNUM ) % POINTNUM].y > s[k].p[j].y )
					{
						NET *p = new NET;                        
						p->x = s[k].p[j].x;
						p->ymax = s[k].p[ (j+1+POINTNUM) % POINTNUM ].y;
						p->dx = ( float(s[k].p[(j+1+POINTNUM) % POINTNUM ].x-s[k].p[j].x )) / float( s[k].p[ (j+1+POINTNUM) % POINTNUM ].y- s[k].p[j].y );
						p->next = pNET[i]->next;
						pNET[i]->next = p;
					}
				}
			}
		}
		/******建立并更新活性边表AET*****************************************************/
		for( i = MinY; i <= MaxY; i++ ) // for循环中按下面的流程而不是《计算机图形学》徐长青第二版P38中Polygonfill算法中的while循环中的流程,						
		{					            // 这样可以处理书中的边界问题,无需开始时进行边缩短										
			//计算新的交点x,更新AET********************************************************/
			NET *p = pAET->next;
			while( p != NULL )
			{
				p->x = p->x + p->dx;
				p = p->next;
			}

			//更新后新AET先排序*************************************************************/
			//断表排序,不再开辟空间
			AET *tq = pAET;
			p = pAET->next;
			tq->next = NULL;

			while( p != NULL )
			{
				while( tq->next != NULL && p->x >= tq->next->x )
				{
					tq = tq->next;
				}

				NET *s = p->next;
				p->next = tq->next;
				tq->next = p;
				p = s;
				tq = pAET;
			}

			//(改进算法)先从AET表中删除ymax==i的结点****************************************/
			AET *q = pAET;
			p = q->next;
			while( p != NULL )
			{
				if( p->ymax == i)
				{
					q->next = p->next;
					delete p;
					p = q->next;
				}
				else
				{
					q = q->next;
					p = q->next;
				}
			}
			//将NET中的新点加入AET,并用插入法按X值递增排序**********************************/
			p = pNET[i]->next;
			q = pAET;
			while( p != NULL )
			{
				while( q->next != NULL && p->x >= q->next->x)
				{
					q = q->next;
				}

				NET *s = p->next;
				p->next = q->next;
				q->next = p;
				p = s;
				q = pAET;
			}

			/******配对填充颜色***************************************************************/
			p = pAET->next;
			while( p != NULL && p->next != NULL )
			{
				for(float j = p->x;j <= p->next->x; j++)
				{
					//glVertex2i(j,i);
					glVertex2i(static_cast<int>(j),i);
					//pDC.SetPixel( static_cast<int>(j), i, RGB(255,0,0) );
				}  // pDC.MoveTo( static_cast<int>(p->x), i ); 用画直线来替换上面的设置像素点颜色,速度更快
				//  pDC.LineTo( static_cast<int>(p->next->x), i );
				p = p->next->next;//考虑端点情况
			}    
		}

		glEnd();
		exam = false;
		NET *phead = NULL;
		NET *pnext = NULL;
		//释放边表
		//释放活跃边表
		phead = pAET;
		while( phead != NULL )
		{
			pnext = phead->next;
			delete phead;
			phead = pnext;
		}
	}
    glFlush();
}

void lineSegment()
{
	glClear(GL_COLOR_BUFFER_BIT);
	glColor3f(red,green,blue);   //设定颜色,既是线段颜色也是填充色
	int i, j;                 //两个循环控制变量,在下面的向量循环和数组循环中将被多次调用。

	//if(exam){
		if(!s.empty())            //看多边形类向量是否为空,即判断除了当前正在画的多边形是否还有曾经已经画好的多边形
		{
			for( i = 0; i < s.size(); i++)   //对多边形类向量循环,该向量中的每个元素代表一个多边形
			{
				int k = s[i].p.size();  //将一个多边形的点的个数,后面划线会用到
				//			s[i].line(); //生成多边形的边
				for(j = 0; j < s[i].p.size(); j++) //画多边形
				{
					glBegin(GL_LINES); //将当前的点与后一个点连线
					glVertex2i(s[i].p[j].x, s[i].p[j].y);
					glVertex2i(s[i].p[(j+1)%k].x, s[i].p[(j+1)%k].y);//,通过取模操作来避免越界问题,该思路来源于循环队列.
					glEnd();
				}
				//			paint(s[i].edge);  //为当前的多边形填充颜色
				//			s[i].edge.clear(); //清空当前多边形的边向量
			}
		}
		i = 0; 
		j = p.size() - 1;
		while(i < j)           //循环画图,将当前正在画的多边形
		{
			glBegin(GL_LINES);   //将已经确定的点连接起来
			glVertex2i(p[i].x, p[i].y);
			glVertex2i(p[i+1].x, p[i+1].y);
			glEnd();
			i++;
		}
		if(!p.empty()) 
		{
			//	int i = p.size() - 1; //将确定的最后一个点与当前鼠标所在位置连线,即动态画线
			glBegin(GL_LINES);
			glVertex2i(p[j].x, p[j].y);
			glVertex2i(move_x, move_y);
			glEnd();		 
		}else{                       //按下F1以后将线进行重新绘制,便展现了清屏的效果
			glBegin(GL_LINES);
			glVertex2i(0, 0);
			glVertex2i(0, 0);
			glEnd();

		}
	//}
	if(colorNum>0)
		fillKColor(colorNum);
	if(select) //判断右键是否被点下
	{
		select = false; //将状态值置为假
		if(!p.empty())
		{
			glBegin(GL_LINES); //将多边形封闭
			glVertex2i(p[j].x, p[j].y);
			glVertex2i(p[0].x, p[0].y);
			glEnd();
			polygon sq;
			//将封闭了的多边形保存到多边形类中
			for(i = 0; i < p.size(); i++)
				sq.p.push_back(p[i]);
			s.push_back(sq); //将绘成的多边形存入多边形类向量中
			//			paint(sq.edge); //给当前画完的多边形填色
		}
		p.clear();
	}
	glFlush();
}

void myMouse(int button, int state ,int x, int y) //鼠标点击事件响应函数
{
	if(state == GLUT_DOWN && button == GLUT_LEFT_BUTTON)//当鼠标左键被点击
	{
		point v;  //申请一个点类变量,点类为自定义类,在zl.h中定义
		v.x = x; //将点击处的点坐标,即x和y的值存入v中
		v.y = screenheight - y;
		p.push_back(v); //将点信息存入多边形点集向量p中
		exam = true;
		glutPostRedisplay(); //重绘窗口
	}

	if(state == GLUT_DOWN && button == GLUT_RIGHT_BUTTON) //当鼠标右键被点击
	{
		select = true; 
		glutPostRedisplay();
	}
}

void myPassiveMotion(int x, int y) //鼠标移动事件响应函数
{
	move_x = x; //保存当前鼠标所在的坐标的值
	move_y = screenheight - y;
	glutPostRedisplay();
}

void processNormalKey(unsigned char key, int x, int y)   //使用组合键改变线段的颜色
{
	int mod = glutGetModifiers();
	if(mod ==GLUT_ACTIVE_CTRL)
	{
		if(key == 1)       //对应CTRL+a
		{
			red = 1.0;
			green = 0.0;
			blue = 0.0;
		}
		if(key == 26)    //对应CTRL+z
		{
			red = 0.0;
			green = 1.0;
			blue = 0.0;
		}
		else if(key == 24)   //对应CTRL+x
		{
			red = 0.0;
			green = 0.0;
			blue = 1.0;
		}
		else
		{
			red = 1.0;
		}
	}
}

void processSpqcialKeys(int key, int x, int y){       //按下按键改变线条的颜色

	if(key == 27){
		exit(0);
	}
	else if(key == GLUT_KEY_UP)
	{
		lineWidth = lineWidth+2;
		glLineWidth(lineWidth);
	}
	else if(key == GLUT_KEY_DOWN)
	{
		lineWidth = lineWidth-2;
		glLineWidth(lineWidth);
	}
	else if(key == GLUT_KEY_F2){  //按下F2键将多边形填充
		if(!s.empty()){
			//PolyScan();
			//fillKColor();
		
			if(s.size()>colorNum)
				colorNum = s.size();
		}
	}
	else if(key == GLUT_KEY_F1)  //按下F1键清除屏幕
	{
		printf("%d  ",s.size());  //将的多边形全部删除
		while(!s.empty()){
			s.pop_back();
		}
		printf("%d",p.size());
		while(!p.empty()){ //将最后一个多变形删除
			p.pop_back();
		}
		exam = true;
		colorNum =0;
	}else if(key == GLUT_KEY_F3){   //按下F3键撤销一个刚画的边
		p.pop_back();                         
	}else if(key == GLUT_KEY_F4){   //直接撤销一个三角形
		s.pop_back();
	}
	glutPostRedisplay();
}

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

	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
	glutInitWindowPosition(50,100);
	glutInitWindowSize(screenwidth,screenheight);
	glutCreateWindow("扫描线填充算法");
	init();
	glutMouseFunc(myMouse); //鼠标点击消息监控,即监控鼠标是否被点击,若被点击就调用myMouse函数
	glutDisplayFunc(lineSegment);
	glutPassiveMotionFunc(myPassiveMotion); //鼠标移动消息监控,即监控鼠标是否移动,若移动就调用myPassiveMotion函数
	glutKeyboardFunc(processNormalKey); //通过按键改变线段的颜色
	glutSpecialFunc(processSpqcialKeys); //通过按特殊按键改变多边形线条的大小
	glutMainLoop();
	return 0;
}

头文件 datastruct.h

#ifndef DATA_H_
#define DATA_H_
#include<vector>
using namespace std;
class point //点类,存储了一个点的两坐标值
{
public:
	int x;
	int y;
};
class polygon //多边形类,存了一个多边形
{
public:
	vector<point> p; //多边形的顶点
};
#endif
typedef struct XET
{
	float x;
	float dx,ymax;
	struct XET* next;
}AET,NET;

实现效果在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
#include "stdafx.h" #include <GL/glut.h> #include <stdlib.h> #include <stdio.h> #define stripeImageWidth 32 GLubyte stripeImage[4 * stripeImageWidth]; #ifdef GL_VERSION_1_1 static GLuint texName; #endif void makeStripeImage(void) { int j; for (j = 0; j < stripeImageWidth; j++) { stripeImage[4 * j] = (GLubyte)((j <= 4) ? 255 : 0); stripeImage[4 * j + 1] = (GLubyte)((j>4) ? 255 : 0); stripeImage[4 * j + 2] = (GLubyte)0; stripeImage[4 * j + 3] = (GLubyte)255; } } /* planes for texture coordinate generation */ static GLfloat xequalzero[] = { 1.0, 0.0, 0.0, 0.0 }; static GLfloat slanted[] = { 1.0, 1.0, 1.0, 0.0 }; static GLfloat *currentCoeff; static GLenum currentPlane; static GLint currentGenMode; static float roangles; static float roangles1; float roangles2 = -2; float roangles3 = -3; void SpecialKeys(int key, int x, int y) { if (key == GLUT_KEY_F1) roangles += 2.0f; roangles2 += 0.05; roangles3 += 1; if (key == GLUT_KEY_F2) roangles1 += 2.0f; if (roangles2 >= 3) roangles2 = -3; // 使用新的坐标重新绘制场景 glutPostRedisplay(); } void init(void) { glClearColor(1.0, 1.0, 1.0, 0.0); glEnable(GL_DEPTH_TEST); glShadeModel(GL_SMOOTH); makeStripeImage(); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); #ifdef GL_VERSION_1_1 glGenTextures(1, &texName;); glBindTexture(GL_TEXTURE_1D, texName); #endif glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); #ifdef GL_VERSION_1_1 glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, stripeImageWidth, 0, GL_RGBA, GL_UNSIGNED_BYTE, stripeImage); #else glTexImage1D(GL_TEXTURE_1D, 0, 4, stripeImageWidth, 0, GL_RGBA, GL_UNSIGNED_BYTE, stripeImage); #endif glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); currentCoeff = xequalzero; currentGenMode = GL_OBJECT_LINEAR; currentPlane = GL_OBJECT_PLANE; glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, currentGenMode); glTexGenfv(GL_S, currentPlane, currentCoeff); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_1D); //glEnable(GL_CULL_FACE); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_AUTO_NORMAL); glEnable(GL_NORMALIZE); glFrontFace(GL_CW); //glCullFace(GL_BACK); glMaterialf(GL_FRONT, GL_SHININESS, 64.0); roangles = 45.0f; roangles1 = 362.0f; } void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); glBegin(GL_QUADS); glColor3f(1, 0, 1); glVertex3f(-1, -1, 0); glColor3f(1, 0, 1); glVertex3f(-3, -1, 0); glColor3f(1, 0, 1); glVertex3f(1, -1, 0); glColor3f(1, 0, 1); glVertex3f(-1, -2, 0); glEnd(); glPopMatrix(); glPushMatrix(); glTranslated(roangles2, 2, -3); glRotatef(roangles, 0.0, 1.0, 0.0); #ifdef GL_VERSION_1_1 glBindTexture(GL_TEXTURE_1D, texName); #endif //glutSolidTeapot(2.0); glutSolidSphere(0.8, 32, 32); glPopMatrix(); glFlush(); glPushMatrix(); glTranslated(1, 2, -3); glRotatef(roangles1, 1.0, 0.0, 0.0); glRotatef(roangles3, 0.0, 1.0, 0.0); #ifdef GL_VERSION_1_1 glBindTexture(GL_TEXTURE_1D, texName); #endif //glutSolidTeapot(2.0); glTranslated(-1, -3, -0); glRotatef(90, 1.0f, 0.0f, 0.0f); glRotatef(180, 0.0f, 1.0f, 0.0f); glRotatef(-30, 0.0f, 0.0f, 1.0f); glutSolidCone(1, 2, 32, 32); glPopMatrix(); glFlush(); } void reshape(int w, int h) { glViewport(0, 0, (GLsizei)w, (GLsizei)h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) glOrtho(-3.5, 3.5, -3.5*(GLfloat)h / (GLfloat)w, 3.5*(GLfloat)h / (GLfloat)w, -3.5, 3.5); else glOrtho(-3.5*(GLfloat)w / (GLfloat)h, 3.5*(GLfloat)w / (GLfloat)h, -3.5, 3.5, -3.5, 3.5); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void idle() { roangles += 0.1f; glutPostRedisplay(); } int main(int argc, char** argv) { glutInit(&argc;, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(600, 600); glutInitWindowPosition(100, 100); glutCreateWindow(argv[0]); //glutIdleFunc(idle); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutSpecialFunc(SpecialKeys); glutMainLoop(); return 0; }

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值