计算机图形学实验二图形的绘制及裁剪

1.六芒星的绘制

选择File->New->Project,然后选择Win32 Console Application,选择一个名字,然后按OK。在谈出的对话框左边点Application Settings,找到Empty project并勾上,选择Finish。然后向该工程添加一个代码文件,并编写代码生成以下图形,如图1所示。修改各顶点颜色,使得每个顶点颜色不一样,多边形内部颜色渐变,如图2所示。
在这里插入图片描述
在这里插入图片描述

#include <GL/glut.h>
void Display(void)
{
	glClearColor(0.0, 0.0, 0.0, 0.0);
	glClear(GL_COLOR_BUFFER_BIT);

	//六角星
	glBegin(GL_POLYGON);
		glColor3f(1.0f, 1.0f, 1.0f);
		//先画凹点
		glVertex2f(-0.22f, 0.0f);

		glVertex2f(-0.4f, 0.3f);
		glVertex2f(-0.1f, 0.3f);

		glVertex2f(0.0f, 0.5f);
		glVertex2f(0.1f, 0.3f);

		glVertex2f(0.4f, 0.3f);
		glVertex2f(0.22f, 0.0f);

		glVertex2f(0.4f, -0.3f);
		glVertex2f(0.1f, -0.3f);

		glVertex2f(0.0f, -0.5f);
		glVertex2f(-0.1f, -0.3f);

		glVertex2f(-0.4f, -0.3f);
		glVertex2f(-0.22f, 0.0f);
	glEnd();

	glutSwapBuffers();
}
void Display1(void)
{
	glClearColor(0.0, 0.0, 0.0, 0.0);
	glClear(GL_COLOR_BUFFER_BIT);

	//六角星
	glBegin(GL_POLYGON);
		//先画中间的点
		glVertex2f(0.0f, 0.0f);
		//绿色凹点
		glColor3f(0.0f, 1.0f, 0.0f);
		glVertex2f(-0.22f, 0.0f);
		//黄色顶点
		glColor3f(1.0f, 1.0f, 0.0f);
		glVertex2f(-0.4f, 0.3f);
		glVertex2f(-0.1f, 0.3f);
		//红色顶点
		glColor3f(1.0f, 0.0f, 0.0f);
		glVertex2f(0.0f, 0.5f);
		glVertex2f(0.1f, 0.3f);
		//品红色顶点
		glColor3f(1.0f, 0.0f, 1.0f);
		glVertex2f(0.4f, 0.3f);
		glVertex2f(0.22f, 0.0f);
		//蓝色顶点
		glColor3f(0.0f, 0.0f, 1.0f);
		glVertex2f(0.4f, -0.3f);
		glVertex2f(0.1f, -0.3f);
		//青色顶点
		glColor3f(0.0f, 1.0f, 1.0f);
		glVertex2f(0.0f, -0.5f);
		glVertex2f(-0.1f, -0.3f);
		//绿色顶点
		glColor3f(0.0f, 1.0f, 0.0f);
		glVertex2f(-0.4f, -0.3f);
		glVertex2f(-0.22f, 0.0f);
	glEnd();

	glutSwapBuffers();
//	glFlush();
}

int main(int argc, char *argv[])
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
	glutInitWindowPosition(100, 100);

	glutInitWindowSize(400, 400);
	glutCreateWindow("无颜色");
	glutDisplayFunc(Display);

	glutInitWindowPosition(500, 100);
	glutInitWindowSize(400, 400);
	glutCreateWindow("有颜色");
	glutDisplayFunc(Display1);

	glutMainLoop();



	return 0;

}

2.用扫描线填充算法(或种子填充算法)

用扫描线填充算法(或种子填充算法)填充任一多边形域。
基本要求:
(1)数据输入项为:多边形的顶点数、各顶点x, y坐标。对于扫描线填充算法要输入扫描线间距;对于种子填充算法要输入种子象素的x, y坐标。
(2)输出填充区域。

在这里插入图片描述

#include <math.h>		// double floor(double  x ); // double ceil(double  x ); 
#include <gl/glut.h>
#include <iostream>
#include <vector>
#include <fstream>
using namespace std;

int Vertexs;

typedef struct _EdgeItem
{
	float	x;
	int		yMax;
	float	reverseK;					// 1/k
	_EdgeItem * next;
}EdgeItem;
vector<EdgeItem *> g_pItemVector;

typedef struct _Point
{
	int x;
	int y;
}Point;

typedef struct _EdgePtr
{
	int		nScanLine;					// Current scan line
	EdgeItem * pItem;					// Pointer to edge item
}EdgePtr;

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
}PolyPoints;

EdgePtr * g_pEdgeList;					// Edge list
EdgePtr * g_pActiveEdgeList;			// Active edge list
PolyPoints g_polyPoints;				// Storage for points of polygons

ifstream scin ("polypoints.txt");

void PutPixel(GLsizei x, GLsizei y)
{
//	glRectf(10*x,10*y,10*x+10,10*y+10);
	glRectf(10*x-5,10*y-5,10*x+10-5,10*y+10-5);
}


void inputPoints (void)
{
	int n;
	scin>>n;
	Vertexs = 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;
	int x, y;
	for (int i = 0; i < n; ++i)
	{
		scin>>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;
		}
	}
}
// Calculate the reverse of k
float calculateReverseK (const Point & p1, const Point & p2)
{
	return (float)(p2.x - p1.x) / (float)(p2.y - p1.y);
}

// Sort one scan line's list, first sort by x, if x is equal then sort by 1/k
void sortOneScanLineEdgeList (EdgePtr & edgePtr)
{
	// Sort by x (select sort)
	EdgeItem * pEdgeItem = edgePtr.pItem;
	EdgeItem * pNext;
	EdgeItem * pTmp;
	while (pEdgeItem)
	{
		pNext = pEdgeItem->next;
		pTmp = pEdgeItem;
		while (pNext)
		{
			if (pNext->x < pTmp->x)
			{
				pTmp = pNext;
			}
			pNext = pNext->next;
		}
		if (pTmp != pEdgeItem)
		{
			// Swap x
			float fTmp = pTmp->x;
			pTmp->x = pEdgeItem->x;
			pEdgeItem->x = fTmp;
			// Swap yMax
			
			int iTmp = pTmp->yMax;
			pTmp->yMax = pEdgeItem->yMax;
			pEdgeItem->yMax = iTmp;
			// Swap 1/k
			float kTmp = pTmp->reverseK;
			pTmp->reverseK = pEdgeItem->reverseK;
			pEdgeItem->reverseK = kTmp;
		}
		pEdgeItem = pEdgeItem->next;
	}
	// When the x is the same, then sort by 1/k
	pEdgeItem = edgePtr.pItem;
	EdgeItem * pStart = NULL;
	EdgeItem * pEnd = NULL;
	while (pEdgeItem)
	{
		// Find the start pointer and end pointer with the same x, then sort them
		pEnd = pStart = pEdgeItem;
		pNext = pStart->next;
		while (pNext && (pNext->x == pStart->x))
		{
			pEnd = pNext;
			pNext = pNext->next;
		}
		// Sort the edge list from pStart to pEnd by 1/k (select sort)
		while (pStart != pEnd)
		{
			pTmp = pStart;
			pNext = pTmp->next;
			while (pNext != pEnd)
			{
				if (pNext->reverseK < pTmp->reverseK)
				{
					pTmp = pNext;
				}
				pNext = pNext->next;
			}
			// Swap values
			if (pTmp != pStart)
			{
				// Swap x
				float fTmp = pTmp->x;
				pTmp->x = pStart->x;
				pStart->x = fTmp;
				// Swap yMax
				int iTmp = pTmp->yMax;
				pTmp->yMax = pStart->yMax;
				pStart->yMax = iTmp;
				// Swap 1/k
				float kTmp = pTmp->reverseK;
				pTmp->reverseK = pStart->reverseK;
				pStart->reverseK = kTmp;
				
			}
			pStart = pStart->next;
		} // while (pStart != pEnd)
		pEdgeItem = pEnd->next;
	}
}
// Construct the edge list
void constructEdgeList (void)
{
	// Construct the edge list
	int nScanLines = g_polyPoints.yMax - g_polyPoints.yMin + 1;
	g_pEdgeList = new EdgePtr[nScanLines];
	memset (g_pEdgeList, 0, sizeof (EdgePtr) * nScanLines);
	Point * pPoint = g_polyPoints.pPoint;
	int nScanLine = g_polyPoints.yMin;
	
	EdgeItem * pEdgeItem = NULL;
	for (int i = 0; i < nScanLines; ++i, ++ nScanLine)		//对每一个扫描线 nScanLine,将多边形的较低顶点在 nScanLine上的边,装入边表 g_pEdgeList 的 第 nScanLine 分量中
	{
		g_pEdgeList[i].nScanLine = nScanLine;
		for (int j = 0; j < g_polyPoints.n; ++j)			//遍历多边形的顶点,找到满足条件的边
		{
			if (pPoint[j].y == nScanLine)
			{
				int j1 = (j+g_polyPoints.n-1) % g_polyPoints.n;
				int j2 = (j+1) % g_polyPoints.n;
				// if point j1's y > nScanLine then add this edge to the current scanline's list
				if (pPoint[j1].y > nScanLine)
				{
					pEdgeItem = new EdgeItem;
					pEdgeItem->reverseK = calculateReverseK (pPoint[j], pPoint[j1]);
					pEdgeItem->x = (float)pPoint[j].x;
					pEdgeItem->yMax = pPoint[j1].y;
					// Add pEdgeItem to the scanline's list
					pEdgeItem->next = g_pEdgeList[i].pItem;
					g_pEdgeList[i].pItem = pEdgeItem;

				}
				// if point j2's y > nScanLine then add this edge to the curretn scanline's list
				if (pPoint[j2].y > nScanLine)
				{
					pEdgeItem = new EdgeItem;
					pEdgeItem->reverseK = calculateReverseK (pPoint[j], pPoint[j2]);
					pEdgeItem->x = (float)pPoint[j].x;
					pEdgeItem->yMax = pPoint[j2].y;
					// Add pEdgeItem to the scanline's list
					pEdgeItem->next = g_pEdgeList[i].pItem;
					g_pEdgeList[i].pItem = pEdgeItem;
				}
			} // if (pPoints[j].y == nScanLine)
		} // for (int j = 0; j < g_polyPoints.n; ++j)
		sortOneScanLineEdgeList (g_pEdgeList[i]);
	}
	// Init the active edge list
	g_pActiveEdgeList = new EdgePtr[nScanLines];
}
// free the memory
void destroy (void)
{
	if (g_pActiveEdgeList)
	{
		delete g_pActiveEdgeList;
	}
	int nScanLines = g_polyPoints.yMax - g_polyPoints.yMin + 1;
	EdgeItem * pItem, * pNext;
	if (g_pEdgeList)
	{
		for (int i = 0; i < nScanLines; ++i)
		{
			if (g_pEdgeList[i].pItem)
			{
				pItem = g_pEdgeList[i].pItem;
				pNext = pItem;
				while (pItem)
				{
					pNext = pItem->next;
					delete pItem;
					pItem = pNext;
				}
			}
		}
	}
}
void init (void)
{
	glClearColor (1.0f, 1.0f, 1.0f, 1.0f);
}

void activEdgeListFillPolygon (void)
{
	int nScanLines = g_polyPoints.yMax - g_polyPoints.yMin + 1;
	memset (g_pActiveEdgeList, 0, sizeof (EdgePtr) * nScanLines);
	int nScanLine = g_polyPoints.yMin;
	int i;
	for (i = 0;i < nScanLines;  ++ nScanLine, ++ i)					//找到第一个非空活动边表 g_pActiveEdgeList[i].pItem
	{
		if (g_pEdgeList[i].pItem)
		{
			g_pActiveEdgeList[i].pItem = g_pEdgeList[i].pItem;
			break;
		}
	}
	for (int j = i; j < nScanLines; ++j, ++ nScanLine)
	{
		if (g_pActiveEdgeList[j].pItem)
		{
			// Delete the edge where yMax = nScanLine				//填充之前先删除ymax=y(当前扫描线)的边结点	//(下闭)上开
			EdgeItem * pPre = NULL;
			EdgeItem * pNext = g_pActiveEdgeList[j].pItem;
			bool bEven = true;
			while (pNext)
			{
				if (pNext->yMax == nScanLine)
				{
					if (!pPre)
					{
						g_pActiveEdgeList[j].pItem = pNext->next;
						pNext = pNext->next;
					}
					else
					{
						pPre->next = pNext->next;
						pNext = pNext->next;
					}
				}
				else 
				{
					bEven = !bEven;
					pPre = pNext;
					pNext = pNext->next;
				}
			} // while (pNext)

			// Fill the scan line when bFill is true
			bool bFill = false;
			pNext = g_pActiveEdgeList[j].pItem;					//对当前活动边表 g_pActiveEdgeList[j].pItem 进行填充
			while (pNext && bEven)	
			{
				bFill = !bFill;
				if (bFill)										//通过bFill控制填充区间的始点
				{
/* 
					int x1 = (int)(pNext->x + 0.5);				//始点四舍五入
					int x2 = (int)(pNext->next->x + 0.5);		//终点四舍五入
			
					for (int i = x1; i <= x2; ++i)				//左闭右闭
*/ 

/* 
					int x1 = ceil(pNext->x);				//始点向右取整
					int x2 = floor(pNext->next->x);			//终点向左取整
			
					for (int i = x1; i <= x2; ++i)				//左闭右闭
*/ 

 /
					int x1 = 25-(int)(25-(pNext->x));				//始点为:左交点上取整。  交点不是整点时,始点是交点右侧整点;交点是整点时,始点就是交点,保证左闭。
					int x2 = 25-(int)(25-(pNext->next->x))-1;		//终点为:右交点上取整-1. 不管交点是不是整点,终点都是交点左侧整点,保证右开。
					
					int x11 = pNext->x;
					
					for (int i = x1; i <= x2; ++i)					
 /

					{
						PutPixel(i, nScanLine);
					}
				}
				pNext = pNext->next;
			}	// while (pNext)
			pNext = g_pActiveEdgeList[j].pItem;
			int kk = j + 1;
			if (kk < nScanLines)
			{
				while (pNext)											//此循环将活动边表 g_pActiveEdgeList[kk].pItem 每个结点的x变为x+1/k,修正后的结点顺序正好倒序了
				{		
					EdgeItem * pItem = new EdgeItem;
					pItem->x = pNext->x + pNext->reverseK;
					pItem->reverseK = pNext->reverseK;
					pItem->yMax = pNext->yMax;
					pItem->next = g_pActiveEdgeList[kk].pItem;
					g_pActiveEdgeList[kk].pItem = pItem;
					pNext = pNext->next;
					g_pItemVector.push_back (pItem);
				} // while (pNext)
				// Add edge list to active edge list
				pNext = g_pEdgeList[kk].pItem;
				EdgeItem * pTemp = NULL;
				while (pNext)											//此循环将边表 g_pEdgeList[kk].pItem 中第kk扫描线的边结点信息倒序插在 活动边表 g_pActiveEdgeList[kk].pItem 之前
				{
					pTemp = new EdgeItem;
					pTemp->reverseK = pNext->reverseK;
					pTemp->x = pNext->x;
					pTemp->yMax =pNext->yMax; 
					g_pItemVector.push_back (pTemp);
					pTemp->next = g_pActiveEdgeList[kk].pItem;
					g_pActiveEdgeList[kk].pItem = pTemp;
					pNext = pNext->next;
				}
				sortOneScanLineEdgeList (g_pActiveEdgeList[kk]);
			}


		} // 			if (g_pActiveEdgeList[j].pItem)
	}
	//这里为了简单所以把分配的内存放在vector容器中,方便删除
	vector<EdgeItem*>::iterator itr = g_pItemVector.begin();
	vector<EdgeItem*>::iterator endItr = g_pItemVector.end ();
	while (itr != endItr)
	{
		delete (*itr);
		++ itr;
	}
	g_pItemVector.clear ();
}

//绘制坐标线
void DrawCordinateLine(void)
{
	int i = 0 ;
	//坐标线为黑色
	glColor3f(0.0f, 0.0f ,0.0f);
	glBegin(GL_LINES);
	for (i=10;i<=250;i=i+10)
	{
		glVertex2f((float)(i), 0.0f);
		glVertex2f((float)(i), 250.0f);
		glVertex2f(0.0f, (float)(i));
		glVertex2f(250.0f, (float)(i));
	}
	glEnd();
}

void DrawPolygonLine(void)
{
	glColor3f(0.0f, 1.0f, 0.0f);
	glBegin(GL_LINE_LOOP);
	for (int i = 0; i < Vertexs; ++i)
	{
		glVertex2i(10*g_polyPoints.pPoint[i].x, 10*g_polyPoints.pPoint[i].y); 
	}
	glEnd();

}
//绘制一个点,这里用一个正方形表示一个点。
void display (void)
{
	glClear (GL_COLOR_BUFFER_BIT);

	//画出坐标线
	DrawCordinateLine();
	

	// Fill a polygon
	glColor3f (1.0f, 0.0f, 0.0f);
	activEdgeListFillPolygon ();
	DrawPolygonLine();
	glutSwapBuffers ();
}

void reshape (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);
}

int main (int argc, char ** argv)
{
	glutInit (&argc, argv);
	glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
	glutInitWindowSize(600, 600);
	glutInitWindowPosition(100,100);
	glutCreateWindow ("AET填充算法");
	init ();
	inputPoints ();
	constructEdgeList ();

	glutDisplayFunc (display);
	glutReshapeFunc (reshape);
	glutMainLoop ();
	destroy ();
	return 0;
}

polypoints.txt

7
7 8
3 12
1 7
3 1
6 5
8 1
12 9


3.实现不同属性的点和线、字符显示、反走样技术

在这里插入图片描述

#include <GL/glut.h>
#include <cstring>
int winWidth = 400, winHeight = 300;     //窗口的宽度和高度

void myDisplay1(void)
{
	glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
	glClear(GL_COLOR_BUFFER_BIT); //用当前背景色填充窗口
   	glColor3f(0.0f, 0.0f, 0.0f); //设置当前的绘图绘图RGB颜色

	//绘制不同大小的点
	GLfloat sizes[2];  //保存绘制点的尺寸范围
	GLfloat step;      //保存绘制点尺寸的步长
	GLfloat curSize;   //当前绘制的点的大小
	glGetFloatv(GL_POINT_SIZE_RANGE,sizes);
	glGetFloatv(GL_POINT_SIZE_GRANULARITY,&step);

	curSize=sizes[0];
	
	for (int i=0;i<25;i++)
	{
		glPointSize(curSize);
		glBegin(GL_POINTS);
			glVertex3f(25.0+i*8,200.0,0.0);
		glEnd();
		curSize +=step*2;
	}

	//绘制一条宽度为5的直线
	glLineWidth(5);
	glBegin(GL_LINES);
		glVertex3f(25.0,160.0,0.0);
		glVertex3f(225.0,160.0,0.0);
	glEnd();

	//绘制一条虚线
	glEnable(GL_LINE_STIPPLE);
	glLineStipple(1,0x00FF);
	glBegin(GL_LINES);
		glVertex3f(25.0,120.0,0.0);
		glVertex3f(225.0,120.0,0.0);
	glEnd();

	//绘制一条宽度为3的点划线
	glLineWidth(3);
	glLineStipple(1,0xFF0C);
	glBegin(GL_LINES);
		glVertex3f(25.0,80.0,0.0);
		glVertex3f(225.0,80.0,0.0);
	glEnd();

	//增加重复因子绘制的点划线
	glLineStipple(4,0xFF0C);
	glBegin(GL_LINES);
		glVertex3f(25.0,40.0,0.0);
		glVertex3f(225.0,40.0,0.0);
	glEnd();
	glDisable(GL_LINE_STIPPLE);

	glFlush();//刷新OpenGL命令队列

}

void ChangeSize1(int w, int h)
{
	winWidth = w;	winHeight = h;
	glViewport(0, 0, w, h);           //指定窗口显示区域
	glMatrixMode(GL_PROJECTION);      //设置投影参数
	glLoadIdentity();
	gluOrtho2D(0.0,winWidth,0.0,winHeight);
}

//显示字符
void Initial(void)
{
	glClearColor(1.0f, 1.0f, 1.0f, 1.0f);    
	glColor3f(0.0f, 0.0f, 0.0f);
}

void output(int x, int y, char *string)
{
	int len, i;
	glRasterPos2f(x, y);
	len = (int) strlen(string);
	for (i = 0; i < len; i++)
	{
		glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, string[i]);
	}
}
void Display2(void)
{
	glClear(GL_COLOR_BUFFER_BIT); //用当前背景色填充窗口 
	glColor3f(1.0f, 0.0f, 0.0f); //设置当前的绘图绘图 RGB 颜色
	output(100,100,"hello!");
	glFlush();//刷新 OpenGL命令队列 
}

void ChangeSize2(int w, int h)
{
	winWidth = w;	winHeight = h;
	glViewport(0, 0, w, h);           //指定窗口显示区域
	glMatrixMode(GL_PROJECTION);      //设置投影参数
	glLoadIdentity();
	gluOrtho2D(0.0,winWidth,0.0,winHeight);
}
//反走样

GLuint lineList; //指定显示列表ID
void Initial1()
{
	glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
	glLineWidth(12.0f);
	glColor4f (0.0, 0.6, 1.0, 1.0);
	lineList = glGenLists(1);
	glNewList(lineList, GL_COMPILE);  //定义显示列表
		glBegin(GL_LINE_LOOP);
			glVertex2f(1.0f, 1.0f);
			glVertex2f(4.0f, 2.0f);
			glVertex2f(2.0f, 5.0f);
		glEnd();
	glEndList();
}

void ChangeSize3(GLsizei w, GLsizei h)
{
	if(h == 0)		h = 1;
   	glViewport(0, 0, w, h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	if(w<=h)
		gluOrtho2D(0.0, 5.0, 0.0, 6.0*(GLfloat)h/(GLfloat)w);
	else
		gluOrtho2D(0.0, 5.0*(GLfloat)w/(GLfloat)h, 0.0, 6.0);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

void Displayt(void)
{	
	glClear(GL_COLOR_BUFFER_BIT);
	glCallList(lineList);
    	glFlush();
}

void Displayw(void)
{
	glClear(GL_COLOR_BUFFER_BIT);
	glEnable(GL_LINE_SMOOTH);      //使用反走样
	glEnable (GL_BLEND);             //启用混合函数
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);  //指定混合函数
	glCallList(lineList);
    	glFlush();
}
int main(int argc, char *argv[])
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
    glutInitWindowPosition(100, 100);
    glutInitWindowSize(400, 400);
    glutCreateWindow("点与线");
    glutDisplayFunc(myDisplay1);
    glutReshapeFunc(ChangeSize1);
   // glutMainLoop();

	//显示字符
	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);  
	glutInitWindowSize(400,400);                  
	glutInitWindowPosition(500,100);              
	glutCreateWindow("显示字符");
	glutDisplayFunc(Display2);
	glutReshapeFunc(ChangeSize2);
	Initial(); 
	
	//反走样
      glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); 
	glutInitWindowSize(400, 400);
		glutInitWindowPosition(100, 500);
	glutCreateWindow("原始图形");
	glutDisplayFunc(Displayt);
    glutReshapeFunc(ChangeSize3);
   	Initial1();

	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); 
	glutInitWindowPosition(500, 500);
	glutInitWindowSize(400, 400);
	glutCreateWindow("反走样图形");
	glutDisplayFunc(Displayw);
   	glutReshapeFunc(ChangeSize3);
	Initial1();                             
	glutMainLoop();    
    return 0;
}

4.实现线段裁剪的Cohen-Sutherland算法或Liang-Barsky算法

要求:1)输入直线段的两端点坐标:p1(x1,y1)、p2(x2,y2),以及窗口的四条边界坐标:wyt、wyb、wxl和wxr。
2)输出裁剪前与裁剪后的结果。
在这里插入图片描述

#include <GL/glut.h>
#include <stdio.h>
#include <stdlib.h>
#define LEFT_EDGE 1
#define RIGHT_EDGE 2
#define BOTTOM_EDGE 4
#define TOP_EDGE 8

struct Rectangle {
	float xmin, xmax, ymin, ymax;
};
Rectangle rect;

int x0, y0, x1, y1;
int accept=1;

void Init() {
	
	glClearColor(0.0, 0.0, 0.0, 0.0);
	glShadeModel(GL_FLAT);
	rect.xmin=100;
	rect.xmax=300;
	rect.ymin=100;
	rect.ymax=300;
	accept=1;
	//x0=160, y0=150, x1=230, y1=180; 
	//x0=360, y0=50, x1=30, y1=360; //此时窗口内有直线段,accept=1
	x0=280, y0=50, x1=180, y1=150; //此时窗口内有直线段,accept=1
	//x0=280, y0=50, x1=380, y1=150; //此时窗口内无直线段,accept=0
	printf("Press key 'c' to Clip!\nPress key 'r' to Restore!\n");
}

void LineGL(int x0, int y0, int x1, int y1) {
	glBegin(GL_LINES);
	
	glColor3f(1.0f, 0.0f, 0.0f);
	glVertex2f(x0, y0);
	
	glColor3f(0.0f, 1.0f, 0.0f);
	glVertex2f(x1, y1);
	
	glEnd();
}

void myDisplay() {
	glClear(GL_COLOR_BUFFER_BIT);
	glColor3f(1.0f, 0.0f, 0.0f);
	glRectf(rect.xmin, rect.ymin, rect.xmax, rect.ymax);
	if (accept)//窗口内有直线段时才显示
		LineGL(x0, y0, x1, y1);
	glFlush();
}

void Reshape(int w, int h) {
	glViewport(0, 0, (GLsizei)w, (GLsizei)h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluOrtho2D(0.0, (GLdouble)w, 0.0, (GLdouble)h);
}

int CompCode(int x, int y, Rectangle rect) {
	int code = 0;
	if (x<rect.xmin)
		code=code|LEFT_EDGE;
	if (x>rect.xmax)
		code=code|RIGHT_EDGE;//
	if (y<rect.ymin)
		code=code|BOTTOM_EDGE;//
	if (y>rect.ymax)
		code=code|TOP_EDGE;//
	return code;
}
int cohensutherlandlineclip(Rectangle rect, int& x0, int& y0, int& x1, int& y1) {
	float x, y;
	int done=0;//控制求交循环
	int code0, code1, codeout;
	code0=CompCode(x0, y0, rect);
	code1=CompCode(x1, y1, rect);
	do {
		if (!(code0|code1)) { //两端点都在窗口内
			accept=1;//取之
			done=1;
		} else if ((code0&code1)!=0) { //两端点都在窗口某边界外侧
			accept=0;//弃之
			done=1;
		} else {
			if (code0!=0)
				codeout=code0;
			else
				codeout=code1;
			
			if (codeout&LEFT_EDGE) {
				y=y0+(y1-y0)*(rect.xmin-x0)/(x1-x0);
				x=rect.xmin;
			} else if (codeout&RIGHT_EDGE) {
				y=y0+(y1-y0)*(rect.xmax-x0)/(x1-x0);
				x=rect.xmax;
			} else if (codeout&TOP_EDGE) {
				x=x0+(x1-x0)*(rect.ymax-y0)/(y1-y0);
				y=rect.ymax;
			} else if (codeout&BOTTOM_EDGE) {
				y=rect.ymin;
				x=x0+(x1-x0)*(rect.ymin-y0)/(y1-y0);
			}
			
			if (codeout==code0) {
				x0=x;
				y0=y;
				code0=CompCode(x0, y0, rect);
			} else {
				x1=x;
				y1=y;
				code1=CompCode(x1, y1, rect);
			}
		}
	} while (!done);
	return accept;
}

void keyboard(unsigned char key, int x, int y) {
	switch (key) {
	case 'c':
		cohensutherlandlineclip(rect, x0, y0, x1, y1);
		glutPostRedisplay();
		break;
	case 'r':
		Init();
		glutPostRedisplay();
		break;
	case 'x':
		exit(0);
		break;
		default:
			break;
	}
}

int main(int argc, char *argv[]) {
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGB|GLUT_SINGLE);
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(640, 480);
	glutCreateWindow("Cohen-Sutherland编码裁剪算法");

	Init();
	glutDisplayFunc(myDisplay);
	glutReshapeFunc(Reshape);
	glutKeyboardFunc(keyboard);
	glutMainLoop();
	return 0;
}

  • 6
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值