前言
在计算几何、机器人运动规划、图像轮廓分析中,我们常常需要知道一个平面图形的对称性(包括旋转对称、轴对称和镜像对称)。那么给定一个平面简单多边形,是否存在O(n)的算法,找出其所有的对称轴和旋转对称角度?
答案是肯定的。下面我们一起来看看这一优雅高效的算法吧。
对称问题的巧妙转化
对于对称性求解,一个直接的方法就是逐个顶点依次尝试(对于轴对称,还要尝试边的中点),然后判断图形是否重合,但是这种做法时间复杂度,太过愚蠢。
其实上述逐点尝试比对的过程,有点像字符串匹配问题:在字符串A中寻找字符串S。
假设串B的长度为n,串A的长度为m,我们知道KMP算法可以在O(m+n)的时间复杂度内找到A中所有S的匹配位置。
我们将KMP算法推广一下,它可以用于任何信息串的匹配。只要修改相应的比较函数即可。
将多边形按照某种规则进行编码,得到模式串S,然后通过合理构造匹配串A,使用KMP算法在A中寻找S的匹配,即可求解得到S的对称性。利用KMP思想判断对称性的过程如下:
- 编码:将多边形按照某种规则进行编码,编码成信息串S;
- 构造匹配串:根据要判断旋转对称还是轴对称来构造不同的匹配信息串A
- 匹配:用KMP算法在A中寻找S的匹配位置
- 解码:找到对称轴/对称角度
下面对此进行详细说明。
旋转对称
旋转对称就是要求解一个图形的旋转对称角度:上图中,左图的对称角度是360/3=120度,右图是360/5=72度。
我们需要先将多边形的每一个顶点信息编码为二元组(Length, Angle),其中Length为边长、Angle为顶点的内角。
上图中,边长均为l,那么多边形编码为如下数组:
对于任意一个多边形,假设其编码为:
那么构造旋转对称的匹配串如下:
读者可以思考一下:为什么这么构造呢?这么构造,以下三点是成立的:
- 匹配位置对应旋转角度
- 收割匹配位置不为,则是旋转对称图形
- 旋转角度为:首个匹配位置(从1开始)*360/n,n是S的长度
构造出了模式串和匹配串,利用KMP算法寻找匹配即可得到旋转对称角度。
轴对称
轴对称判定需要找出所有的对称轴。上图中雪花有6条对称轴,而蝴蝶只有1条对称轴。
对于轴对称,每个顶点处的编码二元组与旋转对称一样。但是整个多边形的编码序列则有所不同,如下:
原因如下图:
匹配串A的编码序列基本不变:.
对于轴对称,其解码规则如下:
- 每个匹配位置对应一个对称轴
- 对称轴的另一个端点在“对面”
- 匹配位置每往后一个,对称轴经过的顶点后移半个(顶点移动半个是中点)
以下图为例,匹配位置为(0,1,2,3,4,5):