1、第4章 变换和裁剪,直线P0P1的参数方程,对于直线上一点(x,y),若它在窗口内则有,梁友栋-Barsky算法,2,2009-2010-2:CG:SCUEC,令,则有,由,梁友栋-Barsky算法,3,2009-2010-2:CG:SCUEC,梁友栋-Barsky算法,由,4,2009-2010-2:CG:SCUEC,设P0P1和两条始边的交点参数为t0,t0”,令 t0 = max(t0,t0”,0), 则t0就是P0P1和两条始边的交点与P0三点中最靠近P1的点的参数。 设P0P1和两条终边的交点参数为t1,t1”,令 t1 = min(t1,t1”,1), 则t1就是P0P1和两条终边
2、的交点与P1三点中最靠近P0的点的参数。 当t1t0时,参数tt0,t1的线段就是P0P1的可见部分 当t1t0时,整个线段为不可见。,梁友栋-Barsky算法,5,2009-2010-2:CG:SCUEC,初始化线段在边界内的端点参数为t0 = 0、t1 = 1。 计算出各个裁剪边界的q、d值。 当q = 0且d 0时,参数 t 用于更新 t1。 如果更新了 t0 或 t1 后,使t0 t1,则舍弃该线段。否则画出以t0和t1为参数的线段,梁友栋-Barsky算法的基本步骤,6,2009-2010-2:CG:SCUEC,梁友栋-Barsky算法,double t0 = 0, t1 = 1;
3、double xL,xR,yB,yT; bool visible; void Liang_Barsky(double x2, double y2) double dx,dy;visible = false;dx = x1-x0; dy = y1-y0;if (clipt(-dx, x0-xL)if (clipt(dx,xR-x0)if (clipt(-dy,y0-yB)if (clipt(dy,yT-y0) visible = true;if (visible)drawline(P0+(P1-P0)t0, P0+(P1-P0)t1); ,Boo clipt(double q, double d
4、) double t;if (q t1) return false;else if (t t0) t0 = t;else if (q 0) /属于终点边参数 t=q/d;if (t t0) return false;else if (t t1) t1 = t;else if(d 0) return false;return true;,梁-Barsky算法演示例子,7,2009-2010-2:CG:SCUEC,Cyrus-Beck裁剪算法(参数化裁剪算法),考虑如图所示一个凸多边形区域R和一条线段P1P2,要求计算线段落在区域R中的部分。假定A是区域R边界L上一点。N是区域边界在A点的内法向量
5、。线段P1P2用参数方程表示:P(t) = (P2-P1)t +P1 0 t 1,P1,P2,A,N,R,图示,称直线上某点在某边界的内侧,如果该点和多边形区域内任一点都在该边界的同一侧。,Ref: M. Cyrus and J. Beck, Generalized two- and three-dimension clipping, Computers and Graphics, 3(1), 23-28, 1978.,8,2009-2010-2:CG:SCUEC,线段上的点和多边形的关系,P(t) = (P2-P1)t +P1 0 t 1 对于线段上任意一点P(t) ,P(t)和多边形边 界
6、L的关系有三种可能(此处 t 为一定值): 1) N (P(t)-A) 0,则P(t)在L内侧。 2) N (P(t)-A) = 0,则P(t)在L或其延长线上。 3) N (P(t)-A) 0,则P(t)在L外侧。,凸多边形裁剪区域,性质1,性质1表明,P(t)在凸多边形内的充要条件是,对于凸多边形边界上任意一点A和该处内法向量N,都有N (P(t)-A) 0 。,9,2009-2010-2:CG:SCUEC,现假设多边形有k条边,在每条边界Li上取1个点 Ai ,该点处的内法向量Ni(i=1,2,k),则可见线段的参数区间为下列不等式组的解,i=1,2,k,解的最小值ts和最大值te分别对
7、应于可见线段的端点。 把式P(t) = (P2-P1)t +P1代入上式,整理得,当 Ni (P2-P1) 0,由上式可求得t ti,当Ni (P2-P1) 0t ti,当Ni (P2-P1) 0,i=1,2,k,而 是线段与第i条边界(或延长线)的交点参数。,Cyrus-Beck算法,10,2009-2010-2:CG:SCUEC,解的几何意义:Ni (P2-P1)把ti分为两组:起点组和终点组。,终点组以Ni (P2-P1) 0为特征,表示在该处沿P1P2方向前进进入多边形内侧。,t ti,当Ni (P2-P1) 0t ti,当Ni (P2-P1) 0,i=1,2,k,设起点组中最大的t为
8、ts,终点组中最小的t为te,则ts = max0, maxti | Ni (P2-P1) 0 |te = min1, minti | Ni (P2-P1) 0 | 若 ts te,则ts和te是可见线段的端点参数,否则,整条线段在区域外部。,Cyrus-Beck算法,11,2009-2010-2:CG:SCUEC,若对于某个i,有Ni (P2-P1)=0 ,这时,Ni P2-P1 ,P1P2 与对应边平行,如图所示。这时有两种情况:线段在区域外侧或内侧。前一种情况对应于 Ni (P1-Ai) 0,线段与裁剪边平行的情况,可直接判断线段在多边形之外 后一种情况对应于Ni (P1-Ai) 0 则
9、不予考虑(因为没有交点),继续处理其他边界。,线段与多边形边平行,12,2009-2010-2:CG:SCUEC,Cyrus-Beck算法,double ts=0, te=1; int Cyrus_Beck(double A 2, double N 2, int k, double x2, double y2) int i,j;double t, dn, nw, Rs2, Re2;for(i=0; i 0) /属于起点组参数 if (t ts) ts = t; /求最大值else if (t te) te = t; /属于终点组,求最小值if (ts = te) /起点组的最大值小于等于终点组
10、的最小值 Rs0 = (x1-x0)*ts + x0; Rs1 = (y1-y0)*ts + y0; /计算起点坐标Re0 = (x1-x0)*te + x0; Re1 = (y1-y0)*te + y0; /计算终点坐标LineFunction(double Rs, double Re); return 1; return 0; /起点组的最大值大于终点组的最小值 ,13,2009-2010-2:CG:SCUEC,当凸多边形是矩形窗口,且矩形的边平行于坐标轴时,上述算法可简化为梁友栋-Barsky算法。由于每条边上法向量只有一个非零分量,所以任意一个向量与法向量求内积的运算很简单。,Cyru
11、s-Beck算法特例Liang-Barsky算法,14,2009-2010-2:CG:SCUEC,多边形是由一组线段围成的封闭区域,线段裁剪是多边形裁剪的基础。下图(b)是多边形的线段被裁剪后的结果,但已不再是封闭的区域。正确的剪裁结果应是一个有边界的区域,即裁剪后的结果仍是一个(或多个)多边形 ,这就要求在裁剪过程中应当保留多边形的区域性质。,(a) 裁剪前,多边形裁剪,多边形裁剪-凸多边形的二维裁剪,15,2009-2010-2:CG:SCUEC,Sutherland-Hodgman算法,Sutherland-Hodgman 算法,对多边形裁剪的SutherlandHodgman 算法是一
12、种十分简便的方法,只要对多边形用窗口的四条边依次裁剪四次(见下图)便可得到裁剪后的多边形。,算法的输入是以顶点序列表示的多边形,输出也是一个顶点序列,构成一个或多个多边形。 考虑以窗口的一条边及其延长线构成的裁剪线,该线把平面分成两部分:一部分包含窗口,称为可见侧;另一部分称为不可见侧。,16,2009-2010-2:CG:SCUEC,线段端点S、P与裁剪线的位置关系,对多边形的每一条边,假设它的两个端点分别为S和P。则它与裁剪直线的位置关系只有4种情况。,根据上述4种情况,线段SP经裁剪后可输出0至2个顶点。 情况1: S、P都在可见一侧,则输出P。 情况2: S、P都在不可见一侧,则不输出
13、顶点。 情况3: S在可见一侧,P在不可见一侧,则输出SP与裁剪线的交点点I。 情况4: S在不可见一侧,P在可见一侧,则输出SP与裁剪线的交点点I和P 。,17,2009-2010-2:CG:SCUEC,Sutherland-Hodgman算法框图,左算法框图仅描述用一条裁剪边对多边形裁剪,得到一个顶点序列,作为下一条裁剪边处理过程的输入。对于每条裁剪边,算法的框图是一样的,只是判断点在裁剪边哪一侧以及求线段SP与裁剪边的交点算法应做相应的改变。,18,2009-2010-2:CG:SCUEC,1从主函数得到待裁剪多边形的顶点序列P2、顶点序列数n、窗口一条边界参数xl (假如为矩形窗口的左
14、边界); 2赋初值:将顶点序列中的最后一个顶点赋给前一顶点S;设置初始标志flag:if (S在边界内侧)flag=0;else flag=1;设新的顶点序列数j=0;,考虑多边形相对于一条边界及其延长线进行裁剪的算法:,Sutherland-Hodgman算法步骤,19,2009-2010-2:CG:SCUEC,3、对多边形各顶点进行裁剪规则处理,结果放入新的多边形顶点序列Q2中:for(对第一个顶点直到最后一个顶点,逐一处理)if (Pi在边界内侧)if (flag!=0)flag=0;求交点并放入新的多边形顶点序列Qj中; j+;将当前顶点放入新的多边形顶点序列Qj中:Qj=Pi; j+
15、;elseif (flag=0)flag=1;求交点并放入新的多边形顶点序列Qj中; j+;将当前顶点赋给S:S=Pi;,Sutherland-Hodgman算法步骤,S-H算法演示例子,完整的S-H程序,20,2009-2010-2:CG:SCUEC,Sutherland-Hodgeman算法,对凸多边形应用本算法可以得到正确的结果,但是对凹多边形的裁剪将如图所示显示出一条多余的直线。这种情况在裁剪后的多边形有两个或者多个分离部分的时候出现。因为只有一个输出顶点表,所以表中最后一个顶点总是连着第一个顶点。 解决这个问题有多种方法,一是把凹多边形分割成若干个凸多边形,然后分别处理各个凸多边形。
16、二是修改本算法,沿着任何一个裁剪窗口边检查顶点表,正确的连接顶点对。三就是Weiler-Athenton算法。,21,2009-2010-2:CG:SCUEC,字符裁剪,串精度裁剪 字符精度裁剪 以及笔画象素精度:将笔划分解成直线段对窗口作裁剪 基于构成字符最小元素裁剪 见教材P82,22,2009-2010-2:CG:SCUEC,结 束,练习题,描述如何用一个圆形窗口裁剪一条直线。,24,2009-2010-2:CG:SCUEC,完整Sutherland-Hodgman算法,const int RIGHT = 1; const int BOTTOM = 2; const int LEFT =
17、 3; const int TOP = 4;clip_polygon(int xR, int xL, int yB, int yT, int n, int *x, int *y) int *x1, *y1, n1;clip_single_edge(xR, RIGHT, n, x, y, ,25,2009-2010-2:CG:SCUEC,clip_single_edge(int edge, const int TYPE, int nin, int *xin, int *yin, int *nout, int *xout, int *yout) int i, k;bool is_cross, is
18、_in;int x, y, x_intersect, y_intersect;x = xinnin-1; y = yinnin-1; k=0;for(i=0; inin-1; i+)test_intersect(edge, type, x, y, xini, yini, ,26,2009-2010-2:CG:SCUEC,switch(type)case RIGHT:if(x2edge)is_cross = true;else if(x1=edge)is_in = true;if(y1=edge)is_cross = true;break; /end of BOTTOM,test_interse
19、ct(int edge, const int type, int x1, int y1, int x2, int y2, int *xout, int *yout, bool *is_cross, bool *is_in) float m;is_cross = is_in = false;m = (y2-y1)/(x2-x1);,27,2009-2010-2:CG:SCUEC,case LEFT:if(x2=edge)is_in = true;if(x1=edge)is_cross = true;break; / end of LEFTcase TOP:if(y2edge)is_cross =
20、 true;else if(y1=edge)is_cross = true;default:break; / end of switch(type),28,2009-2010-2:CG:SCUEC,if(is_cross)if(type = RIGHT)|(type = Left)xout = edge; yout = y1 + m*(xout - x1);elseyout = edge; xout = x1 + (yout - y1)/m; ,完整Sutherland-Hodgman算法,29,2009-2010-2:CG:SCUEC,Weiler-Atherton任意多边形裁剪,Suthe
21、rland-Hodgeman算法解决了裁剪窗口为凸多边形窗口的问题,但一些应用需要涉及任意多边形窗口(含凹多边形窗口)的裁剪。Weiler-Atherton多边形裁剪算法正是满足这种要求的算法。,30,2009-2010-2:CG:SCUEC,1. WA任意多边形裁剪算法描述,在算法中,裁剪窗口、被裁剪多边形可以是任意多边形:凸的、凹的(内角大于180o)、甚至是带有内环的(子区),见下图。,裁剪窗口和被裁剪多边形处于完全对等的地位,这里我们称: 1、被裁剪多边形为主多边形,记为A; 2、裁剪窗口为裁剪多边形,记为B。 主多边形A和裁剪多边形B的边界将整个二维平面分成了四个区域: 1、A B(
22、交:属于A且属于B); 2、AB(差:属于A不属于B); 3、BA(差:属于B不属于A); 4、AB (并:属于A或属于B,取反;即:不属于A且不属于B)。,31,2009-2010-2:CG:SCUEC,内裁剪即通常意义上的裁剪,取图元位于窗口之内的部分,结果为AB。 外裁剪取图元位于窗口之外的部分,结果为AB。,观察右图不难发现裁剪结果区域的边界由被裁剪多边形的部分边界和裁剪窗口的部分边界两部分构成,并且在交点处边界发生交替,即由被裁剪多边形的边界转至裁剪窗口的边界,或者反之。由于多边形构成一个封闭的区域,所以,如果被裁剪多边形和裁剪窗口有交点,则交点成对出现。这些交点分成两类: 一类称入
23、点,即被裁剪多边形由此点进入裁剪窗口,如图中a、c、e; 一类称出点,即被裁剪多边形由此点离开裁剪窗口,如图中b、d、f。,1. WA任意多边形裁剪算法描述,32,2009-2010-2:CG:SCUEC,2. WA任意多边形裁剪算法思想,假设被裁剪多边形和裁剪窗口的顶点序列都按顺时针方向排列。当两个多边形相交时,交点必然成对出现,其中一个是从被裁剪多边形进入裁剪窗口的交点,称为“入点”,另一个是从被裁剪多边形离开裁剪窗口的交点,称为“出点”。 算法从被裁剪多边形的一个入点开始,碰到入点,沿着被裁剪多边形按顺时针方向搜集顶点序列;而当遇到出点时,则沿着裁剪窗口按顺时针方向搜集顶点序列。 按上述
24、规则,如此交替地沿着两个多边形的边线行进,直到回到起始点。这时,收集到的全部顶点序列就是裁剪所得的一个多边形。 由于可能存在分裂的多边形,因此算法要考虑:将搜集过的入点的入点记号删去,以免重复跟踪。将所有的入点搜集完毕后算法结束。,33,2009-2010-2:CG:SCUEC,3 WA任意多边形裁剪算法步骤,1、顺时针输入被裁剪多边形顶点序列放入数组1中。 2、顺时针输入裁剪窗口顶点序列放入数组2中。 3、求出被裁剪多边形和裁剪窗口相交的所有交点,并给每个交点打上“入”、“出”标记。然后将交点按顺序插入序列得到新的顶点序列,并放入数组3中;同样也将交点按顺序插入序列得到新的顶点序列,放入数组
25、4中; 4、初始化输出数组Q,令数组Q为空。接着从数组3中寻找“入”点。如果“入”点没找到,程序结束。 5、如果找到“入”点,则将“入”点放入S中暂存。 6、将“入”点录入到输出数组Q中。并从数组3中将该“入”点的“入”点标记删去。 7、沿数组3顺序取顶点:如果顶点不是“出点”,则将顶点录入到输出数组Q中,流程转第7步。否则,流程转第8步。 8、沿数组4顺序取顶点:如果顶点不是“入点”,则将顶点录入到输出数组Q中,流程转第8步。否则,流程转第9步。,34,2009-2010-2:CG:SCUEC,9、如果顶点不等于起始点S,流程转第6步,继续跟踪数组3。否则,将数组Q输出;流程转第4步,寻找可
26、能存在的分裂多边形。算法在第4步:满足“入”点没找到的条件时,算法结束。算法的生成过程见下图所示。,3 WA任意多边形裁剪算法步骤,35,2009-2010-2:CG:SCUEC,4 WA任意多边形裁剪算法特点,裁剪窗口可以是矩形、任意凸多边形、任意凹多边形。 可实现被裁剪多边形相对裁剪窗口的内裁或外裁,即保留窗口内的图形或保留窗口外的图形,因此在三维消隐中可以用来处理物体表面间的相互遮挡关系。 裁剪思想新颖,方法简洁,裁剪一次完成,与裁剪窗口的边数无关。,36,2009-2010-2:CG:SCUEC,5 WA任意多边形裁剪算法小结,前面介绍的是内裁算法,即保留裁剪窗口内的图形。而外裁算法(
27、保留裁剪窗口外的图形)同内裁算法差不多。外裁算法与内裁算法不同的是:1、从被裁剪多边形的一个“出点”开始,碰到出点,沿着被裁剪多边形按顺时针方向搜集顶点序列;2、而当遇到“入点”时,则沿着裁剪窗口按逆时针方向搜集顶点序列。按上述规则,如此交替地沿着两个多边形的边线行进,直到回到起始点为止。这时,收集到的全部顶点序列就是裁剪所得的一个多边形。由于可能存在分裂的多边形,因此算法要考虑:将搜集过的“出点”的出点记号删去,以免重复跟踪。将所有的出点搜集完毕后算法结束。Weiler-Atherton算法的的设计思想很巧妙,裁剪是一次完成,不象Sutherland-Hodgman多边形裁剪算法,每次只对裁剪窗口的一条边界及其延长线进行裁剪,如裁剪窗口有n条边,则要调用n次S-H算法后才能最后得出裁剪结果。但Weiler-Atherton算法的编程实现比Sutherland-Hodgman算法稍难,主要难在入、出点的查寻以及跨数组搜索上。,37,2009-2010-2:CG:SCUEC,