前言
在計算幾何、機器人運動規劃、圖像輪廓分析中,我們常常需要知道一個平面圖形的對稱性(包括旋轉對稱、軸對稱和鏡像對稱)。那麼給定一個平面簡單多邊形,是否存在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):