梁友栋-Barsky直线裁剪算法计算机图形学课程设计
- 格式:doc
- 大小:567.87 KB
- 文档页数:21
《计算机图形学实验》报告任课教师:钱文华2016年春季学期实验:梁友栋裁剪实验时间:2016年11月17日实验地点:信息学院2204实验目的:掌握梁友栋裁剪程序代码:#include <stdio.h>#include <glut.h>#include <stdlib.h>#include <math.h>class wcPt2D{public:GLfloat x,y;void setCoords(GLfloat xCoord,GLfloat yCoord){x=xCoord;y=yCoord;}GLfloat getx() const{return x;}GLfloat gety() const{return y;}};inline GLint round(const GLfloat a){return GLint(a+0.5);}void setPixel(int x,int y){glBegin(GL_POINTS);glVertex2i(x,y);glEnd();}void init(){glClearColor(1.0,1.0,1.0,0.0);glMatrixMode (GL_PROJECTION);gluOrtho2D(-200.0,200.0,-200.0,200.0);}void lineBres(GLfloat x0,GLfloat y0,GLfloat xEnd,GLfloat yEnd){ int dx = fabs(xEnd - x0),dy = fabs(yEnd - y0);int p = 2*dy - dx;int twoDy = 2*dy,twoDyMinusDx = 2*(dy - dx);int x,y;if(x0>xEnd){x = xEnd;y = yEnd;xEnd = x0;}else{x = x0;y = y0;}setPixel(x,y);while(x<xEnd){x++;if(p<0)p+=twoDy;else{y++;p+=twoDyMinusDx;}setPixel(x,y);}}GLint clipTest(GLfloat p,GLfloat q,GLfloat *u1,GLfloat *u2){ GLfloat r;GLint returnValue = true;if(p<0.0){r = q/p;if(r>*u2)returnValue = false;elseif(r>*u1)*u1 = r;}elseif(p>0.0){r = q/p;if(r<*u1)returnValue = false;else if(r<*u2)*u2 = r;}elseif(q<0.0)returnValue = false;return(returnValue);}void lineClipLiangBarsk(wcPt2D winMin,wcPt2D winMax,wcPt2D p1,wcPt2D p2){GLfloat u1 = 0.0,u2 = 1.0,dx = p2.getx()-p1.getx(),dy;GLfloat x1 = p1.getx(),y1 = p1.gety();GLfloat x2 = p2.getx(),y2 = p2.gety();if(clipTest(-dx,p1.getx()-winMin.getx(),&u1,&u2))if(clipTest(dx,winMax.getx()-p1.getx(),&u1,&u2)){dy = p2.gety()-p1.gety();if(clipTest(-dy,p1.gety()-winMin.gety(),&u1,&u2)){if(clipTest(dy,winMax.gety()-p1.gety(),&u1,&u2)){if(u2<1.0){p2.setCoords(p1.getx()+u2*dx,p1.gety()+u2*dy);}if(u1>0.0){p1.setCoords(p1.getx()+u1*dx,p1.gety()+u1*dy);}glColor3f(0.0,0.0,0.0);lineBres(x1,y1,p1.getx(),p1.gety());lineBres(p2.getx(),p2.gety(),x2,y2);glColor3f(1.0,0.0,0.0);lineBres(p1.getx(),p1.gety(),p2.getx(),p2.gety());}}else{glColor3f(0.0,0.0,0.0);lineBres(x1,y1,x2,y2);}}}void displayliangyoudongcaijian(){glClear(GL_COLOR_BUFFER_BIT);glLineWidth(5.0);glColor3f(0.0,0.0,0.0);glBegin(GL_LINE_LOOP);glVertex2i(100,100);glVertex2i(100,-100);glVertex2i(-100,-100);glVertex2i(-100,100);glEnd();glPointSize(4);wcPt2D test1[4] = {{-100.0,-100.0},{100.0,100.0},{-150.0,-200.0},{200.0,120.0}};wcPt2D test2[4] = {{-100.0,-100.0},{100.0,100.0},{-150.0,-120.0},{0.0,0.0}};wcPt2D test3[4] = {{-100.0,-100.0},{100.0,100.0},{-50.0,50.0},{150.0,150.0}};wcPt2D test4[4] = {{-100.0,-100.0},{100.0,100.0},{-50.0,0.0},{60.0,50.0}};wcPt2D test5[4] = {{-100.0,-100.0},{100.0,100.0},{-170.0,-200.0},{200.0,-120.0}};lineClipLiangBarsk(test1[0],test1[1],test1[2],test1[3]);lineClipLiangBarsk(test2[0],test2[1],test2[2],test2[3]);lineClipLiangBarsk(test3[0],test3[1],test3[2],test3[3]);lineClipLiangBarsk(test4[0],test4[1],test4[2],test4[3]);lineClipLiangBarsk(test5[0],test5[1],test5[2],test5[3]);glFlush();}void main(int argc, char* argv[]){glutInit(&argc,argv);glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);glutInitWindowPosition(50,100);glutInitWindowSize(400,300);glutCreateWindow("梁友栋裁剪算法");init();glutDisplayFunc(displayliangyoudongcaijian);glutMainLoop();}实验结果:。
计算机图形学——梁友栋-Barsky算法梁算法是计算机图形学上最经典的⼏个算法,也是⽬前唯⼀⼀个以中国⼈命名的出现在国内外计算机图形学课本的算法,我之前在介绍裁剪算法的时候介绍过这个算法这⼏天复习图形学,发现当时那篇博客写的很空洞,⼀些关键性的推理式⼦讲的不是很清楚,于是在这⾥仔细介绍⼀下。
最近发现中国⼤学MOOC上中国农业⼤学的赵明教授讲的很不错,课程短⼩精悍,感兴趣的同学可以去看⼀下⼀、直线的参数⽅程梁算法表⽰直线是通过直线的参数⽅程来确定的,也就是说给出两个点,利⽤参数表⽰直线。
这⾥对U的理解就是(x,y)点在所给两点之间线段上的位置。
⼆、出边和⼊边把被裁剪的红⾊直线段看 成是⼀条有⽅向的线段,把窗⼝ 的四条边分成两类:⼊边和出边⼊边:直线由窗⼝外向窗⼝内移动时和窗⼝边界相交的边(左边界和下边界)。
出边:直线由窗⼝内向窗⼝外移动时和窗⼝边界相交的边(右边界和上边界)。
裁剪结果的线段起点是直线和两条⼊边的交点以及始端点三 个点⾥最前⾯的⼀个点,即参数u最⼤的那个点;裁剪线段的终点是和两条出边的交点以及端点最后⾯的⼀个 点,取参数u最⼩的那个点。
值得注意的是,当u从-∞到+∞遍历直线时,⾸先对裁剪窗⼝的两条边界直线(下边和左边)从外⾯向⾥⾯移动,再对裁剪窗⼝两条边界直线(上边和右边)从⾥⾯向外⾯移动。
如果⽤u1,u2分别表⽰ 线段(u1≤u2)可见部分的开始和结束上⾯就是梁友栋先⽣的发现,但⼜有了新的问题:如何判断出边和⼊边?四个U值是如何求出来的?判断线段某⼀部分是否在窗⼝内,可以简化为判断直线上⼀个点是否在窗⼝内的问题。
我们知道梁友栋算法的基本出发点是直线的参数⽅程,那么对于那些不会被裁剪掉的点⼀定会满⾜下⾯的不等式:三、运算所⽤的量将上⾯的不等式移项得:在这⾥可以确定那些直线与裁剪窗⼝的交点中P K<0的点输⼊⼊边,P K>0的点属于出边1)分析P k=0的情况如果还满⾜q k<0则线段完全在边界外,应舍弃该线段如果q k≥0则进⼀步判断(2)当p k≠0时:当p k<0时线段从裁剪边界延长线的外部 延伸到内部,是⼊边交点当p k> 0时线段从裁剪边界延长线的内部 延伸到外部,是出边交点线段和窗⼝边界⼀共有四个交点,根据p k的符号,就知道 哪两个是⼊交点,哪两个是出交点当p k< 0时:对应⼊边交点当p k> 0时:对应出边交点⼀共四个u值,再加上u=0、u=1两个端点值,总共六个值把pk<0的两个u值和0⽐较去找最⼤的,把pk>0的两个u值 和1⽐较去找最⼩的,这样就得到两个端点的参数值四、⼩结直线参数化直线段看成是有⽅向的把窗⼝的四条边分为⼊边和出边。
河南理工大学万方科技学院课程设计报告2011 — 2012学年第二学期课程名称计算机图形学设计题目计算机图形学基本算法演示系统设计学生姓名学号专业班级网络11升—1班指导教师徐文鹏2012 年5 月28 日目录第1章设计内容与要求 (1)1.1 总体目标和要求 (1)1.2内容与要求 (1)1.2.1 直线的生成 (1)1.2.2 圆弧的生成 (1)1.2.3 线段裁剪 (2)1.2.4 多边形裁剪 (2)1.2.5 综合 (2)第2章总体设计 (3)2.1 Bresenham算法画直线 (3)2.1.1 Bresenham算法画直线理论基础 (3)2.1.2 Bresenham算法画直线原理 (3)2.2 Bresenham算法画圆 (4)2.2.1 Bresenham算法画圆理论基础 (4)2.2.2 Bresenham算法画圆原理 (5)2.3 梁友栋-Barsky算法进行线段裁剪 (6)2.3.1梁友栋-Barsky算法进行线段裁剪基本原理 (6)2.4 Sutherland-Hodgman算法进行多边形裁剪 (8)2.4.1 Sutherland—Hodgman多边形裁剪算法思想 (8)2.4.2 点在边界内侧的判断方法 (8)2.4.4 Sutherland-Hodgeman多边形裁剪算法特点 (8)第3章详细设计 (9)3.1 Bresenham算法画直线 (9)3.1.1 Bresenham 算法画线算法具体实现过程 (9)3.2 Bresenham算法画圆 (9)3.2.1 Bresenham 算法画圆核心代码 (9)3.3 梁友栋-Barsky算法进行线段裁剪 (10)3.3.1梁友栋-Barsky算法推导过程 (10)3.3.2梁友栋-Barsky算法进行线段裁剪的步骤 (11)3.4 Sutherland-Hodgman算法进行多边形裁剪 (11)3.4.1 Sutherland—Hodgman多边形裁剪算法步骤 (11)3.5将画线、画圆、线段裁剪和多边形裁剪综合 (12)第4章功能实现 (14)4.1用Bresenham算法画线测试结果 (14)4.2用Bresenham算法画圆测试结果 (14)4.3梁友栋-Barsky算法进行线段裁剪测试结果 (15)4.4 Sutherland-Hodgman算法进行多边形裁剪测试结果 (16)4.5将四种算法综合测试结果 (16)第5章总结 (17)参考文献 (18)第1章设计内容与要求1.1 总体目标和要求目标:以图形学算法为目标,深入研究。
计算机图形学课程设计
要求:程序中有必要的注释,程序中变量命名规范合理。
否则,成绩按降一档处理。
1、交互式绘图程序设计
内容:使用VC++6.0编程环境,实现一个简单的交互式绘图界面。
要求:用户通过鼠标能交互式输入一些数据,实现采用橡皮筋技术绘制相应的图形,要求能演示1-2个基本算法(Bresenham画线算法)。
选做:在状态栏上当鼠标运动时,能实时显示鼠标的当前坐标。
2、Cohen-Sutherland裁剪算法的实现
内容:使用VC++6.0环境,编程实现Cohen_Sutherland二维裁剪算法的实现。
要求:用户可以交互输入要裁剪线段的两个顶点,将裁剪后的线段和被裁剪掉的线段以不同的颜色显示在视图中。
3、Liang-Barsky裁剪算法的实现
内容:使用VC++6.0环境,编程实现Liang_Barsky二维裁剪算法的实现。
要求:用户可以交互输入要裁剪线段的两个顶点,将裁剪后的线段和被裁剪掉的线段以不同的颜色显示在视图中。
4、满足四象限的Bresenham绘制直线算法的实现
内容:使用VC++6.0环境,编程实现满足四象限的Bresenham直线段算法,并能够设置线宽和颜色属性。
要求:要求直线段端点可以由用户随机输入。
5、用OpenGL生成裁剪NURBS曲面
内容:使用VC++6.0编程环境,用OpenGL实现一个裁剪NURBS曲面的绘制。
要求:用户能交互式输入控制多面体的顶点,和剪切曲线的顶点数目和顶点坐标。
河南理工大学万方科技学院课程设计报告2011 — 2012学年第二学期课程名称计算机图形学设计题目计算机图形学基本算法演示系统设计学生姓名学号专业班级网络11升—1班指导教师徐文鹏2012 年5 月28 日目录第1章设计内容与要求 (1)1.1 总体目标和要求 (1)1.2内容与要求 (1)1.2.1 直线的生成 (1)1.2.2 圆弧的生成 (1)1.2.3 线段裁剪 (2)1.2.4 多边形裁剪 (2)1.2.5 综合 (2)第2章总体设计 (3)2.1 Bresenham算法画直线 (3)2.1.1 Bresenham算法画直线理论基础 (3)2.1.2 Bresenham算法画直线原理 (3)2.2 Bresenham算法画圆 (4)2.2.1 Bresenham算法画圆理论基础 (4)2.2.2 Bresenham算法画圆原理 (5)2.3 梁友栋-Barsky算法进行线段裁剪 (6)2.3.1梁友栋-Barsky算法进行线段裁剪基本原理 (6)2.4 Sutherland-Hodgman算法进行多边形裁剪 (8)2.4.1 Sutherland—Hodgman多边形裁剪算法思想 (8)2.4.2 点在边界内侧的判断方法 (8)2.4.4 Sutherland-Hodgeman多边形裁剪算法特点 (8)第3章详细设计 (9)3.1 Bresenham算法画直线 (9)3.1.1 Bresenham 算法画线算法具体实现过程 (9)3.2 Bresenham算法画圆 (9)3.2.1 Bresenham 算法画圆核心代码 (9)3.3 梁友栋-Barsky算法进行线段裁剪 (10)3.3.1梁友栋-Barsky算法推导过程 (10)3.3.2梁友栋-Barsky算法进行线段裁剪的步骤 (11)3.4 Sutherland-Hodgman算法进行多边形裁剪 (11)3.4.1 Sutherland—Hodgman多边形裁剪算法步骤 (11)3.5将画线、画圆、线段裁剪和多边形裁剪综合 (12)第4章功能实现 (14)4.1用Bresenham算法画线测试结果 (14)4.2用Bresenham算法画圆测试结果 (14)4.3梁友栋-Barsky算法进行线段裁剪测试结果 (15)4.4 Sutherland-Hodgman算法进行多边形裁剪测试结果 (16)4.5将四种算法综合测试结果 (16)第5章总结 (17)参考文献 (18)第1章设计内容与要求1.1 总体目标和要求目标:以图形学算法为目标,深入研究。
继而策划、设计并实现一个能够表现计算机图形学算法原理的或完整过程的演示系统,并能从某些方面作出评价和改进意见。
通过完成一个完整程序,经历策划、设计、开发、测试、总结和验收各阶段,达到:1)巩固和实践计算机图形学课程中的理论和算法;2)学习表现计算机图形学算法的技巧;3)培养认真学习、积极探索的精神。
总体要求:策划、设计并实现一个能够充分表现图形学算法的演示系统,界面要求美观大方,能清楚地演示算法执行的每一个步骤。
开发环境:Viusal C++ 6.0,VC2005或其他你认为比较熟悉的环境。
1.2 内容与要求实验分为五项内容。
1.2.1 直线的生成内容:用Bresenham算法画直线要求:1)鼠标移动时,显示鼠标当前位置2)显示判别式的计算过程和下一点的选择策略3)记录生成点的坐标4)图形生成过程可以重复进行1.2.2 圆弧的生成内容:用Bresenham算法画圆要求:1)鼠标移动时,显示鼠标当前位置2)显示判别式的计算过程和下一点的选择策略3)记录生成点的坐标4)图形生成过程可以重复进行5)橡皮筋技术实现1.2.3 线段裁剪内容:用梁友栋-Barsky算法进行线段裁剪要求:1)对于线段裁剪,线段被窗口的四条边裁剪的过程要显示出来2)用橡皮筋的形式输入剪裁线段1.2.4 多边形裁剪内容:用Sutherland-Hodgman算法进行多边形裁剪要求:1)裁剪过程需先输入一多边形,然后用窗口四边裁剪的过程中要显示顶点增删过程。
2)用橡皮筋的形式输入剪裁线段1.2.5 综合内容:把前四次的实验内容整合到一起要求:第2章总体设计2.1 Bresenham算法画直线2.1.1 Bresenham算法画直线理论基础计算机是如何画直线的?简单来说,就是过各行各列像素中心构造一组虚拟的网格线,按直线从起点到终点的顺序计算各直线与歌垂直网格线的交点,然后确定各列像素中与此交点最近的像素。
真实的直线是连续的,但我们的计算机显示的精度有限,不可能真正显示连续的直线,于是我们用一系列离散化后的点(像素)来近似表现这条直线。
2.1.2 Bresenham算法画直线原理接下来的问题就是如何尽可能高效地找到这些离散的点,Bresenham直线算法就是一个非常不错的算法。
Bresenham直线算法是用来描绘由两点所决定的直线的算法,它会算出一条线段在 n 维光栅上最接近的点。
这个算法只会用到较为快速的整数加法、减法和位元移位,常用于绘制电脑画面中的直线。
是计算机图形学中最先发展出来的算法。
这个算法的流程图如下:可以看到,算法其实只考虑了斜率在0 ~ 1 之间的直线,也就是与x 轴夹角在0 度到45 度的直线。
只要解决了这类直线的画法,其它角度的直线的绘制全部可以通过简单的坐标变换来实现。
2.2 Bresenham算法画圆2.2.1 Bresenham算法画圆理论基础Bresenham画圆算法与Bresenham 直线算法一样,其基本的方法是利用判别变量来判断选择最近的像素点,判别变量的数值仅仅用一些加、减和移位运算就可以计算出来。
为了简便起见,考虑一个圆心在坐标原点的圆,而且只计算八分圆周上的点,其余圆周上的点利用对称性就可得到。
为什么只计算八分圆周上的点就可以了呢?和上面的直线算法类似,圆也有一个“八对称性”,如下图所示。
显然,我们只需要知道了圆上的一个点的坐标(x, y) ,利用八对称性,我们马上就能得到另外七个对称点的坐标。
2.2.2 Bresenham算法画圆原理和直线算法类似,Bresenham画圆算法也是用一系列离散的点来近似描述一个圆,如下图。
Bresenham画圆算法的流程图如下。
可以看到,与画线算法相比,画圆的循环中用到了整数的乘法,相对复杂了一些。
2.3 梁友栋-Barsky算法进行线段裁剪2.3.1梁友栋-Barsky算法进行线段裁剪基本原理我们知道,一条两端点为P1(x1,y1)、P2(x2,y2)的线段可以用参数方程形式表示:x= x1+ u·(x2-x1)= x1+ u·Δx,y= y1+ u·(y2-y1)= y1+ u·Δy式中,Δx=x2-x1,Δy=y2-y1,参数u在0~1之间取值,P(x,y)代表了该线段上的一个点,其值由参数u确定,由公式可知,当u=0时,该点为P1(x1,y1),当u=1时,该点为P2(x2,y2)。
如果点P(x,y)位于由坐标(xwmin,ywmin)和(xwmax,ywmax)所确定的窗口内,那么下式成立:xwmin≤x1+ u·Δx≤xwmax,ywmin≤y1+ u·Δy≤ywmax这四个不等式可以表示为:u·pk ≤qk ,k=1,2,3,4其中,p、q定义为p1=-Δx,q1=x1-xwminp2= Δx,q2=xwmax-x1p3=-Δy,q3=y1-ywminp4= Δy,q4=ywmax-y1可以知道:任何平行于窗口某边界的直线,其pk=0,k值对应于相应的边界(k=1,2,3,4对应于左、右、下、上边界)。
如果还满足qk<0,则线段完全在边界外,应舍弃该线段。
如果pk=0并且qk≥0,则线段平行于窗口某边界并在窗口内,见图中所示。
1、当pk<0时,线段从裁剪边界延长线的外部延伸到内部;2、当pk>0时,线段从裁剪边界延长线的内部延伸到外部;例如,当Δx≥0时,对于左边界p1<0(p1=-Δx),线段从左边界的外部到内部;对于右边界p2>0(p2=Δx),线段从右边界的内部到外部。
当Δy<0时,对于下边界p3>0(p3=-Δy),线段从下边界的内部到外部;对于上边界p4<0(p4=Δy),线段从上边界的外部到内部。
当pK≠0时,可以计算出参数u的值,它对应于无限延伸的直线与延伸的窗口边界k的交点,即:对于每条直线,可以计算出参数u1和u2,该值定义了位于窗口内的线段部分:1、u1的值由线段从外到内遇到的矩形边界所决定(pk<0),对这些边界计算rk=qk/pk,u1取0和各个r值之中的最大值。
2、u2的值由线段从内到外遇到的矩形边界所决定(pk>0),对这些边界计算rk=qk/pk,u2取0和各个r值之中的最小值。
3、如果u1>u2,则线段完全落在裁剪窗口之外,应当被舍弃;否则,被裁剪线段的端点可以由u1和u2计算出来。
2.4 Sutherland-Hodgman算法进行多边形裁剪2.4.1 Sutherland—Hodgman多边形裁剪算法思想该算法的基本思想是每次用窗口的一条边界及其延长线来裁剪多边形的各边。
多边形通常由它的顶点序列来表示,经过裁剪规则针对某条边界裁剪后,结果形成新的顶点序列,又留待下条边界进行裁剪,直到窗口的所有边界都裁剪完毕,算法形成最后的顶点序列,才是结果多边形(它可能构成一个或多个多边形)。
当多边形一个顶点Pi相对于窗口某条边界及其延长线进行剪裁时,不外乎下列四种情况(即裁剪规则):1、顶点Pi在内侧,前一顶点Pi-1也在内侧,则将Pi纳入新的顶点序列;2、顶点Pi在内侧,前一顶点Pi-1在外侧,则先求交点Q,再将Q、Pi依次纳入新的顶点序列;3、顶点Pi在外侧,前一顶点Pi-1在内侧,则先求交点Q,再将Q纳入新的顶点序列;4、顶点Pi与前一顶点Pi-1均在外侧,则顶点序列中不增加新的顶点。
2.4.2 点在边界内侧的判断方法为了判断点是否在边界内侧可用坐标比较法和更通用的向量叉积符号判别法。
1、坐标比较法将点的某个方向分量与边界进行比较。
例如,判断某点是否在下边界内侧,用条件判别式: if(p[i][1]>=ymin) 即可。
2、向量叉积法为简单计,测试点表示为P点。
假设窗口边界方向为顺时针,如图中所示,对于其中任一边界向量,从向量起点A向终点B看过去:如果被测试点P在该边界线右边(即内侧),AB×AP的方向与X-Y平面垂直并指向屏幕里面,即右手坐标系中Z轴的负方向。
反过来,如果P在该边界线的左边(即外侧),这时AB×AP的方向与X-Y平面垂直并指向屏幕外面,即右手坐标系中Z轴的正方向。