• 边标志法填充多边形


    这里不仔细讲原理,只是把我写的算法发出来,跟大家分享下,如果有错误的话,还请大家告诉我,如果写的不好,也请指出来,一起讨论进步。

    基本思想: 先用一种特殊的颜色在帧缓冲器中将多边形的边界(水平边界除外)勾画出来,然后将着色的像素点依x坐标递增的顺序两两配对,再将每一对像素所构成的扫描线区间内的所有像素置为填充色。具体分为两个步骤;

    (1) 打标记。对多边形的每条边进行直线扫描转换。

    (2) 填充。 对每条与多边形相交的扫描线,依从左到右顺序,按“左闭右开”的原则对扫描线上的像素点进行填充。使用一个布尔量inside来指示当前点的状态,若点在多边形内,则inside为真,否则为假。inside初值为假,第当当前访问像素为被打上标记的点时就把inside取反。对未打标记的像素,inside不变。若访问当前像素时,对inside作必要操作后,inside为真,由把该像素置为填充色。

    下面是程序:

    /*
    *	Date: 11/23/2010
    */
    #include <GL/glew.h>
    #include <GL/freeglut.h>
    #include <vector>
    #include <iostream>
    #include <fstream>
    using std::ofstream;
    using std::ifstream;
    using std::cout;
    using std::endl;
    ifstream cin ("polypoints.txt");
    typedef struct _Point
    {
    	int x;
    	int y;
    }Point;
    
    
    
    typedef struct _PolyPoints
    {
    	Point * pPoint;						// Pointer to points
    	int		n;							// Number of points
    	int		yMax;						// Max y of all points
    	int		yMin;						// Min y of all points
    	int		xMax;						// Max x of all points
    	int		xMin;						// Min x of all points
    }PolyPoints;
    
    
    PolyPoints g_polyPoints;				// Storage for points of polygons
    bool **	g_pbEdgeFlag;					// Edge flag
    void inputPoints (void)
    {
    	int n;
    	cin>>n;
    	if (n < 3)
    	{
    		cout<<"number of points can not be less than 3"<<endl;
    		exit (0);
    	}
    	g_polyPoints.n = n;
    	g_polyPoints.pPoint = new Point[n];
    	g_polyPoints.yMax = INT_MIN;
    	g_polyPoints.yMin = INT_MAX;
    	g_polyPoints.xMax = INT_MIN;
    	g_polyPoints.xMin = INT_MAX;
    	int x, y;
    	for (int i = 0; i < n; ++i)
    	{
    		cin>>x>>y;
    		g_polyPoints.pPoint[i].x = x;
    		g_polyPoints.pPoint[i].y = y;
    		if (g_polyPoints.yMax < y)
    		{
    			g_polyPoints.yMax = y;
    		}
    		if (g_polyPoints.yMin > y)
    		{
    			g_polyPoints.yMin = y;
    		}
    		if (g_polyPoints.xMax < x)
    		{
    			g_polyPoints.xMax = y;
    		}
    		if (g_polyPoints.xMin > x)
    		{
    			g_polyPoints.xMin = x;
    		}
    	}
    	int xLen = g_polyPoints.xMax - g_polyPoints.xMin + 1;
    	int yLen = g_polyPoints.yMax - g_polyPoints.yMin + 1;
    	g_pbEdgeFlag = new bool *[yLen];
    	for (int i = 0; i < yLen; ++i)
    	{
    		g_pbEdgeFlag[i] = new bool [xLen];
    		memset (g_pbEdgeFlag[i], 0, sizeof (bool) * xLen);
    	}
    }
    // Free the memory
    void destroy (void)
    {
    	int yLen = g_polyPoints.yMax - g_polyPoints.yMin + 1;
    	for (int i = 0; i < yLen; ++i)
    	{
    		delete g_pbEdgeFlag[i];
    	}
    	delete g_pbEdgeFlag;
    
    }
    void scanConvertLineAndFlag (const Point & p1, const Point & p2)
    {
    	int x1 = p1.x;
    	int y1 = p1.y;
    	int x2 = p2.x;
    	int y2 = p2.y;
    	int x, y, dx, dy, e;
    	// k does not exist
    	if (x1 == x2)
    	{
    		if (y1 < y2)
    		{
    			y = y1;
    			glBegin (GL_POINTS);
    			while (y <= y2)
    			{
    				glVertex2i (x1, y);
    				// Flag current point
    				bool bFlag = g_pbEdgeFlag[y-g_polyPoints.yMin][x1-g_polyPoints.xMin];
    				g_pbEdgeFlag[y-g_polyPoints.yMin][x1-g_polyPoints.xMin] = !bFlag;
    	
    				++ y;
    			}
    			glEnd ();
    		} // if (y1 < y2)
    		else
    		{
    			y = y2;
    			glBegin (GL_POINTS);
    			while (y <= y1)
    			{
    				glVertex2i (x1, y);
    				// Flag current point
    				bool bFlag = g_pbEdgeFlag[y-g_polyPoints.yMin][x1-g_polyPoints.xMin];
    				g_pbEdgeFlag[y-g_polyPoints.yMin][x1-g_polyPoints.xMin] = !bFlag;
    	
    				++ y;
    			}
    			glEnd ();
    		}
    	} // if (x1 == x2)
    	else if (y1 == y2) // k = 0
    	{
    		if (x1 < x2)
    		{
    			glBegin (GL_POINTS);
    			x = x1;
    			while (x <= x2)
    			{
    			glVertex2i (x, y1);
    				++ x;
    			}
    			glEnd ();
    		} // if (x1 < x2)
    		else 
    		{
    			x = x2;
    			glBegin (GL_POINTS);
    			while (x <= x1)
    			{
    				glVertex2i (x, y1);
    				++ x;
    			}
    			glEnd ();
    		}
    	}
    	else 
    	{
    		if (x1 > x2)
    		{
    			int temp = x1;
    			x1 = x2;
    			x2 = temp;
    			temp = y1;
    			y1 = y2;
    			y2 = temp;
    		}
    		x = x1;
    		y = y1;
    		dx = x2 - x1;
    		dy = y2 - y1;
    		// k = 1
    		if (dx == dy)
    		{
    			glBegin (GL_POINTS);
    			while (x <= x2)
    			{
    				glVertex2i (x, y);
    				// Flag current point
    				bool bFlag = g_pbEdgeFlag[y-g_polyPoints.yMin][x-g_polyPoints.xMin];
    				g_pbEdgeFlag[y-g_polyPoints.yMin][x-g_polyPoints.xMin] = !bFlag;
    				++ x;
    				++ y;
    			}
    			glEnd ();
    		}
    		else if (dx == -dy) // k = -1
    		{
    			glBegin (GL_POINTS);
    			while (x <= x2)
    			{
    				glVertex2i (x, y);
    				// Flag current point
    				bool bFlag = g_pbEdgeFlag[y-g_polyPoints.yMin][x-g_polyPoints.xMin];
    				g_pbEdgeFlag[y-g_polyPoints.yMin][x-g_polyPoints.xMin] = !bFlag;
    
    				++ x;
    				-- y;
    			}
    			glEnd ();
    		}
    		else if (dy > dx)	// k > 1
    		{
    			glBegin (GL_POINTS);
    			dx <<= 1;
    			e = - dy;
    			dy <<= 1;
    			y = y1 > y2 ? y2 : y1;
    			int maxY = y1 > y2 ? y1 : y2;
    			while (y <= maxY)
    			{
    				glVertex2i (x, y);
    				// Flag current point
    				bool bFlag = g_pbEdgeFlag[y-g_polyPoints.yMin][x-g_polyPoints.xMin];
    				g_pbEdgeFlag[y-g_polyPoints.yMin][x-g_polyPoints.xMin] = !bFlag;
    
    				++ y;
    				e += dx;
    				if (e > 0)
    				{
    					++ x;
    					e -= dy;
    				}
    			}
    			glEnd ();
    		}
    		else if (dy > 0)	// 0 < k < 1
    		{
    			e = -dx;
    			dx <<= 1;
    			dy <<= 1;
    			glBegin (GL_POINTS);
    			while (x <= x2)
    			{
    				glVertex2i (x, y);
    				// Flag current point
    				bool bFlag = g_pbEdgeFlag[y-g_polyPoints.yMin][x-g_polyPoints.xMin];
    				g_pbEdgeFlag[y-g_polyPoints.yMin][x-g_polyPoints.xMin] = !bFlag;
    
    				++ x;
    				e += dy;
    				if (e > 0)
    				{
    					e -= dx;
    					++ y;
    				}
    
    			}
    			glEnd ();
    		}
    		else if (-dy < dx)	// 0 > k > -1
    		{
    			e = -dx;
    			dx <<= 1;
    			dy <<= 1;
    			glBegin (GL_POINTS);
    			while (x <= x2)
    			{
    				glVertex2i (x, y);
    				// Flag current point
    				bool bFlag = g_pbEdgeFlag[y-g_polyPoints.yMin][x-g_polyPoints.xMin];
    				g_pbEdgeFlag[y-g_polyPoints.yMin][x-g_polyPoints.xMin] = !bFlag;
    
    				++ x;
    				e += dy;
    				if (e < 0)
    				{
    					-- y;
    					e += dx;
    				}
    			}
    			glEnd ();
    		}
    		else if (-dy > dx) // k < -1
    		{
    			e = dy;
    			dx <<= 1;
    			dy <<= 1;
    			glBegin (GL_POINTS);
    			y = y1 > y2 ? y1 : y2;
    			int minY = y1 > y2 ? y2 : y1;
    			while (y >= minY)
    			{
    				glVertex2i (x, y);
    				// Flag current point
    				bool bFlag = g_pbEdgeFlag[y-g_polyPoints.yMin][x-g_polyPoints.xMin];
    				g_pbEdgeFlag[y-g_polyPoints.yMin][x-g_polyPoints.xMin] = !bFlag;
    				e += dx;
    
    				-- y;
    				if (e > 0)
    				{
    					++ x;
    					e += dy;
    				}
    
    			}
    			glEnd ();
    		}
    	}
    }
    void init (void)
    {
    	glClearColor (0.0f, 0.0f, 0.0f, 1.0f);
    }
    
    void flagAllEdges (void)
    {
    	Point * pPoint = g_polyPoints.pPoint;
    	int n = g_polyPoints.n;
    	for (int i = 0; i < n; ++ i)
    	{
    		scanConvertLineAndFlag (pPoint[i], pPoint[(i+1)%n]);
    	}
    	for (int i = 0; i < n; ++i)
    	{
    		int j1 = (i+n-1)%n;
    		int j2 = (i+1)%n;
    		if (pPoint[j1].y > pPoint[i].y && pPoint[j2].y > pPoint[i].y ||
    			pPoint[j1].y < pPoint[i].y && pPoint[j2].y < pPoint[i].y)
    		{
    			g_pbEdgeFlag[pPoint[i].y - g_polyPoints.yMin][pPoint[i].x - g_polyPoints.xMin] = false;
    		}
    		else
    		{
    			g_pbEdgeFlag[pPoint[i].y - g_polyPoints.yMin][pPoint[i].x - g_polyPoints.xMin] = true;
    
    		}
    	}
    }
    
    void edgeFlagFillPolygon (void)
    {
    	int xLen = g_polyPoints.xMax - g_polyPoints.xMin + 1;
    	int yLen = g_polyPoints.yMax - g_polyPoints.yMin + 1;
    	int nScanLine = g_polyPoints.yMin;
    	glBegin (GL_POINTS);
    	for (int i = 0; i < yLen; ++i, ++ nScanLine)
    	{
    		bool bFlag = false;
    		int nHorizontal = g_polyPoints.xMin;
    		for (int j = 0; j < xLen; ++j, ++ nHorizontal)
    		{
    			if (g_pbEdgeFlag[i][j])
    			{
    				bFlag = !bFlag;
    			}
    			while (bFlag)
    			{
    				glVertex2i (nHorizontal, nScanLine);
    				++ j;
    				++ nHorizontal;
    				if (g_pbEdgeFlag[i][j])
    				{
    					bFlag = !bFlag;
    				}
    			}
    		}
    	}
    	glEnd ();
    
    }
    
    void display (void)
    {
    	glClear (GL_COLOR_BUFFER_BIT);
    	glLoadIdentity ();
    	glColor3f (1.0f, 0.0f, 0.0f);
    	//flagAllEdges ();
    	// Fill a polygon
    	edgeFlagFillPolygon ();
    	glutSwapBuffers ();
    }
    
    void reshape (int w, int h)
    {
    	glViewport (0, 0, (GLsizei) w, (GLsizei) h);
    	glMatrixMode (GL_PROJECTION);
    	glLoadIdentity ();
    	if (w <= h)
    	{
    		gluOrtho2D (-600.0, 600.0, -600.0 * (GLfloat) h / (GLfloat) w, 600.0 * (GLfloat) h / (GLfloat) w);
    	}
    	else
    	{
    		gluOrtho2D (-600.0 * (GLfloat) w / (GLfloat) h,600.0 * (GLfloat) w / (GLfloat) h, -600.0, 600.0);
    	}
    	glMatrixMode (GL_MODELVIEW);
    	glLoadIdentity ();
    }
    void keyboard (unsigned char key, int x, int y)
    {
    	switch (key)
    	{
    	case 27: // 'VK_ESCAPE'
    		exit (0);
    		break;
    	default:
    		break;
    	}
    }
    int main (int argc, char ** argv)
    {
    	glutInit (&argc, argv);
    	glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
    	glutInitWindowSize (600, 600);
    	glutCreateWindow ("Bresenham line");
    	init ();
    	inputPoints ();
    	flagAllEdges ();
    	glutReshapeFunc (reshape);
    	glutDisplayFunc (display);
    	glutKeyboardFunc (keyboard);
    	glutMainLoop ();
    	destroy ();
    	return 0;
    }
    

    polypoints.txt中的示例内容如下:
    7
    30 120
    10 70
    30 10
    60 50
    80 10
    120 90
    70 80
    


    作者: 风恋残雪

    出处: http://www.cnblogs.com/ghl_carmack

    关于作者:专注游戏引擎,关注VR,对操作系统、编译原理有深厚兴趣!

    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出, 原文链接,否则保留追究法律责任的权利。

  • 相关阅读:
    得到一个文件夹中所有文件的名称的几个方法(命令指示符, C++, python)
    C++ 使用命名规范
    【前端】直击源头的让你3秒理解并且会用Jsonp!!!
    React Native新手入门
    【方法】纯jQuery实现星巴克官网导航栏效果
    【方法】jQuery无插件实现 鼠标拖动切换图片/内容 功能
    【总结】前端框架:react还是vue?
    【总结】2017年当下最值得你关注的前端开发框架,不知道你就OUT了!
    【疑点】<p></p>标签为什么不能包含块级标签?还有哪些特殊的HTML标签?
    【总结】最常用的正则表达式大全,你要找的这里都有!
  • 原文地址:https://www.cnblogs.com/ghl_carmack/p/1896644.html
Copyright © 2020-2023  润新知