我們求出四參數(shù)到底有什么意義呢?
假如我們用C#寫一個畫圖的程序,比如在picturebox中畫一個某一邊是尖頭的矩形。我們知道,picturebox的坐標(biāo)系的原點在它的左上角,X軸是向指向右邊的,Y軸是指向下邊的。而測量坐標(biāo)系中,X是指向上邊的(北),Y是指向右邊的(東),原點在左下角,為了方便用戶設(shè)計圖形,我們就用測量的坐標(biāo)系來設(shè)計。
在船體坐標(biāo)系中,如下圖3(新坐標(biāo)系,用戶定義的坐標(biāo)系):
我們知道四參數(shù)后,就可以把測量坐標(biāo)系的幾個點轉(zhuǎn)換成picturebox坐標(biāo),然后畫出來。當(dāng)然也可以改變picturebox控件的坐標(biāo),但是這樣效率很低,也不容易理解,特別是圖形旋轉(zhuǎn)的話也很難弄。
原始坐標(biāo)系是: Xo-Yo 經(jīng)過尺度縮放,坐標(biāo)系旋轉(zhuǎn),然后再平移,變成了Xt-Yt坐標(biāo)系。如《控制測量》上的圖1:
圖1中,我們要注意的是:
1. X的方向是向右的,Y是向上的。
2. 旋轉(zhuǎn)角是以順時針方向為正的
這兩點非常重要。如果X是向上的,那么四參數(shù)將會不一樣;而如果旋轉(zhuǎn)角是逆時針方向為正的,四參數(shù)也不一樣。X有可能是向左或者向下的甚至是向任意方向的,所以關(guān)鍵是我們一定要能畫出圖形,并且推導(dǎo)出公式。
如《控制測量》書上的推導(dǎo)圖就很典型可以做為參考,如圖2:
這個圖的優(yōu)點就在于,它的源坐標(biāo)系旋轉(zhuǎn)后就成為水平和垂直的軸線,非常便于平移理解。
需要注意的是,圖2中,源坐標(biāo)系X向任意方向,Y軸的正方向和X軸的正方向逆時針旋轉(zhuǎn)90度的方向一致,定義旋轉(zhuǎn)角順時針方向為正時。其實應(yīng)該有4種情況,圖上是下面提到的情況C。
其中 為新坐標(biāo), 為兩個平移參數(shù),(1 m)為尺度,為旋轉(zhuǎn)角,為原坐標(biāo)。這就是下面提到的情況A。公式1也可以用在情況C。
令 ,
則四參數(shù)公式可以寫成:
(公式2)
為了求解四參數(shù),把所有已知的和未知的矩陣寫在一起,構(gòu)造出:
的形式,然后再利用 求解。
公式2經(jīng)過展開,變成下面的形式:
寫成矩陣的形式(公式3):
這樣我們就構(gòu)造成了 的形式,其中, , 為原坐標(biāo)系下某點的坐標(biāo), 分別為原坐標(biāo)系到新坐標(biāo)系的平移量, , ,其中(1 m)是尺度, 為旋轉(zhuǎn)角。
公式三就這樣變成了一個單純的矩陣運(yùn)算,2個點的話恰好能求出四參數(shù),無法計算殘差,如果大于等于3個點,就可以計算出殘差,這實際上用了最小二乘法。
現(xiàn)在,我們來根據(jù)圖1的實際情況假設(shè)幾個比較接近情況的四參數(shù):
假如原坐標(biāo)系上有5個點,P1(0, 15) P2(0, 5) P3(3, 0) P4(6, 5) P5(6, 15)
其中P1(0, 15)表示在原坐標(biāo)系下,點P1的X坐標(biāo)為0, Y坐標(biāo)為15。
現(xiàn)在,把原坐標(biāo)系(整個坐標(biāo)系:包括原點,X軸,Y軸)的X,Y軸都縮短為原來的1/2,然后把整個坐標(biāo)系逆時針旋轉(zhuǎn)30度,再把兩條坐標(biāo)軸或者說整個坐標(biāo)系向X軸的負(fù)方向移動(旋轉(zhuǎn)以后的X軸的正方向的反方向)4米(如果是負(fù)數(shù),那么應(yīng)該向旋轉(zhuǎn)后的X軸的正方向移動個單位);同理,向Y軸的負(fù)方向移動3米(如果是負(fù)數(shù)就向正方向),經(jīng)過這3個步驟,原坐標(biāo)系變成了新的坐標(biāo)系,原來的5個點,它們在新坐標(biāo)系下的坐標(biāo)分別是:
P1(-11.0, 28.981) P2(-1.0, 11.660) P3(9.196, 6.0) P4(9.392, 17.660) P5(-0.608, 34.981)
注意:P1 P2 P3 P4 P5 并不同原坐標(biāo)系一起旋轉(zhuǎn)!
我們來看使用四參數(shù)的計算過程:
double c = fourP.Scale * Math.Cos(fourP.Rotate);
double d = fourP.Scale * Math.Sin(fourP.Rotate);
公式4:
aPtfNew.X = fourP.Xdelta (c * aPtfOld.X - d * aPtfOld.Y);
aPtfNew.Y = fourP.Ydelta (d * aPtfOld.X c * aPtfOld.Y);
只有同意了這個公式才能討論下面的問題。
那么,我們求出四參數(shù)到底有什么意義呢?
假如我們用C#寫一個畫圖的程序,比如在picturebox中畫一個某一邊是尖頭的矩形。我們知道,picturebox的坐標(biāo)系的原點在它的左上角,X軸是向指向右邊的,Y軸是指向下邊的。而測量坐標(biāo)系中,X是指向上邊的(北),Y是指向右邊的(東),原點在左下角,為了方便用戶設(shè)計圖形,我們就用測量的坐標(biāo)系來設(shè)計。
在船體坐標(biāo)系中,如下圖3(新坐標(biāo)系,用戶定義的坐標(biāo)系):
如果我們把圖3中的船體坐標(biāo)系去掉,沿著船的矩形邊緣建立一個類似于C#中的Picturebox的坐標(biāo)系,那么在picturebox中各點坐標(biāo)如下,如圖4(源坐標(biāo)系,它恰好是下面提到的4種情況的情況A):
這個過程到底是什么轉(zhuǎn)換的呢?或許有些人一眼就看出了是picturebox坐標(biāo)系先逆時針轉(zhuǎn)90度,然后再下方移動15個單位就變成了船體的坐標(biāo)系。但是大多數(shù)人反應(yīng)畢竟沒有那么快,還是有點暈的。所以現(xiàn)在我們看看可否通過四參數(shù)的求解,而不用畫圖或者憑借空間想象力來探討坐標(biāo)系的變換:
我們利用其中的兩個點的兩套坐標(biāo)系,求出坐標(biāo)系的變換參數(shù):
P1(0, 15) P2(0, 5) 兩個點在源的坐標(biāo)系中的坐標(biāo)(picturebox坐標(biāo)系)
P1(0, 0) P2(10, 0) 兩個點在新的坐標(biāo)系中的坐標(biāo)(船體坐標(biāo)系/用戶坐標(biāo)系)
求得的四參數(shù)是:(源坐標(biāo)系的X向右,Y向下,逆時針旋轉(zhuǎn)Rotate為正)
X平移 = 15.0
Y平移 = 0.0
旋轉(zhuǎn)(度) = 90 (逆時針)
尺度 = 1.0
我們用剛才對四參數(shù)的解釋來理解(按次序):1.不縮放 2.逆時針旋轉(zhuǎn)90度 3.向此刻的坐標(biāo)系(僅是尺度變化和旋轉(zhuǎn)以后的形成的坐標(biāo)系)的X方向的反方向移動15個單位。
這里有一個誤區(qū),是很容易讓人混淆的地方。因為源坐標(biāo)系和以前定義的不一樣了,X,Y的方向分別是向右和向下的,逆時針旋轉(zhuǎn)為正的。
我通過作圖,得出的結(jié)論是存在4種情況:
情況A.
不管X是向哪個方向的(向上,向下,向左,向右或者任意方向),只要Y軸的正方向和X軸的正方向順時針旋轉(zhuǎn)90度的方向一致,而且定義旋轉(zhuǎn)角逆時針方向為正,那么用的公式也是公式1。測量上用得最多的情況是X向上,Y向右;也是實例中的picturebox的坐標(biāo)系的情況。
情況B.
X向任意方向,Y軸的正方向和X軸的正方向順時針旋轉(zhuǎn)90度的方向一致,定義旋轉(zhuǎn)角順時針方向為正(數(shù)學(xué)坐標(biāo)系用得比較多),那么公式是:
顯然,情況C的四參數(shù)計算和求解完全和情況A不同,需要重新推導(dǎo),如果直接用公式3來求四參數(shù)和公司4來計算點在新坐標(biāo)系下的xy,計算出來的結(jié)果和理解的肯定不一樣。
情況C.
X向任意方向,Y軸的正方向和X軸的正方向逆時針旋轉(zhuǎn)90度的方向一致,定義旋轉(zhuǎn)角順時針方向為正時,得出的也是公式1。如前面的圖2顯示,公式同情況A是:
情況A和情況C都可以用公式3來求四參數(shù),用公式4來計算點在新坐標(biāo)系下的XY坐標(biāo)。
情況D.
如果,X向任意方向,Y軸的正方向和X軸的正方向逆時針旋轉(zhuǎn)90度的方向一致,定義旋轉(zhuǎn)角逆時針方向為正,那么公式同情況B是:
顯然,情況D的四參數(shù)計算和求解完全和情況A不同,需要重新推導(dǎo),否則計算出來的結(jié)果和理解的肯定是錯的。
回到剛才討論的應(yīng)用的例子(船體坐標(biāo)系和picturebox的轉(zhuǎn)換)這和視覺上看起來是一樣的,比較容易理解。這就恰恰是四參數(shù)的用武之地。
而在C#的picturebox中,我們是如何利用四參數(shù)來為我們服務(wù)的呢?
我們的想法是:重新定義picturebox的坐標(biāo)系,讓它變成船體坐標(biāo)系,然后直接在picturebox上面畫出5個船體坐標(biāo)點的連線:P1(0, 0) P2(10, 0) P3(15, 3) P4(10, 6) P5(0, 6)
這其實有3個步驟(這要求我們把源坐標(biāo)系和新坐標(biāo)系顛倒過來看,就是說把picturebox坐標(biāo)系當(dāng)做源坐標(biāo)系,這樣四參數(shù)就反過來了。而當(dāng)源坐標(biāo)系的X向右,Y向下,逆時針旋轉(zhuǎn)時,四參數(shù)的計算公式和源坐標(biāo)X向):
1. 先在picShip的paint事件中利用ScaleTransform把比例尺調(diào)整成我們需要的坐標(biāo)范圍,它本來是用象素做單位的,寫入e.Graphics.ScaleTransform(picShip.Width / 6, picShip.Height / 15)
把它的水平軸范圍調(diào)整成[0,6],垂直的范圍調(diào)整成[0, 15]
2. e.Graphics.RotateTransform(-90.0F); // 此句運(yùn)行之后picShip的X坐標(biāo)向上了,Y向右了??梢晠^(qū)域的范圍是x[-6, 0] y[0, 15]
3. e.Graphics.TranslateTransform(-15, 0); // 把旋轉(zhuǎn)之后的坐標(biāo)系再向下移動15個單位
這些我花了將近一兩個星期的時間,始終不能理解,現(xiàn)在回頭過來探討1年前弄不清楚半知半解的東西——有點或然開朗的感覺。
這些都不太好理解,挺惡心,但是為了以后不再恐懼,我們不如多花點時間把它徹底弄清楚,增強(qiáng)我們的信心和實力。試驗分析如下:
假如picturebox的長為400象素,高為300象素。
1. ScaleTransform(10, 10)的作用是,把picturebox的水平軸X軸拉長10倍,垂直軸也拉長10倍。那么picturebox現(xiàn)在能顯示的范圍就變成了:水平[0, 40] 垂直[0, 30]。 而如果e.Graphics.ScaleTransform(0.1F, 0.1F)之后,picturebox可顯示的范圍放大了10倍將變成:水平[0, 4000] 垂直[0,3000]
// ScaleTransform的作用是對坐標(biāo)軸X軸和Y軸進(jìn)行縮放
// pic能表達(dá)的范圍縮小了10倍
e.Graphics.ScaleTransform(10, 10);
e.Graphics.DrawLine(Pens.Blue, new PointF(0, 0), new PointF(39, 29));
2.
// 作用把當(dāng)前的坐標(biāo)系改變,新坐標(biāo)系的原點在源坐標(biāo)系的[100, 10]位置
// 也就是說現(xiàn)在picturebox的左上角的坐標(biāo)是[-100, -10]
// pic現(xiàn)在能表達(dá)的范圍是: 水平[-100, 300] 垂直[-10, 290]
// 所以畫出的兩個點故意縮進(jìn)了一下,這樣就能看到整條線的面貌。
e.Graphics.TranslateTransform(100, 10);
e.Graphics.DrawLine(Pens.Blue, new PointF(-95, -5), new PointF(295, 285));
3.
// RotateTransform的作用是對坐標(biāo)系進(jìn)行順時針的旋轉(zhuǎn)
// 這個比較復(fù)雜,而且不好理解
// 假如是順時針旋轉(zhuǎn)30度后形成新的坐標(biāo)系,
// 那么當(dāng)前pic的右上角的點在新坐標(biāo)系下的坐標(biāo)是(346.4, -200)
// pic的左下角點在新坐標(biāo)系中的坐標(biāo)是[150, 259.8]
// pic的右下角點在新坐標(biāo)系中的坐標(biāo)是[496.4, 59.8]
e.Graphics.RotateTransform(30.0F);
// 連接到pic的右上角的點
e.Graphics.DrawLine(Pens.Blue, new PointF(5, 5), new PointF(340, -190));
// 連接到pic的左下角的點
e.Graphics.DrawLine(Pens.Blue, new PointF(5, 5), new PointF(155, 250));
// 連接到pic的右下角的點
e.Graphics.DrawLine(Pens.Blue, new PointF(5, 5), new PointF(485, 51));
最后,我們要注意的是:使用或者求解四參數(shù)之前,應(yīng)該弄明白源坐標(biāo)是如何定義的,X軸是向哪個方向,Y軸和X軸呈什么關(guān)系,旋轉(zhuǎn)角是逆時針轉(zhuǎn)為正還是正時針轉(zhuǎn)為正,得自己推導(dǎo)一下公式。如果情況A和情況C,就可以用上面的公式3求解四參數(shù),用公式4來計算xy,否則會出錯的。所以會推導(dǎo)公式才是最重要的,千萬不要亂用,亂猜,或者知之而不能言而亂言。
聯(lián)系客服