图形的绘制及裁剪
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;
}