优雅高效的多边形对称性判定算法

前言

在计算几何、机器人运动规划、图像轮廓分析中,我们常常需要知道一个平面图形的对称性(包括旋转对称、轴对称和镜像对称)。那么给定一个平面简单多边形,是否存在O(n)的算法,找出其所有的对称轴和旋转对称角度?

答案是肯定的。下面我们一起来看看这一优雅高效的算法吧。

对称问题的巧妙转化

对于对称性求解,一个直接的方法就是逐个顶点依次尝试(对于轴对称,还要尝试边的中点),然后判断图形是否重合,但是这种做法时间复杂度O(n^2),太过愚蠢。

其实上述逐点尝试比对的过程,有点像字符串匹配问题:在字符串A中寻找字符串S。

假设串B的长度为n,串A的长度为m,我们知道KMP算法可以在O(m+n)的时间复杂度内找到A中所有S的匹配位置。

我们将KMP算法推广一下,它可以用于任何信息串的匹配。只要修改相应的比较函数即可。

将多边形按照某种规则进行编码,得到模式串S,然后通过合理构造匹配串A,使用KMP算法在A中寻找S的匹配,即可求解得到S的对称性。利用KMP思想判断对称性的过程如下:

  1. 编码:将多边形按照某种规则进行编码,编码成信息串S;
  2. 构造匹配串:根据要判断旋转对称还是轴对称来构造不同的匹配信息串A
  3. 匹配:用KMP算法在A中寻找S的匹配位置
  4. 解码:找到对称轴/对称角度

下面对此进行详细说明。

旋转对称

                                     

旋转对称就是要求解一个图形的旋转对称角度:上图中,左图的对称角度是360/3=120度,右图是360/5=72度。

我们需要先将多边形的每一个顶点信息编码为二元组(Length, Angle),其中Length为边长、Angle为顶点的内角。

上图中,边长均为l,那么多边形编码为如下数组:

                     [(l, \beta),(l, \alpha),(l, \beta),(l, \alpha), (l, \beta), (l, \alpha), (l, \beta),(l, \alpha)]

对于任意一个多边形,假设其编码为:S=[s_o,s_1,...,s_{n-1}]

那么构造旋转对称的匹配串如下:A=[s_1,...,s_{n-1},s_o,s_1,...,s_{n-1}]

读者可以思考一下:为什么这么构造呢?这么构造,以下三点是成立的:

  • 匹配位置对应旋转角度
  • 收割匹配位置不为s_0,则是旋转对称图形
  • 旋转角度为:首个匹配位置(从1开始)*360/n,n是S的长度

构造出了模式串和匹配串,利用KMP算法寻找匹配即可得到旋转对称角度。

 

轴对称

       

轴对称判定需要找出所有的对称轴。上图中雪花有6条对称轴,而蝴蝶只有1条对称轴。

对于轴对称,每个顶点处的编码二元组与旋转对称一样。但是整个多边形的编码序列则有所不同,如下:

                                                                        S=[s_{n-1},s_{n-2},...,s_0]

原因如下图:

轴对称后边长和夹角的顺序改变,所以要将编码序列倒序,且其中的S_{n-1}{P_{n-1}P_0的长度; P_1-P_0-P_{n-1}的夹角}。

匹配串A的编码序列基本不变:A=[s_0,s_1,...,s_{n-1},s_o,s_1,...,s_{n-1}].

对于轴对称,其解码规则如下:

  • 每个匹配位置对应一个对称轴
  • 对称轴的另一个端点在对面
  • 匹配位置每往后一个,对称轴经过的顶点后移半个(顶点移动半个是中点)

以下图为例,匹配位置为(012345):

 

红色数字表示顶点的编码顺序,而绿色数字表示解码出的对称轴。
 
算法原理清楚了,相信读者不难写出代码,这里不再赘述。如有需要可以私信本人。
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章