梁友栋-Barsky直线裁剪算法计算机图形学课程设计
OpenGL计算机图形学梁友栋裁剪算法实验代码及运行结果

《计算机图形学实验》报告任课教师:钱文华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();}实验结果:。
实验报告文档

done=TRUE;
}else if((code0.all&code1.all)!=0){
done=TRUE;
}else{
if(code0.all!=0){
x = x0; y = y0;
dx = x1 - x0; dy = y1 - y0;
d = dx - 2 * dy;
UpIncre=2*dx-2*dy;DownIncre=-2*dy;
while(x<=x1)
{
putpixel(x,y);
printf("x = %d , y = %d \n",x,y);
对剩余部分,把它作为新的线段看待,又从头开始考虑。两遍循环之后,就能确定该线段是部分截留下来,还是全部舍弃。
1、分区编码
延长裁剪边框将二维平面分成九个区域,每个区域各用一个四位二进制代码标识。各区代 码值如图中所示。
2、判别
根据C1和C2的具体值,可以有三种情况:
(1)C1=C2=0,表明两端点全在窗口内,因而整个线段也在窗内,应予保留。
(2)C1&C2≠0(两端点代码按位作逻辑乘不为0),即C1和C2至少有某一位同时为1,表明两端点必定处于某一边界的同一外侧,因而整个线段全在窗外,应予舍弃。
(3)不属于上面两种情况,均需要求交点。
3、求交点
假设算法按照:左、右、下、上边界的顺序进行求交处理,对每一个边界求完交点,并相关处理后,算法转向第2步,重新判断,如果需要接着进入下一边界的处理。
实验
类型
设计型
综合型
创新型
√
实
验
目
的
或
要
求
1.实验内容
计算机图形学裁剪

学院:理学院专业:信息与计算科学班级:
姓名
学号
指导教师
实验时间
4.
实验地点
计算机实验室
成绩
实验项目名称
裁剪
实验环境
VC++ 6.0
实验内容
(1)理解直线裁剪的原理(Cohen-Surtherland算法、梁友栋算法)
(2)利用VC+OpenGL实现直线的编码裁剪算法,在屏幕上用一个封闭矩形裁剪任意一条直线。
};
Rectangle rect;
int x0,y0,x1,y1;
int CompCode(int x,int y,Rectangle rect)
{
int code=0x00;
if(y<rect.ymin)
code=code|4;
if(y>rect.ymax)
code=code|8;
if(x>rect.xmax)
x0=450,y0=0,x1=0,y1=450;
printf("Press key'c'to Clip!\nPress key'r'to Rrstore!\n");
}
void Reshape(int w,int h)
{
glViewport(0,0,(GLsizei)w,(GLsizei)h);
glMatrixMode(GL_PROJECTION);
accept=0;
done=0;
int code0,code1,codeout;
code0=CompCode(x0,y0,rect);
code1=CompCode(x1,y1,rect);
计算机图形学——梁友栋-Barsky算法

计算机图形学——梁友栋-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⽐较去找最⼩的,这样就得到两个端点的参数值四、⼩结直线参数化直线段看成是有⽅向的把窗⼝的四条边分为⼊边和出边。
梁友栋-Barsky直线裁剪算法计算机图形学课程设计

河南理工大学万方科技学院课程设计报告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 总体目标和要求目标:以图形学算法为目标,深入研究。
计算机图形学——Liang-Barsky

算法思想
➢用upK≤qK(k=1,2,3,4)表示上式,则参数p、q定义为: p1=-∆x, q1=x0-xmin p2=∆x, q2=xmax-x0 p3=-∆y, q3=y0-ymin p4=∆y, q4=ymax-y0
算法思想
➢ u1----线段从外到内遇到的矩形边界决定(p<0) 计算rk=qk/pk u1=max{0,r}
➢ u2----线段从内到外遇到的矩形边界决定(p>0) 计算rk=qk/pk u2=min{r,1}
算法剪窗口外; 否则,由参数u1和u2计算出裁剪后的线段端点
例题演示
Step1: 写出参数方程,计算∆x和∆y。
x=x0+u∆x
y
y=y0+u∆y
∆x=5 ∆y=5
(0,0) F1(1,-2)
F2(6,3)
(8,4)
x
例题演示
Step2:计算pk、qk和rk的值,并确定u1、u2的值。
p1=-∆x=-5, q1=x0-xmin=1, r1=q1/p1=-1/5 p2=∆x=5, q2=xmax-x0=7, r2=q2/p2=7/5 p3=-∆y=-5, q3=y0-ymin=-2, r3=q3/p3=2/5 p4=∆y=5, q4=ymax-y0=6, r4=q4/p4=6/5
算法思想
➢ 根据pk的值判断线段的方向:
• pk=0 线段平行于裁剪边界 qk<0 线段完全位于边界外 qk≥0 线段位于平行边界内
• pk<0 线段从裁剪边界延长线的外到内 • pk>0 反之
计算机图形学第7章二维图形的裁剪(2_3)

7.3.1 Sutherland-Hodgeman多边形裁剪 3、对多边形的n条边进行处理,对当前点号的考虑为:0~n-1。
for(i=0;i<n;i++) { if(当前第i个顶点是在边界内侧) /*对左边界:p[i][0]>=xmin */ { if(flag!=0) /*前一个点在外侧吗?*/ { flag=0;/*从外到内的情况,将标志置0,作为下一次循环的前一点标志*/ j++; q[j][0]=求出交点的x方向分量; /*将交点q放入新多边形*/ q[j][1]=求出交点的y方向分量; } j++; q[j][0]= p[i][0]; /*将当前点p放入新多边形*/ q[j][1]= p[i][1]; } else { if(flag==0) /*前一个点在内侧吗?*/ { flag=1;/*从内到外的情况,将标志置1,作为下一次循环的前一点标志*/ j++; q[j][0]=求出交点的x方向分量; /*将交点q放入新多边形*/ q[j][1]=求出交点的y方向分量; } } s[0]=p[i][0]; /*将当前点作为下次循环的前一点*/ s[1]=p[i][1]; }
7.2.3 梁友栋-Barsky裁剪算法
XWmin X 1 Xu ' XWmax X 1 Xu ' YWmin Y1 Yu ' YWmax Y1 Yu '
XWmin X 1 Xu '
这四个不等式可以表示为:
XWmax X 1 Xu ' YWmin Y1 Yu ' YWmax Y1 Yu '
7.2.3 梁友栋-Barsky裁剪算法
裁剪III(计算机图形学)

2009-2010-2:CG:SCUEC
14
多边形裁剪-凸多边形的二维裁剪
多边形是由一组线段围成的封闭区域,线段裁剪是多边形 裁剪的基础。下图(b)是多边形的线段被裁剪后的结果,但 已不再是封闭的区域。正确的剪裁结果应是一个有边界的区 域,即裁剪后的结果仍是一个(或多个)多边形 ,这就要求
x t x R x 0 y t y0 yB y t y T y 0
令
QR x QB y QT y
则有 t Q i D i i L , R , B , T
2009-2010-2:CG:SCUEC
3
梁友栋-Barsky算法
凸多边形裁剪区域
3) N (P(t)-A) < 0,则P(t)在L外侧。
性质1表明,P(t)在凸多边形内的充要条件是,对于凸多边形边界上 任意一点A和该处内法向量N,都有N (P(t)-A) 0 。
2009-2010-2:CG:SCUEC
9
Cyrus-Beck算法
现假设多边形有k条边,在每条边界Li上取1个点 Ai ,该点处的内法 向量Ni(i=1,2,…,k),则可见线段的参数区间为下列不等式组的解
由
t Q i D i i L , R , B , T
i , j { L , R }i j
Dj Di (Q i 0 ) t (Q j 0 ) Q Qj i D Dj i (Q i 0 ) t (Q j 0 ) Qj Qi 0 t 1
i , j { B , T }i j
2009-2010-2:CG:SCUEC
4
梁友栋-Barsky算法
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
河南理工大学万方科技学院课程设计报告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轴的正方向。