今天来系统的学习一下两种直线裁剪的算法。
首先先来介绍一下直线裁剪的基本原理:
下图所示的为直线与窗口边界之间可能出现的几种关系。
可以通过检查直线的两个端点是否在窗口之内确定如何对此直线裁剪。
裁剪前:
裁减后:
在上图中,如果一直线的两个端点均在窗口边界之内(如图1中P5到P6的直线),则此直线应保留。
如果一条直线的一个端点在窗口外(如P9)另一个点在窗口内(如P10),则应从直线与边界的交点(P9)处裁剪掉边界之外的线段。
如果直线的两个端点均在边界外,则可分为两种情况:一种情况是该直线全部在窗口之外;
另一种情况是直线穿过两个窗口边界。图中从P3到P4的直线属于前一种情况,应全部裁剪掉;
从P7到P8的直线属于后一种情况,应保留P7到P8的线段,其余部分均裁剪掉。
直线裁剪算法应首先确定哪些直线全部保留或全部裁剪,剩下的即为部分裁剪的直线。
对于部分裁剪的直线则首先要求出这些直线与窗口边界的交点,把从交点开始在边界外的部分裁剪掉。
一个复杂的画面中可能包含有几千条直线,为了提高算法效率,加快裁剪速度,应当采用计算量较小的算法求直线与窗口边界的交点。
下面来介绍一下Cohen-Sutherland直线裁剪算法。
Cohen-Sutherland算法的大意是:对于每条线段P1P2,分为3种情况处理。
①若直线的两个端点P1P2完全在窗口内,则显示该线段P1P2,简称“取”之。
②若直线的两个端点P1P2明显在窗口外,则丢弃该线段,简称“弃”之。
③若线段既不满足“取”的条件,也不满足“弃”的条件,则把线段分为两段。其中一段完全在窗口外,可弃之。然后对另一段重复上述处理。
1.区域码及其建立
Cohen-Sutherland直线裁剪算法的核心是把所有直线的端点均分配一个表示其相对位置的4位二进制代码。此代码称为区域码。
区域码按照端点与窗口边界的相对位置编码,即区域码的4位分别代表端点位于窗口的上、下、左、右。
区域码从右到左的各位所代表的坐标区如下所示:
位 4 3 2 1
坐标区 上 下 右 左
上述各位中某位为1,则表示点位于此坐标区。
窗口周围各坐标区的区域码如下图所示。
由上图可见,位于窗中内的点,其区域码应为0000,
位于窗口左下方的点,其区域码应为0101,其余类推。
区域码各位的值可以通过对端点坐标(x,y)与窗口边界的比较求得。
如果x<xwmin,则区域码的第一位为1,其余各位的确定与此相似。
现在的计算机语言都可以进行位操作,因此,可以通过以下步骤建立区域码:
①计算出端点坐标与窗口边界的差。
②按计算出的各个差的符号把区域码的相应位置为0或1,即
区域码的第一位置为(x-xwmin)的符号位;
区域码的第二位置为(xwmin-x)的符号位;
区域码的第三位置为(y-ywmin)的符号位;
区域码的第四位置为(ywmin-y)的符号位。
2.区域码裁剪算法
对所有直线的端点都建立了区域码之后,就可按区域码判断直线在窗口之内或窗口之外。这可分为如下几种情况:
①若一直线的两个端点的区域码均为0000则此直线在窗口边界之内,应子保留。
②若一直线的两个端点的区域码的同一位同时为1,则此直线全部在窗口边界之外,应子裁剪。
例如,若一直线的一个端点的区域码为1001,另一个端点的区域码为0101,则此两端点的区域码的第一位均为1,说明此两端点均在窗口边界之左,
因此,直线在窗口边界之外,应予裁剪。可用将直线两个端点的区域码进行“与”(&)操作的方法,判断直线是否在窗口之外,
若“与”操作的结果为0000则两端点的区域码任何位均不同时为1,此直线不一定被裁剪。
③以上两种情况之外的直线,有可能穿过窗口,也有可能不穿过窗口。
对这类直线可以进行如下处理:取窗口外的一个端点与窗口边界比较以确定可排除直线的哪一部分,
然后,把直线剩下的部分与其他边界比较,这样一直到直线全部被排除或确定直线的哪一部分在窗口之内为止。
可按“左、右、下、上”的次序建立检查直线端点与窗口边界关系的算法。
Liang(梁友栋)-Barsky算法又称为参数方程法。首先写出端点及之间连线的参数方程如下:
参数u可取0到1之间的值,坐标表示此范围内的u值定义的直线上的一个点。
当u=0时,(x,y)=(x1-y1),直线的另一端u=1时,(x,y)=(x2-y2)。
我们发现,如果直线上的某点处于(x,y)即(xmin,ymin)以及(xmax,ymax)所定义的窗口之内,则满足一下条件:
这四个不等式可以表示为:
其中,参数定义为:
按照直线与窗口边界的相对位置,可分为以下几种倩况。
①任何一条与窗口边界平行的直线,其Pk=0,此处k值表示取哪一个边界(k=1,2,3及4,分别相应于左、右、下及上边界)。
如果对某一k值,还满足qk<0,则此直线完全在边界外,可不进一步考虑;如果qk≥0,则此与边界平行的直线在边界内。
②如果qk≠0,则情况较复杂。此时,可把直线按从(x1,y1)到(x2,y2)连线方向作为正向,将此直线无限延伸,同时把各窗口边界也无限延伸。
然后分以下两种情况讨论:
a当qk<0时,则是由窗口外发出的一条直线的无限延伸线进入相应窗口边界的无限延伸线的内部。
b当qk>0时,情况相反。即直线的延伸线是由窗口边界延伸线的内部到外部。
以图3中的直线L1为例,说明以上两种情况。表1.1给出的L1延伸线相对于4个边界延伸线的方向及qk取值。
当qk≠0时,可以用下式计算出一参数u,此u值应于直线延伸线与窗口边界k的延伸线的交点:
对于每条直线,可计算出一对u值(u1及u2),由此两参数可判断直线是如何裁剪的。
其中,u1的值可由从窗口边界外发出进人窗口边界之内的直线(pk<0)所涉及的窗口边界确定。
对于这些窗口边界,可计算出各自的r值:
取各rk中最大值即为回u1,u2可由自窗口边界内发出至窗口边界外的直线(Pk>0)所涉及的窗口边界确定,
同样可计算出这些窗口边界的rk值,取各rk中的最小值即为u2。
如果u1>u2,则此直线全部在窗口外而可排除:否则,此直线在窗口内,可由u1及u2计算出彼裁剪直线的端点。
图3中标出直线L1及L2相应于u1及u2的与边界的交点。
L1的u2>u1,则L1被裁剪,并可由u1及u2计算出裁剪点;
而L2的u1>u2,则此直线全部彼排除。
总结一下Liang-Barsky算法:
1. 算法的基本思想
以直线的参数方程为基础,对不同情况下的裁剪求得相应的参数值。
2. 算法的推导过程
情形一 pk=0
(1)p1=p2=0
若q1<0或q2<0,则可删除直线段
若q1>=0且q2>=0,则进一步判断
u=qk/pk(k=3,4)
令 u1=max(0,u|pk<0)
u2=min(1,u|pk>0)
若u1>u2,则可删除直线段
若u1<=u2,将u1,u2代入直线方程,得到直线段的两个可见端点。
(2)p3=p4=0
若q3<0或q4<0,则可删除直线段
若q3>=0且q4>=0,则进一步判断
u=qk/pk(k=1,2)
令 u1=max(0,u|pk<0)
u2=min(1,u|pk>0)
若u1>u2,则可删除直线段
若u1<=u2,将u1,u2代入直线方程,得到直线段的两个可见端点。
情形二 pk不为0
u=qk/pk(k=1,2,3,4)
令 u1=max(0,u|pk<0,u|pk<0)
u2=min(1,u|pk>0, u|pk>0)
若u1>u2,则可删除直线段
若u1<=u2,将u1,u2代入直线方程,得到直线段的两个可见端点。
3. 算法步骤
(1)输入直线段的两端点坐标以及窗口的四条边界坐标。
(2)若Δx=0,则p1=p2=0。进一步判断是否满足q1<0或q2<0,若满足,则该直线段不在窗口内,转(7)。否则,满足q1>0且q2>0,则进一步计算u1和u2。转(5)。
(3)若Δy=0,则p3=p4=0。进一步判断是否满足q3<0或q4<0,若满足,则该直线段不在窗口内,转(7)。否则,满足q1>0且q2>0,则进一步计算u1和u2。转(5)。
(4)若上述两条均不满足,则有pk≠0(k=1,2,3,4)。此时计算u1和u2。
(5)求得u1和u2后,进行判断:若u1>u2,则直线段在窗口外,转(7)。若u1<u2,利用直线的参数方程求得直线段在窗口内的两端点坐标。
(6)利用直线的扫描转换算法绘制在窗口内的直线段。
(7)算法结束。