本发明涉及一种多边形偏移算法,特别是涉及一种带岛的多边形曲线偏移算法。
背景技术:
在许多的关于2d偏移等距曲线的矢量算法的研究方法中,有三种方法被广泛应用:使用voronoi图、基于边-法向偏移和基于角平分线的偏移。其中使用voronoi图的方法的优势是可以避免自相交的发生。但是由于生成voronoi图的成本巨大,并且存在数值误差,在快速的算法中很少被使用。基于边-法向偏移在逻辑上是直观和简单的,以往的工作表明,可以使用边的起点和终点沿着边的法线方向进行一段距离的偏移来完成整个多边形的偏移。但是,这种方法的主要问题是需要解决偏移之后边的不连续和自相交问题的情况,并且处理它们是十分耗时的过程,导致算法的复杂性很高并容易出现数值错误。在基于角平分线偏移的方法下,由于角平分线上的点到角两边的距离相等,这样通过处理原始多边形中的角可以得到偏移之后多边形的顶点,按照顺序依次相连便可以得到偏移多边形。然后进行判定,去除局部无效边和全局无效边。但是,仅仅使用点偏移的方法在局部锐角角度极小的情况下因为不生成圆弧会发生局部的偏移量很大的情况,虽然有些算法使用截断进行了改进,但依然不是准确的结果。
技术实现要素:
本发明的目的在于针对现有技术的不足之处,提供一种既能降低算法复杂度又能保证结果准确的带岛的多边形曲线偏移算法。
本发明提供的这种带岛的多边形曲线偏移算法,该算法包括以下步骤:
步骤一、对各多边形的时针方向进行定向;
步骤二、对多边形偏移方向和时针方向进行约定;
步骤三、对于多边形上任一顶点pi进行凹点或凸点判定,如果为凹点采用法向-线偏移,如图为凸点则采用点偏移;
步骤四、判定局部无效边并去除;
步骤五、去除全局无效边。
在一个具体实施方式中,在步骤一中通过多边形在凸包上的极值点对多边形的时针方向进行定向。
进一步的,在步骤二中约定逆时针方向表示向多边形内部偏移、顺时针方向表示向多边形外部偏移。
在一个具体实施方式中,在步骤三中,pi与相邻顶点pi+1之间存在有向边ei,ei=pi-pi+1,
根据公式:
如果pconvex≤0,则称点p为多边形的凹点,
如果pconvex>0,则称点p为多边形的凸点,
凹点采用法向-线偏移的方式,凸点采用点偏移的方式。
进一步的,在步骤三中,
法向-线偏移的具体步骤为:对点凹pi通过公式
对凸点pi,偏移后的点qi为:
进一步的,步骤四中判定局部无效边并去除的具体步骤为:
1)定义方向无效的边满足:pipi-1·qiqi-1<0,定义距离无效的顶点qi满足dist(qi,p)≥d,其中p为原始多边形;
2)建立两个链表存放所有无效边和临时无效边;
3)遍历多边形中所有的未遍历过的边
3.1如果所遍历的边是非圆弧边并且满足方向无效,将无效原始边插入临时链表;
3.2判断边的前后顶点是否满足距离无效,如果距离无效则将无效顶点所邻接的边按照顺序插入临时链表,并且向前(后)继续遍历顶点。同时标记边已经遍历,直到遍历的顶点均为有效的顶点;
3.3将临时无效边链表插入存放所有无效边的链表中。
4)遍历所有无效边的链表,建立结构体数组存放前向边、后向边和无效边;
4.1遍历所有结构体中的无效边,使其延长线和不断和有效的前向边、后向边求交,并且向有效的顶点方向截取;
4.2如果在前(后)向边上有交点,则使用交点代替无效顶点,同时去除掉所有的无效边的顶点;
4.3如果在前(后)向边上没有交点,则使用前向边延长线和后向边求交以及后向边的反向延长线与前向边求交得到交点,进而得到新的多边形;
5)将无效边链表的结果依次代替原始多边形的链表,得到新的多边形。
进一步的,在步骤五中去除全局无效边时,
首先,利用扫描线算法,对圆弧进行预处理,采用x轴作为主方向,将圆弧通过主方向上的极值点分成两个圆弧,使扫描线经过时能够将圆弧和折线同等对待;
其次,对于单个多边形,确定所有偏移多边形的自相交顶点,步骤为:
1)定义vllist、vrlist、vlist分别存放左侧顶点、右侧顶点和自相交顶点,对于多边形中所有的边,左侧顶点插入vllist,右侧顶点插入vrlist;
2)对于vllist、vrlist分别按照顶点在x轴上的投影坐标排序;
3)建立局部边链表elist,顶点链表指针pl,pr,p;
4)pl、pr在链表中遍历,其中pl一定是pr的前一个不重复的投影;
4.1对于满足满足小于pl并且大于pr的顶点所在边和原始链表中所有边进行求交,将交点插入vlist中,并且记录相对应的边;
4.2将vllist、vrlist中不满足小于pl并且大于pr的顶点从局部边链表elist移除;
5)将原始多边形插入交点后重新序列化;
接着,重新定义多边形顶点的路由规则,规则为:a、对于原始多边形上的顶点方向不改变;b、对于自相交的顶点,跳转到相交的另一条边上的原始方向;根据该规则将偏移多边形划分成多个简单多边形;
然后,根据原始多边形与偏移后各简单多边形的相交情况将各简单多边形分为o-i多边形,o多边形和i多边形三类,
o-i多边形定义为:包含外多边形偏移边,与内部多边形偏移边有交,
o多边形:包含外多边形偏移边,与内部多边形偏移边无交,
i多边形:仅为内多边形偏移,并且只和内多边形偏移边有交;
最后将o-i多边形和o多边形保留逆时针方向的多边形,i多边形根据步骤四保留顺时针方向的多边形。
本发明在具体实施时首先对各多边形的时针方向进行定向;其次对多边形偏移方向和时针方向进行约定;接着对多边形上各顶点进行凹点或凸点的判定区分;然后对于判定为凹点的顶点采用法向-线偏移,对于判定为凸点的顶点采用点偏移;再判定局部无效边并去除;最后去除全局无效边即可得到偏移后的曲线。在整个过程中第一步检测曲线方向并且偏移所有的顶点,时间复杂度为o(n);判定去除局部无效边时,时间复杂度为o(nlogn);去除全局无效边具有o(n2/log(n))的时间复杂度,总而言之,整个偏移算法的时间复杂度可以被视为o(nlogn),降低了算法复杂度。
附图说明
图1为本发明一个优选实施例的算法过程框图。
图2为多边形顶点判定为凹点或凸点的示意图。
图3为顶点偏移路径示意图。
图4为多边形分类示意图。
图5为算例偏移示意图。
具体实施方式
如图1所示,本实施例提供的这种带岛的多边形曲线偏移算法,包括以下步骤:
(ⅰ)对各多边形的时针方向进行定向;
由于单个多边形的遍历方式一定会存在顺时针方向和逆时针方向两种,可通过多边形在凸包上的极值点对于复杂多边形(包含圆弧段)的时针方向进行定向。其中凸包上的极值点可以认为是凸包在某个方向(例如x轴方向)上的投影的值的最大或者最小的点。
(ⅱ)约定逆时针方向表示向多边形内部偏移、顺时针方向表示向多边形外部偏移,其偏移向量r可以取负数表示与时针方向表示的偏移方向相反。
(ⅲ)a、对于多边形上任一顶点pi进行凹点或凸点判定;
对于多边形上顶点pi与相邻顶点pi+1之间存在有向边ei,ei=pi-pi+1,
如果pconvex>0,则称点p为多边形的凸点(如图2(a)所示),
如果pconvex≤0,则称点p为多边形的凹点(如图2(b)、2(c)所示);
a1、对于多边形上判断为凸点的顶点,我们采用点偏移的方式得到偏移后的图形,如图3(b)所示。因为凸点所在的角小于180°,所以偏移之后并没有圆弧而是退化成一个点。由于点一定在角平分线上,所以偏移点到原始点的向量应当满足v=ni-1+ni,然后因为偏移点到原始偏移点的长度应该等于d·sin-1(φi/2)。所以qi可以表示为:
其中如果使用
a2、对于多边形上判断为凹点的顶点,我们可以通过方式(3)得到偏移后的两个控制点,如图3(a)所示。因为凹点所在的角为优角,那么偏移后的圆弧的圆心角一定是小于180°的。因此通过这两个点,截取以偏移的顶点为圆心,r为半径的的圆所得到的劣弧就是凹点的准确的偏移曲线。
(ⅳ)、判定局部无效边并去除;
定义方向无效的边为满足pipi-1·qiqi-1<0的边(因为圆弧一定是等距的并且方向是正确的,所以圆弧所在边一定是方向有效的)。并且定义距离无效的顶点qi为dist(qi,p)≥d,其中p为原始多边形,但是实际上并不需要偏移后的点与原始多边形所有边求交,只需要考虑到局部的情况,所以判断顶点是否距离无效的可以仅仅与一部分局部的方向无效边求距离。距离无效边被定义为两个顶点均是局部距离无效的点。因而我们算法的思路是首先找到方向无效的边然后通过向前和向后的迭代判断顶点的有效性,直到寻找到距离有效的顶点即有效边,即算法1。其伪代码如下:
算法1解释成具体步骤为:
①定义方向无效的边满足:pipi-1·qiqi-1<0,定义距离无效的顶点qi满足dist(qi,p)≥d,其中p为原始多边形;
②建立两个链表存放所有无效边和临时无效边;
③遍历多边形中所有的未遍历过的边
④如果所遍历的边是非圆弧边并且满足方向无效,将无效原始边插入临时链表;
⑤判断边的前后顶点是否满足距离无效,如果距离无效则将无效顶点所邻接的边按照顺序插入临时链表,并且向前(后)继续遍历顶点。同时标记边已经遍历,直到遍历的顶点均为有效的顶点;
⑥将临时无效边链表插入存放所有无效边的链表中。
⑦遍历所有无效边的链表,建立结构体数组存放前向边、后向边和无效边;
⑧遍历所有结构体中的无效边,使其延长线和不断和有效的前向边、后向边求交,并且向有效的顶点方向截取;
⑨如果在前(后)向边上有交点,则使用交点代替无效顶点,同时去除掉所有的无效边的顶点;
⑩如果在前(后)向边上没有交点,则使用前向边延长线和后向边求交以及后向边的反向延长线与前向边求交得到交点,进而得到新的多边形;
在算法复杂度上,对于一个拥有n个顶点的多边形,计算所有偏移后的顶点到原始多边形的距离,直接计算算法复杂度是o(n3),即使通过边的连续性优化也会有o(n2·log(n))。但是我们算法所得到的结果算法复杂度只有o(n2),如果经过边的连续性优化复杂度可以减少到o(nlogn),并且结果是准确有效的。
在去除局部无效边的过程中,方向有效边的顶点可能是距离无效的,因此可以将所有的情况合并成一个过程。首先,无效边的延长线和不断和有效的前向边、后向边求交并且截取,如果有交则使用交点并且去除掉所有的无效边的顶点。在没有交点的情况下,则使用前向边延长线和后向边求交以及后向边的反向延长线与前向边求交得到交点,进而得到新的多边形。
(ⅴ)、去除全局无效边;
第一步、进行自相交环的去除;
对于单个多边形而言,在去除掉局部无效边后需要进一步去除全局无效部分。一般来说全局无效边是一些偏移多边形上的自相交的环。所以我们首先需要算出所有偏移多边形的自相交顶点。在计算出所有自相交顶点时,我们采用了扫描线(sweepline)算法。扫描线算法能够用于简化计算的主要思想是如果两条线段在主方向上的投影没有重叠,那么这两条线段一定不会有交点。但是由于在上一章节中生成的偏移多边形中含有圆弧,因而传统的算法在如下的情况会出现不正确的结果。我们通过扫描线的特性,将会出现问题圆弧通过主方向上的极值点分成两个圆弧,这样在扫描线经过的时候就能够将圆弧和折线一样对待。
在进行了这样的预处理之后,圆弧可以看作是一段或者两段折线构成。类似于计算机图形学中多边形裁剪算法和多边形布尔运算的方法,我们采用x轴作为主方向,假使扫描线从左向右经过多边形,在某时刻扫描线穿过的边作为一个边的动态集合。在扫描线运动时如果有新的边穿过扫描线时,进行求交运算并且将新的边加入到边的集合。同样如果有边集中的边与扫描线不交,那么在边集中去除这条边。在扫描线从左到右穿过多边形后便能不重不漏的得到所有的交点,伪代码见算法2。
算法2解释成具体步骤为:
①定义vllist、vrlist、vlist分别存放左侧顶点、右侧顶点和自相交顶点,对于多边形中所有的边,左侧顶点插入vllist,右侧顶点插入vrlist;
②对于vllist、vrlist分别按照顶点在x轴上的投影坐标排序;
③建立局部边链表elist,顶点链表指针pl,pr,p;
④pl、pr在链表中遍历,其中pl一定是pr的前一个不重复的投影;
⑤对于满足满足小于pl并且大于pr的顶点所在边和原始链表中所有边进行求交,将交点插入vlist中,并且记录相对应的边;
⑥将vllist、vrlist中不满足小于pl并且大于pr的顶点从局部边链表elist移除;
⑦将原始多边形插入交点后重新序列化。
去除自相交的环之前我们需要重新定义多边形的自相交和裁剪方式。当然相对于多边形上的点而言,这个过程则仅仅是改变邻接关系、进行重新的路由。因此定义了两条关于顶点的路由规则如下:
①对于原始多边形上的顶点方向不改变;
②对于自相交的顶点,跳转到另一条边上的原始方向。
通过这两个规则我们可以将偏移多边形划分成多个简单多边形。然后对于每个多边形的有效性需要进行判断,即对含有岛的多边形进行裁剪。
第二步、对含有岛的多边形进行裁剪;
在计算出所有的交点并且进行重新连接后,在全局上可能会存在多个方向不一致的多个多边形。通过原始多边形和偏移后边的相交的情况,我们将这些多边形分成三类:
o-i多边形:包含外多边形偏移边,与内部多边形偏移边有交,如图4中的loop1、loop3和loop4;
o多边形:包含外多边形偏移边,与内部多边形偏移边无交,如图4中的loop2;
i多边形:仅为内多边形偏移,并且只和内多边形偏移边有交,如图4中的loop5。
对于o-i多边形和o多边形我们将保留逆时针方向的多边形,对于i多边形我们将通过算法1保留顺时针方向的多边形即得到偏移后的多边形。
从整个偏移过程来看,对于一个有n个边(包含内部多边形和外部多边形)的情形。第一步检测曲线方向并且偏移所有的顶点,时间复杂度是o(n)。第二步是去除局部无效边的情况,时间复杂度为o(nlogn)。第三部是删除全局无效边其中使用了修改扫描线的算法,具有o(n2/log(n))的时间复杂度。总而言之,偏移算法的时间复杂度可以被视为o(nlogn)。
表1为和2013年linz的含有岛的多边形偏移算法的时间和误差的比较。其中误差在偏移多边形进行上采样,然后计算到原始多边形距离后得到的。表1:偏移曲线算法比较