由使用者輸入系列對稱的點的解決方案

熊鐸發表於2015-09-25

需求

由使用者輸入一系列對稱的點,對稱軸未知。

需求分析

對稱的點包括對稱點和對稱軸上的點。可以先要求使用者(圖形化)輸入成對的對稱點,程式計算出對稱軸後,再由使用者輸入軸上的點,並將點修正到軸上。

實際上計算對稱軸的過程是對對稱點中垂線求平均。但是要注意的是,輸入點的誤差是一個恆定值,以真實點為中心,越遠概率越小。因此兩對稱點的連線的誤差跟連線長度負相關。

而對使用者輸入的點的修正,其實是計算點到直線的垂足座標,是一個簡單的的解析幾何問題。

解決方案

第一步,通過使用者輸入的對稱點解出對稱軸

演算法思路

計算出對稱軸的基本思路分為兩步,先通過輸入的對稱點的連線計算對稱軸的斜率;然後計算在這個斜率下使得對稱點中點距該線距離最小時的截距。

對稱軸斜率的計算

斜率的計算需要先計算對稱點的方向向量,再計算與該方向向量垂直的向量,即為對稱軸的方向向量。求解如下:

11

為了計算方便,確保方向向量為正值,令x = 1

22

正常情況下,這時候斜率就應該是-x'/y'。然而本例中有多個對稱點,需要用連線長度做權,對傾角求加權平均。注意,是傾角而非斜率做加權平均,所以我們要轉換為傾角:

tanα

33

值得注意的是,當y_1' = y_1 即 y' = 0 時,會出現0做除數的情況。

因為 arctanx的定義域為(-∞, +∞), 值域為(-π/2, π/2)

arctan-s.png

而傾角的有效範圍是[0,π),所以需要一次轉換。

3

因為∠β∠γ角度上相等,所以∠β要轉換成線的傾角,即∠γ的補角,因∠β為負數,只需要對計算出的傾角為負的值加上π即可。

(之所以要將傾角歸到[0,π),是因為要求平均角度。如果直接求∠α∠β平均角度的話,會得到。而我們想得到的是90°,所以必須要用∠γ的補角取平均。)

計算對稱軸的斜率k

44

對稱軸截距的計算

因為對於恆定的斜率,點到直線的距離和點在y方向上到直線的距離是成正比的,即a = k·b

結論3.png

因此要計算恆定斜率下,與若干點距離(a)最短的直線。和求若干點在y方向距離(b)最短的直線是等價的。

只需要假定截距為0,計算各個點的y值與直線上相應y值之差,再求平均值即為截距。

555

程式碼

很多計算是由numpy的矩陣計算完成的,因此程式碼比較簡單

程式碼中self.rawData['symmMark']是使用者輸入的對稱點的資料,資料結構為一個一維陣列, x 座標 y 座標依次排列。
A1(x1, y1) A'1(x'1, y'1)是第一對對稱點,A2(x2, y2) A'2(x'2, y'2)是第二對對稱點。其儲存在self.rawData['symmMark']中的形式為: [x1, y1, x'1, y'1, x2, y2, x'2, y'2]

第二步,將接下來使用者輸入的點投射到對稱軸上

設輸入點為C(x1, y1), 對稱軸為 y = a x + b

設垂直於對稱軸,通過點C的直線斜率為k 則有 k · a = -1

於是直線方程為: y - y1 = - 1/a (x - x1)

化為斜截式: y = -1/a x + x1/a + y1

與對稱軸方程聯立解得交點x座標為

6666

帶入對稱軸方程可得y座標

程式碼

結果展示

標記數字相同的圓圈為滑鼠點選輸入一對對稱點,綠色的線為計算出的對稱軸,橙色的點為滑鼠點選後修正到軸上之後的點。

結果.png

結果2.png

結果3.png

相關文章