向量旋轉,分別以三角變換,矩陣變換實現,C#源碼。

來源:互聯網
上載者:User

標籤:style   blog   http   ar   color   os   使用   sp   for   

最近用到了圖形旋轉,花了不少時間尋找材料,編碼測試。而且還用到了20年前老師教給的三角函數,還有大學裡面早已淡忘的矩陣運算。

呵呵,整理一下把,希望對大家有些協助。

 

 

功能: 已知向量OP,順時針旋轉α度,求P2點的座標。

根據三角函數,我們可以很自然的寫出:

P2.X = O.X + (int)(Math.Cos(alpha) * r) ;
P2.Y = O.Y + (int)(Math.Sin(alpha) * r) ;    //哦,代碼的顏色怎麼不變呢? 噢,因為我剛開始在部落格園寫部落格,所有不會使,呵呵,懶得理它了。

可惜,這樣寫是不對的。 原因嘛,一共有四個象限啊,當P1在不同的象限時候,結果是不同的。 論證過程。。。省掉N字。

嗯,先說個定理,可能大家會用到:

如上,半徑 r 知道了,旋轉角也知道了,P1P2的長度是多少? 

呵呵,獻醜了,手繪的。

這個定理,可以幫我們得到邊長,或者得到某邊對應角的大小。 在我的項目裡面用到了。

那麼上面的P2點,究竟是多少? 哦,我就省去複雜的推理過程了,直接出代碼:

 private Point GetNewPoint(double Rate, Point cirPos, Point startPos)        {            double Rage2 = Rate;// / 180 * Math.PI;            //B點繞A點轉R度得到C點座標,flag: 順時針1,反時針-1:B是轉的點,A是圓心            //C.X=(B.X-A.X)*COS(R*flag)-(B.Y-A.Y)*Sin(R*flag);            //C.Y= (B.Y-A.Y)*COS(R*flag)+(B.X-A.X)*sin(R*flag);            //轉的點座標-圓心座標            //圓心座標+計算座標=新位置的座標            double t1 = (startPos.X - cirPos.X) * Math.Cos(Rage2);            double t2 = (startPos.Y - cirPos.Y) * Math.Sin(Rage2);            int newx = (int)(t1 - t2);            int newy = (int)((startPos.Y - cirPos.Y) * Math.Cos(Rage2) + (startPos.X - cirPos.X) * Math.Sin(Rage2));            Point newpoint = new Point(cirPos.X + newx, cirPos.Y + newy);            return newpoint;        }

上面這個公式,不是個人推出來的,是教科書上的結論:

x0=|R|*cosA      y0=|R|*sinA                  x1 =|R|*cos(A +B)  y1=|R|*sin(A+B)所以將x1,y1展開,有:x1=|R|*(cosAcosB-sinAsinB)y1=|R|*(sinAcosB+cosAsinB) 把    cosA = x0/|R|   sinA = y0/|R| 代入上面的式子,得到 x1 = |R|*(x0*cosB/|R|-y0*sinB/|R|) y1 = |R|*(y0*cosB/|R|+x0*sinB/|R|)最終結果:x1 = x0 * cosB - y0 * sinBy1 = x0 * sinB + y0 * cosB 呵呵,三角函數方式,代碼與原理交代完畢。  下面就是矩陣了。通常在二維中,我們使用的是三階矩陣,為什麼呢? 因為二階不夠使啊,為什麼呢? 因為二階只能實現:縮放,旋轉,對稱變換,無法實現平移啊,為什麼呢? 因為,二階不是萬能神啊,為什麼呢?萬能神是不問為什麼的哈。。無語。 程式中矩陣的樣子是這樣的:我們敲一個C#中的矩陣看看:
namespace System.Drawing.Drawing2D{    //    // 摘要:    //     封裝表示幾何變換的 3 x 3 仿射矩陣。此類不能被繼承。    public sealed class Matrix : MarshalByRefObject, IDisposable    {        //        // 摘要:        //     將 System.Drawing.Drawing2D.Matrix 類的一個新執行個體初始化為單位矩陣。        public Matrix();               public Matrix(RectangleF rect, PointF[] plgpts);        //        // 摘要:        //     使用指定的元素初始化 System.Drawing.Drawing2D.Matrix 類的新執行個體。        //        // 參數:        //   m11:        //     新的 System.Drawing.Drawing2D.Matrix 的第一行和第一列中的值。        //        //   m12:        //     新的 System.Drawing.Drawing2D.Matrix 的第一行和第二列中的值。        //        //   m21:        //     新的 System.Drawing.Drawing2D.Matrix 的第二行和第一列中的值。        //        //   m22:        //     新的 System.Drawing.Drawing2D.Matrix 的第二行和第二列中的值。        //        //   dx:        //     新的 System.Drawing.Drawing2D.Matrix 的第三行和第一列中的值。        //        //   dy:        //     新的 System.Drawing.Drawing2D.Matrix 的第三行和第二列中的值。        public Matrix(float m11, float m12, float m21, float m22, float dx, float dy);

就是說,微軟的matrix,我們可以定義為 x1 y1,x2 y2,x3 y3。 而微軟會自動給我們補充第三列:0,0,1。這個查一下msdn就看到了。

哦,還是先上代碼把,看看我們用matrix如何?這種旋轉。

        private void MyTest()        {            Point pa = new Point(100, 100);            Point pb = new Point(200, 100);            DrawPoint(Brushes.Red, pa);            DrawPoint(Brushes.Black, pb);            DrawLine(Pens.Red, pa, pb);                        double ang = Math.PI * 30 / 180;            Matrix m = new Matrix();            m.Translate(-pa.X, -pa.Y);            m.Rotate(30, MatrixOrder.Append);            m.Translate(pa.X, pa.Y, MatrixOrder.Append);            Point[] ps = new Point[1];            ps[0] = pb;            m.TransformPoints(ps);            DrawPoint(Brushes.Blue, ps[0]);            Graphics g = Graphics.FromHwnd(this.Handle);            Rectangle rect = new Rectangle(pa, new Size(0, 0));            rect.Inflate(100, 100);                       g.DrawArc(Pens.Red, rect, 0, 30);            DrawPoint(Brushes.Green, ps[0]);            DrawLine(Pens.Red, pa, ps[0]);        }        private void DrawPoint(Brush b, Point p)        {            Rectangle rect = new Rectangle(p, new Size(5, 5));            Graphics g = Graphics.FromHwnd(this.Handle);            g.FillRectangle(b, rect);                   }        private void DrawLine(Pen pen, Point p1, Point p2)        {            Graphics g = Graphics.FromHwnd(this.Handle);            g.DrawLine(pen, p1, p2);        }

這段代碼就可以實現第一幅圖的效果了。

我們在百度上查資料,可以看到:縮放矩陣,旋轉矩陣,平移矩陣。 但是,如果進行一個點,繞另外一個點進行旋轉,那麼這個操作就是一個複合矩陣操作,是組合變換方式。

在實際應用過程中,我們在使用word、ppt、photoshop,經常會把圖片旋轉一下,可能是以左上方為圓心,旋轉20度,或者以圖片中心點為圓心旋轉。問題來了,我們用的圓心,不同於螢幕左上方的圓心哦,圖片的四個角點的座標,都是基於螢幕左上方圓心的座標。這個怎麼整?

是的,從O,到O1(哈哈,我上面畫了O撇,IME輸不上,幹嘛不畫個O1啊,砸到自己腳啦),我們是平移了一個位移。所以我們如果想旋轉P1後得到P2(呵呵,你懂的),

我們應當這樣做:第一步:將O1移到O。  第二步:將座標系旋轉。第三步:將O1移回原來位置。 這樣P2就完成了在座標系 X1O1Y1中,從P1點轉到P2點的任務。

第一步:平移變換:

第二步:旋轉變換:

第三步:平移變換:

注意,矩陣乘法是講究先後次序的,如同領導人的排名,不可亂來哦。 呼。。。小工告成,同志們吉祥。

 

向量旋轉,分別以三角變換,矩陣變換實現,C#源碼。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.