计算机图形学E5——OpenGL 扫描线填充

其他计算机图形学实验见 链接

#include<iostream>
#include<gl/glut.h>
#include<algorithm>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
const int window_width = 800, window_height = 500;
const int maxn = 99999;

struct point
{
	float x, y;
	point()
	{}
	point(int xx, int yy)
		:x(xx), y(yy) {}
};
vector<point> vertice;
typedef struct XET
{
	float x;
	float dx;
	float ymax;//float
	XET* next;
}AET, NET;//AET 活性边表; NET新边表

void draw_a_point(int x, int y);
void PolyScan();
void mymouse(int button, int state, int x, int y);
void display();


int main(int argc, char* argv[])
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
	glutInitWindowPosition(100, 50);
	glutInitWindowSize(window_width, window_height);
	glutCreateWindow("扫描线填充");

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluOrtho2D(0, window_width,  0, window_height);

	glClearColor(1, 1, 1, 1);
	glClear(GL_COLOR_BUFFER_BIT);

	glutMouseFunc(&mymouse);
	//glutDisplayFunc(&display);

	glutMainLoop();
	return 0;
}

void draw_a_point(int x, int y)
{
	glBegin(GL_POINTS);
	glColor3f(1, 0, 0);
	glVertex2f(x, y);
	glEnd();
	glFlush();
}
void PolyScan()
{
	//得到最高点的y坐标
	int Max_Y = 0;
	for (int i = 0; i < vertice.size(); i++)
		/*Max_Y = max(Max_Y, vertice[i].y);*/
		if (vertice[i].y > Max_Y)
			Max_Y = vertice[i].y;
	//cout << "MAX_Y=" << Max_Y << endl;


	//初始化AET表
	AET* pAET = new AET;
	pAET->next = NULL;
	//初始化NET表
	NET* pNET[800];
	for (int i = 0; i <= Max_Y; i++)
	{
		pNET[i] = new NET;
		//pNET[i]->x = NULL;//写的时候我是脑子瓦特了嘛,辣鸡bug,毁我青春!!
		pNET[i]->next = NULL;;
	}

	//扫描并且建立NET表
	int len = vertice.size();
	for (int i = 0; i <= Max_Y; i++)
	{
		//cout << "i=" << i << " ";
		for (int j = 0; j < len; j++)
		{
			//cout << "j=" << j << endl;
			if (i == vertice[j].y)
			{
				//cout <<"y="<< i << endl;
				//如果一个点和前一个点有一条边相连,则该点和后面一个点也相连
				if (vertice[(j - 1 + len) % len].y > vertice[j].y)
				{
					NET* p = new NET;
					p->x = vertice[j].x;
					p->ymax = vertice[(j - 1 + len) % len].y;//与当前扫描线相交的活性边 的 最高点即为相邻顶点的y
					float DX = vertice[(j - 1 + len) % len].x - vertice[j].x;
					float DY = vertice[(j - 1 + len) % len].y - vertice[j].y;
					p->dx = DX / DY;//dx为直线斜率的倒数
					p->next = pNET[i]->next;
					pNET[i]->next = p;
				}
				if (vertice[(j + 1) % len].y > vertice[j].y)
				{
					NET* p = new NET;
					p->x = vertice[j].x;
					p->ymax = vertice[(j + 1) % len].y;
					float DX = vertice[(j + 1) % len].x - vertice[j].x;
					float DY = vertice[(j + 1) % len].y - vertice[j].y;
					p->dx = DX / DY;//dx为直线斜率的倒数
					p->next = pNET[i]->next;
					pNET[i]->next = p;
				}
			}
		}
	}

	//建立并且更新活性边表AET
	for (int i = 0; i <= Max_Y; i++)
	{
		//计算新的交点 更新AET
		NET* p = pAET->next;
		while (p)
		{
			p->x = p->x + p->dx;
			p = p->next;
		}

		//排序
		AET* tq = pAET;
		p = pAET->next;
		tq->next = NULL;

		while (p != NULL)//顺着链表往下走
		{
			//找到第一个比它大的数字tq->next->x,则从p->next到tq->next都是比p->x小的
			while (tq->next != NULL && tq->next->x <= p->x)
				tq = tq->next;
			//把这一段小的整体向前移动
			NET* t = p->next;
			p->next = tq->next;
			tq->next = p;
			p = t;

			tq = pAET;//回到头
		}

		//(改进算法)先从AET表中删除ymax==i的结点****************************************/
		AET* q = pAET;
		p = q->next;
		while (p)
		{
			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)
		{
			while (q->next != NULL && p->x >= q->next->x)
				q = q->next;

			NET* t = p->next;
			p->next = q->next;
			q->next = p;
			p = t;

			q = pAET;
		}

		//配对后填充颜色
		p = pAET->next;
		while (p != NULL && p->next != NULL)
		{
			for (float j = p->x; j <= p->next->x; j++)
			{
				draw_a_point(j, i);
				//cout << "(" << j << ", " << i << ")" << endl;
			}
			p = p->next->next;//考虑端点情况
		}
	}
	glFlush();
}
void mymouse(int button, int state, int x, int y)
{
	if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
	{
		draw_a_point(x, window_height - y);

		point p(x, window_height - y);
		vertice.push_back(p);
		cout << "顶点" << vertice.size() << ": (" << x << ", " << window_height - y << ")" << endl;
	}

	if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
	{
		glClearColor(1, 1, 1, 1);//设置绘制窗口颜色为白色
		glColor3f(1, 0, 0);

		glBegin(GL_LINES);
		for (int i = 0; i < vertice.size(); i++)
		{
			if (i == vertice.size() - 1)//画完最后一个点,使其闭合
			{
				glVertex2f(vertice[0].x, vertice[0].y);
				glVertex2f(vertice[i].x, vertice[i].y);
			}
			else
			{
				glVertex2f(vertice[i].x, vertice[i].y);
				glVertex2f(vertice[i + 1].x, vertice[i + 1].y);
			}
		}
		glEnd();
		glFlush();
	}

	if (button == GLUT_MIDDLE_BUTTON && state == GLUT_DOWN)
	{
		//cout << "center: (" << x << ", " << y << ")" << endl;
		//BoundaryFill4(x, window_height - y);
		//BoundaryFill4_Stack(x, window_height - y);

		cout << "多边形顶点个数为" << vertice.size() << "。 " << "开始扫描线填充。" << endl;
		PolyScan();
	}
}
void display()
{
	glClear(GL_COLOR_BUFFER_BIT);
	glColor3f(0.0, 0.4, 0.2);
	glPointSize(1);
	glBegin(GL_POINTS);
	PolyScan();
	glEnd();
	glFlush();
}
  • 9
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
用VC++6.0实现的扫描线填充,裁剪算及画线方 CPen pen(PS_SOLID,1,fillcolor); //设置扫描线所用笔的属性 CPen *old=pDC->SelectObject(&pen); int j,k,s=0; int p[9]; //每根扫描线交点 int pmin=1000; int pmax=0; for(int i=0;i<inLength;i++)//建立边表 { edge[i].dx=(float)(inVertexArray[i+1].x-inVertexArray[i].x)/(inVertexArray[i+1].y-inVertexArray[i].y); edge[i].num=i; if(inVertexArray[i].y<=inVertexArray[i+1].y) { edge[i].ymin=inVertexArray[i].y; edge[i].ymax=inVertexArray[i+1].y; edge[i].xmin=(float)inVertexArray[i].x; edge[i].xmax=(float)inVertexArray[i+1].x; } else{ edge[i].ymin=inVertexArray[i+1].y; edge[i].ymax=inVertexArray[i].y; edge[i].xmax=(float)inVertexArray[i].x; edge[i].xmin=(float)inVertexArray[i+1].x; } } //求多边形的最大最小值 for(int m=1;m<inLength;m++) { for(int n=0;n<inLength-m;n++) { if (pmax<inVertexArray[n].y) pmax = inVertexArray[n].y; if (pmin>inVertexArray[n].y) pmin=inVertexArray[n].y; } } for(int r=1;r<inLength;r++) //边表edge排序 { for(int q=0;q<inLength-r;q++) { if(edge[q].ymin<edge[q+1].ymin) { newedge[0]=edge[q]; edge[q]=edge[q+1]; edge[q+1]=newedge[0]; } } } for(int scan=pmax;scan>pmin;scan--) //扫描线遵守'“上开下闭”的原则 { int b=0; k=s; for(j=k;j<inLength;j++) { if((scan>=edge[j].ymin)&&(scan<=edge[j].ymax))//判断扫描线与线段是否相交于顶点 { int preNum = edge[j].num; int nextNum = edge[j].num+1; if (preNum==0) preNum = inLength - 1; else preNum = preNum -1; if (nextNum == inLength) nextNum = 0; if(scan==edge[j].ymax) //位于下顶点时,根据相临点的位置决定取几个点 { if(inVertexArray[nextNum].y<edge[j].ymax) { b++; p[b]=(int)edge[j].xmax; } if(inVertexArray[preNum].y<edge[j].ymax) { b++; p[b]=(int)edge[j].xmax; } } if(scan==edge[j].ymin) //位于上顶点时,取两个点 { b++; p[b]=(int)edge[j].xmin; b++; p[b]=(int)edge[j].xmin; } if((scan>edge[j].ymin)&&(scan<edge[j].ymax)) { b++; p[b]=(int)(edge[j].xmax+edge[j].dx*(scan-edge[j].ymax)); } } if(scan<edge[j].ymin) //建立新的活性边表 s=j; } if(b>1) { int tmpp = p[1]; for (int u = 1;u<=b;u++) //对交点排序 { for (int m = 1;m<=b-u;m++) { if (p[m]<p[m+1]) { tmpp = p[m]; p[m] = p[m+1]; p[m+1] = tmpp; } } } for(int n=1;n<b;n=n+2) { pDC->MoveTo(p[n],scan); pDC->LineTo(p[n+1],scan); } } }
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值