地图开窗算法设计Word文档格式.docx
《地图开窗算法设计Word文档格式.docx》由会员分享,可在线阅读,更多相关《地图开窗算法设计Word文档格式.docx(27页珍藏版)》请在冰豆网上搜索。
然后以此新的顶点序列作为输入,相对第二条窗边界线进行裁剪,又得到一个更新的多边形顶点序列。
依次下去,相对于第三条、第四条边界线进行裁剪,最后输出的多边形顶点序列即为所求的裁剪好了的多边形。
如下图所示。
新的多边形顶点序列产生规则:
在用窗口一条边界及其延长线裁剪一个多边形时,该边界线把平面分成两个部分:
一部分称为边界内侧;
另一部分称为边界外侧。
如下图所示,依序考虑多边形的各条边。
假设当前处理的多边形的边为SP(箭头表示顺序关系,S为前一点,P为当前点),边SP与裁剪线的位置关系只有下面四种情况:
1、S在外侧,P在内侧。
则交点Q、当前点P保存到新多边形中。
2、S、P均在内侧,则当前点P保存到新多边形中。
3、S在内侧,P在外侧。
则交点Q保存到新多边形中。
4、S、P均在外侧。
则没有点被保存到新多边形中。
二、Sutherland-Hodgeman多边形裁剪算法实现:
1、已知:
多边形顶点数组p[][2],顶点个数n,
裁剪边界xmin(假设对左边界进行裁剪),
定义新多边形顶点数组q[][2]。
2、赋初值:
被裁多边形顶点数组的下标变量i=0;
新多边形顶点数组的下标变量j=-1;
前一个点S的x方向分量s[0]=p[n-1][0];
S的y方向分量s[1]=p[n-1][1];
前一个点S的内外标志,用变量flag来标识:
0表示在内侧,1表示在外侧。
if(s在边界内侧)/*例如对左边界:
s[0]>
=xmin*/
flag=0;
else
flag=1;
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];
/*将当前点pi放入新多边形*/
q[j][1]=p[i][1];
}
else
if(flag==0)/*前一个点在内侧吗?
flag=1;
/*从内到外的情况,将标志置1,作为下一次循环的前一点标志*/
/*将交点q放入新多边形*/
s[0]=p[i][0];
/*将当前点作为下次循环的前一点*/
s[1]=p[i][1];
}
四、点在边界内侧的判断方法:
为了判断pi点是否在边界内侧可用坐标比较法和更通用的向量叉积符号判别法。
1、坐标比较法
将点的某个方向分量与边界进行比较。
例如,判断某点是否在下边界内侧,用条件判别式:
if(p[i][1]>
=ymin)即可。
对其它边界也一样。
但不能写成通用公式。
2、向量叉积法
为简单计,测试点表示为P点。
假设窗口边界方向为顺时针,如图中所示,对于其中任一边界向量,从向量起点A向终点B看过去:
如果被测试点P在该边界线右边(即内侧),AB×
AP的方向与X-Y平面垂直并指向屏幕里面,即右手坐标系中Z轴的负方向。
反过来,如果P在该边界线的左边(即外侧),这时AB×
AP的方向与X-Y平面垂直并指向屏幕外面,即右手坐标系中Z轴的正方向。
设:
点P(x,y)、点A(xA,yA)、点B(xB,yB),
向量AB={(xB-xA),(yB-yA)},
向量AP={(x-xA),(y-yA)},
那么AB×
AP的方向可由下式的符号来确定:
V=(xB-xA)·
(y-yA)-(x-xA)·
(yB-yA)
(3-14)
因此,当V≤0时,P在边界线内侧;
而V>
0时,P在边界线外侧。
五、Sutherland-Hodgeman多边形裁剪算法特点:
Sutherland-Hodgeman多边形裁剪算法具有一般性,被裁剪多边形可以是任意凸多边形或凹多边形,裁剪窗口不局限于矩形,可以是任意凸多边形。
上面的算法是多边形相对窗口的一条边界进行裁剪的实现,对于窗口的每一条边界依次调用该算法程序,并将前一次裁剪的结果多边形作为下一次裁剪时的被裁剪多边形,即可得到完整的多边形裁剪程序。
一、Weiler-Atherton任意多边形裁剪算法描述:
在算法中,裁剪窗口、被裁剪多边形可以是任意多边形:
凸的、凹的(内角大于180o)、甚至是带有内环的(子区),见下图。
裁剪窗口和被裁剪多边形处于完全对等的地位,这里我们称:
1、被裁剪多边形为主多边形,记为A;
2、裁剪窗口为裁剪多边形,记为B。
主多边形A和裁剪多边形B的边界将整个二维平面分成了四个区域:
1、A∩B(交:
属于A且属于B);
2、A-B(差:
属于A不属于B);
3、B-A(差:
属于B不属于A);
4、A∪B(并:
属于A或属于B,取反;
即:
不属于A且不属于B)。
内裁剪即通常意义上的裁剪,取图元位于窗口之内的部分,结果为A∩B。
外裁剪取图元位于窗口之外的部分,结果为A-B。
观察右图不难发现裁剪结果区域的边界由被裁剪多边形的部分边界和裁剪窗口的部分边界两部分构成,并且在交点处边界发生交替,即由被裁剪多边形的边界转至裁剪窗口的边界,或者反之。
由于多边形构成一个封闭的区域,所以,如果被裁剪多边形和裁剪窗口有交点,则交点成
对出现。
这些交点分成两类:
一类称“入”点,即被裁剪多边形由此点进入裁剪窗口,如图中a、c、e;
一类称“出”点,即被裁剪多边形由此点离开裁剪窗口,如图中b、d、f。
二、Weiler-Atherton任意多边形裁剪算法思想:
假设被裁剪多边形和裁剪窗口的顶点序列都按顺时针方向排列。
当两个多边形相交时,交点必然成对出现,其中一个是从被裁剪多边形进入裁剪窗口的交点,称为“入点”,另一个是从被裁剪多边形离开裁剪窗口的交点,称为“出点”。
算法从被裁剪多边形的一个入点开始,碰到入点,沿着被裁剪多边形按顺时针方向搜集顶点序列;
而当遇到出点时,则沿着裁剪窗口按顺时针方向搜集顶点序列。
按上述规则,如此交替地沿着两个多边形的边线行进,直到回到起始点。
这时,收集到的全部顶点序列就是裁剪所得的一个多边形。
由于可能存在分裂的多边形,因此算法要考虑:
将搜集过的入点的入点记号删去,以免重复跟踪。
将所有的入点搜集完毕后算法结束。
三、Weiler-Atherton任意多边形裁剪算法步骤:
1、顺时针输入被裁剪多边形顶点序列Ⅰ放入数组1中。
2、顺时针输入裁剪窗口顶点序列Ⅱ放入数组2中。
3、求出被裁剪多边形和裁剪窗口相交的所有交点,并给每个交点打上“入”、“出”标记。
然后将交点按顺序插入序列Ⅰ得到新的顶点序列Ⅲ,并放入数组3中;
同样也将交点按顺序插入序列Ⅱ得到新的顶点序列Ⅳ,放入数组4中;
4、初始化输出数组Q,令数组Q为空。
接着从数组3中寻找“入”点。
如果“入”点没找到,程序结束。
5、如果找到“入”点,则将“入”点放入S中暂存。
6、将“入”点录入到输出数组Q中。
并从数组3中将该“入”点的“入”点标记删去。
7、沿数组3顺序取顶点:
如果顶点不是“出点”,则将顶点录入到输出数组Q中,流程转第7步。
否则,流程转第8步。
8、沿数组4顺序取顶点:
如果顶点不是“入点”,则将顶点录入到输出数组Q中,流程转第8步。
否则,流程转第9步。
9、如果顶点不等于起始点S,流程转第6步,继续跟踪数组3。
否则,将数组Q输出;
流程转第4步,寻找可能存在的分裂多边形。
算法在第4步:
满足“入”点没找到的条件时,算法结束。
算法的生成过程见下图所示。
四、Weiler-Atherton任意多边形裁剪算法实现:
1、算法在实现中,需要用到六个数组,分别用来存放:
被裁剪多边形、裁剪窗口、交点数组、插入交点后的被裁剪多边形、插入交点后的裁剪窗口、输出多边形。
2、由于交点具有“入”、“出”标记,因此凡与交点有关的数组都要采用结构数组类型:
structpoint
doublex;
doubley;
intflag;
}交点数组,数组3,数组4;
标记flag有三种状态:
0:
非交点;
1:
“入”点;
-1:
“出”点。
3、求交点时,利用被裁剪多边形的各边去对裁剪窗口的各边求交点:
for(被裁剪多边形的各边)
…;
for(裁剪窗口的各边)
求有效交点;
放入交点数组;
…;
4、交点的顺序插入,意味着要对交点数组排序后再分别插入到数组1、数组2的相应位置上。
5、所谓找“入”点、“出”点,必须根据flag找寻满足条件的顶点位置。
不光数组3中要找“入”点、“出”点,而且找到后还要转到数组4的相应顶点位置处。
对数组4的处理也同上。
这种处理在本算法中大量遇到。
六、Weiler-Atherton任意多边形裁剪算法特点:
1、裁剪窗口可以是矩形、任意凸多边形、任意凹多边形。
2、可实现被裁剪多边形相对裁剪窗口的内裁或外裁,即保留窗口内的图形或保留窗口外的图形,因此在三维消隐中可以用来处理物体表面间的相互遮挡关系。
3、裁剪思想新颖,方法简洁,裁剪一次完成,与裁剪窗口的边数无关。
七、Weiler-Atherton任意多边形裁剪算法小结:
前面介绍的是内裁算法,即保留裁剪窗口内的图形。
而外裁算法(保留裁剪窗口外的图形)同内裁算法差不多。
外裁算法与内裁算法不同的是:
1、从被裁剪多边形的一个“出点”开始,碰到出点,沿着被裁剪多边形按顺时针方向搜集顶点序列;
2、而当遇到“入点”时,则沿着裁剪窗口按逆时针方向搜集顶点序列。
按上述规则,如此交替地沿着两个多边形的边线行进,直到回到起始点为止。
将搜集过的“出点”的出点记号删去,以免重复跟踪。
将所有的出点搜集完毕后算法结束。
Weiler-Atherton算法的的设计思想很巧妙,裁剪是一次完成,不象Sutherland-Hodgman多边形裁剪算法,每次只对裁剪窗口的一条边界及其延长线进行裁剪,如裁剪窗口有n条边,则要调用n次S-H算法后才能最后得出裁剪结果。
但Weiler-Atherton算法的编程实现比Sutherland-Hodgman算法稍难,主要难在入、出点的查寻以及跨数组搜索上。
3.1点的裁剪
先看简单的点图元裁剪,它是线段裁剪以及后面的多边形裁剪的基础。
如果矩形窗口的左、右横坐标为:
xmin、xmax;
上、下纵坐标为:
ymin,ymax。
某点(x,y)在窗口内的充分必要条件是:
xmin≤x≤xmax
ymin≤y≤ymax
(3-1)
如果上面四个不等式中任何一个不满足,则点(x,y)位于窗口之外。
对于任意多边形窗口,需要根据第二章提到的多边形内点的判别准则进行判断。
2、多边形内点的判别准则
对多边形进行填充,关键是找出多边形内的象素。
在顺序给定多边形顶点坐标的情况下,如何判明一个象素点是处于多边形的内部还是外部呢?
从测试点引出一条伸向无穷远处的射线(假设是水平向右的射线),因为多边形是闭合的,那么:
若射线与多边形边界的交点个数为奇数时,则该点为内点(例:
图中测试点4引出的射线);
反之,交点个数为偶数时,则该点为外点。
(例:
测试点2引出的射线)。
多边形内点的判别准则和奇异点
3.2线段的裁剪
直线段的裁剪比点复杂,其裁剪方法又是多边形裁剪和三维图形裁剪的基础。
一、直线裁剪的基本思想
判断直线与窗口的位置关系:
1.确定直线是完全可见;
2.部分可见;
3.还是完全不可见。
对部分可见线段,求出它与窗口边界的交点,并将窗口内的线段输出。
二、裁剪线段和窗口的关系
假定窗口左下角坐标为(xmin,ymin),右上角坐标为(xmax,ymax),待裁剪线段和窗口的关系如图所示,这五种位置关系存在下面三种情况:
1、直线的两个端点均在窗口内,如图中AB线。
这时直线完全可见,可被简单接受。
2、直线的两个端点都在窗口外,并且位于窗口某一边界的同一外侧,如图中EF线。
则直线完全不可见,可被简单舍弃。
3、除此之外需要求交点,以确定直线在窗口某一边界内是否有可见部分,并裁掉外部线段,显示内部线段。
如CD、GH、IJ线。
为了提高裁剪效率,算法设计一般可从下面两方面作出考虑:
(1)快速判断情况1和情况2。
(2)在情况3中,设法减少求交的次数和每次求交时所需的计算量。
三、直线求交计算
当线段P1P2穿过某边界L时,交点P的计算如图中所示。
根据直线两点式方程:
(3-2)
整理后得通用交点公式:
(3-3)
1、与上边界的求交公式:
(3-4)
2、与下边界的求交公式:
(3-5)
3、与右边界的求交公式:
(3-6)
4、与左边界的求交公式:
(3-7)
四、直线裁剪的常用算法
1.Cohen-Sutherland算法
2.中点分割算法
3.梁友栋-Barsky裁剪算法
3.2.1Cohen-Sutherland算法
一、Cohen-Sutherland算法思想:
该算法也称为编码算法,首先对线段的两个端点按所在的区域进行分区编码,根据编码可以迅速地判明全部在窗口内的线段和全部在某边界外侧的线段。
只有不属于这两种情况的线段,才需要求出线段与窗口边界的交点,求出交点后,舍去窗外部分。
对剩余部分,把它作为新的线段看待,又从头开始考虑。
两遍循环之后,就能确定该线段是部分截留下来,还是全部舍弃。
二、Cohen-Sutherland算法步骤:
1、分区编码
延长裁剪边框将二维平面分成九个区域,每个区域各用一个四位二进制代码标识。
各区代码值如图中所示。
四位二进制代码的编码规则是:
(1)第一位置1:
区域在左边界外侧
(2)第二位置1:
区域在右边界外侧
(3)第三位置1:
区域在下边界外侧
(4)第四位置1:
区域在上边界外侧
裁剪窗口内(包括边界上)的区域,四位二进制代码均为0。
设线段的两个端点为P1(x1,y1)和P2(x2,y2),根据上述规则,可以求出P1和P2所在区域的分区代码C1和C2。
2、判别
根据C1和C2的具体值,可以有三种情况:
(1)C1=C2=0,表明两端点全在窗口内,因而整个线段也在窗内,应予保留。
(2)C1&
C2≠0(两端点代码按位作逻辑乘不为0),即C1和C2至少有某一位同时为1,表明两端点必定处于某一边界的同一外侧,因而整个线段全在窗外,应予舍弃。
(3)不属于上面两种情况,均需要求交点。
3、求交点
假设算法按照:
左、右、下、上边界的顺序进行求交处理,对每一个边界求完交点,并相关处理后,算法转向第2步,重新判断,如果需要接着进入下一边界的处理。
为了规范算法,令线段的端点P1为外端点,如果不是这样,就需要P1和P2交换端点。
当条件(C1&
0001≠0)成立时,表示端点P1位于窗口左边界外侧,按照前面介绍的求交公式,进行对左边界的求交运算。
依次类推,对位于右、下、上边界外侧的判别,应将条件式中的0001分别改为0010、0100、1000即可。
求出交点P后,用P1=P来舍去线段的窗外部分,并对P1重新编码得到C1,接下来算法转回第2步继续对其它边界进行判别。
三、Cohen-Sutherland算法分区编码程序:
Code(intx,inty,int*c)
{
*c=0;
if(y>
ymax) /*(xmin,ymin)和(xmax,ymax)为窗口左下角、右上角坐标。
*c=*c|0x08;
elseif(y<
ymin)
*c=*c|0x04;
if(x>
xmax)
*c=*c|0x02;
elseif(x<
xmin)
*c=*c|0x01;
}
3.2.2中点分割算法
Cohen-Sutherland直线裁剪算法,充分利用了直线段与裁剪边框的相关性,使裁剪速度大大提高,但在求交过程中仍采用了乘除运算,裁剪速度受到影响。
而中点分割法的特点,就在于它是用连续平分线段最终求得交点的方法代替用乘除法实现求交运算。
这样只需进行整数的加法和用运算器右移一位来实现除法运算,从而避免去做大量的乘除法。
一、中点分割算法思想:
1、中点公式
(3-8)
2、中点分割法求交点的规则
如图中所示,当线段P1P2求出中点P后,舍弃线段的哪部分,由下面两条规则决定:
中点分割法求交点规则
(1)如果P1与P同侧,移动P1点;
(即可能的交点只能出现在PP2段)
if((C1&
C)!
=0)P1=P;
(2)如果P1与P不同侧,移动P2点。
(即可能的交点只能出现在P1P段)
C)==0)P2=P;
二、中点分割算法实现:
1、将直线的两端点P1、P2编码得:
C1、C2;
(1)C1=C2=0,表明两端点全在窗口内,因而整个线段也在窗内,应予保留。
(1)令窗外端点为P1,如果窗外点不是P1,则P1和P2交换端点;
(2)保留窗内端点P2到暂存器里;
(3)对P1编码为C1;
(4)用中点公式求出中点
,并编码得C;
(5)按照中点算法的求交规则:
若P1和P同侧,移动P1点;
=0) P1=P;
否则,移动P2点。
else P2=P;
(6)流程转(3),直到P1和P2相差一个单位时:
令交点为P2,取出暂存器的端点赋给P1,然后转向流程1。
三、中点分割算法特点:
1、求交点的次数(n)与线段长度(L)有关,其关系为:
L=2n。
例如:
线段长度为256,则求交点的次数为8。
2、中点分割法求出的交点是边界上的有效交点,而不是边界及其延长线上的交点。
(而Cohen-Sutherland直线裁剪算法求出的则是边界上或者边界的延长线上的交点。
)
3.2.3梁友栋-Barsky裁剪算法
Cyrus和Beck用参数化方法提出了比Cohen-Sutherland更有效的算法。
后来梁友栋和Barsky独立地提出了更快的参数化线段裁剪算法,也称为Liany-Barsky(LB)算法。
一、梁友栋-Barsky裁剪算法思想:
我们知道,一条两端点为P1(x1,y1)、P2(x2,y2)的线段可以用参数方程形式表示:
x=x1+u·
(x2-x1)