二維圖形的矩陣變換(二)——WPF中的矩陣變換基礎


在前文二維圖形的矩陣變換(一)——基本概念中已經介紹過二維圖像矩陣變換的一些基礎知識,本文中主要介紹一下如何在WPF中進行矩陣變換。

 

Matrix結構

在WPF中,用Matrix結構(struct類型)表示二維變換矩陣,它是一個3*3的數組,結構如下,

    

由於第三列是常量0,0,1,因此並不作為公開屬性,可見的只有剩余六個屬性。

 

構造變換

雖然Matrix類公開了這六個屬性讓我們設置,但是靠直接設置這六個屬性來實現平移、旋轉等變換對於我們來說實在太困難了,因此又增加了如下許多函數來幫助我們實現這一過程,常見了有:

  • Rotate
  • RotateAt
  • Scale
  • ScaleAt
  • Skew
  • Translate

這些函數的效果是疊加的,例如,我們要先平移(10,20),然后繞原點旋轉30度,方式如下:

    Matrix matrix = Matrix.Identity;
    matrix.Translate(10, 20);
    matrix.Rotate(30);

其中Matrix.Identity矩陣的默認值,它是一個恆等矩陣(不進行任何變換,可以用於重置)。

 

反轉矩陣

關於反轉矩陣,Matrix類中提供了一個屬性和函數:

  • HasInverse 屬性    用於檢查該矩陣是否可以反轉。
  • Invert()    用於獲取反轉矩陣

反轉矩陣可以非常方便我們進行矩陣的逆運算,十分有用。

 

應用變換

在WPF中可以接受矩陣運算的基礎元素有Point和Vector,可以通過Transform函數進行矩陣變換:

    var transForm = Matrix.Identity;
    transForm.Scale(2, 3);

    var point = new Point(1, 1);
    var newPoint = transForm.Transform(point);

    Console.WriteLine(newPoint);            //
輸出(2,3)

在C#中還重載了"*"運算符,這樣更加直觀了:

    var newPoint = point * transForm;

另外,Transform函數還有一個可以接收數組的的版本,這個版本中並不生成新的對象,因此具有更高的效率。

 

復合變換

前文已經介紹過,矩陣是可以通過乘運算實現變換的疊加的,Matrix類中提供了Multiply函數進行兩個矩陣相乘,在C#中也可以使用"*"運算符來實現這一過程。

    Matrix scale = Matrix.Identity;
    scale.Scale(2, 2);

    Matrix transLate = Matrix.Identity;
    transLate.Translate(10, 20);

    var transForm = scale * transLate;

    Matrix transForm2 = Matrix.Identity;
    transForm2.Scale(2, 2);
    transForm2.Translate(10, 20);

    Contract.Assert(transForm == transForm2);

需要注意的是,矩陣並不滿足交換律,如:

    Contract.Assert((transLate * scale) != (scale * transLate));

 

擴展函數

在日常的使用過程中,我們的變換矩陣往往是通過一系列操作疊加起來的。可能是為了效率,WPF的變換函數返回值都是Void,疊加起來並不方便。這里我寫了幾個擴展函數簡化這一過程: 

    public class GeometryTransForm
    {
        Matrix _matrix;
        public Matrix Matrix
        {
            get { return _matrix; }
            private set { _matrix = value; }
        }

        /// <summary>
        ///  獲取一個恆等變換
        /// </summary>
        public static GeometryTransForm Identity
        {
            get { return new GeometryTransForm(); }
        }

        /// <summary>
        /// 以指定點為中心旋轉指定的角度。
        /// </summary>
        /// <param name="angle">要旋轉的角度(單位為度)。</param>
        /// <param name="centerX">要圍繞其旋轉的點的 x 坐標。</param>
        /// <param name="centerY">要圍繞其旋轉的點的 y 坐標。</param>
        public GeometryTransForm Rotate(double angle, double centerX = 0, double centerY = 0)
        {
            _matrix.RotateAt(angle, centerX, centerY);
            return this;
        }


        /// <summary>
        /// 圍繞指定的點按指定的量縮放
        /// </summary>
        /// <param name="scaleX">沿 x 軸的縮放量</param>
        /// <param name="scaleY">沿 y 軸的縮放量</param>
        /// <param name="centerX">縮放操作中心點的 x 坐標</param>
        /// <param name="centerY">縮放操作中心點的 y 坐標</param>
        public GeometryTransForm Scale(double scaleX, double scaleY, double centerX = 0, double centerY = 0)
        {
            _matrix.ScaleAt(scaleX, scaleY, centerX, centerY);

            return this;
        }

        /// <summary>
        /// 在 x 和 y 維中指定角度的扭曲。
        /// </summary>
        /// <param name="skewX">用於扭曲此的 x 維角度</param>
        /// <param name="skewY">用於扭曲此的 y 維角度</param>
        public GeometryTransForm Skew(double skewX, double skewY)
        {
            _matrix.Skew(skewX, skewY);
            return this;
        }


        /// <summary>
        /// 按指定偏移量的平移
        /// </summary>
        /// <param name="offsetX">沿 x 軸的偏移量</param>
        /// <param name="offsetY">沿 y 軸的偏移量</param>
        public GeometryTransForm Translate(double offsetX, double offsetY)
        {
            _matrix.Translate(offsetX, offsetY);
            return this;
        }


        public GeometryTransForm Transfrom(GeometryTransForm transform)
        {
            return Transfrom(transform.Matrix);
        }

        public GeometryTransForm Transfrom(Matrix transform)
        {
            _matrix = _matrix * transform;
            return this;
        }


        /// <summary>
        /// 反轉變換
        /// </summary>
        public GeometryTransForm Invert()
        {
            _matrix.Invert();
            return this;
        }

        public static Point operator *(Point point, GeometryTransForm transform)
        {
            return point * transform.Matrix;
        }


        //如果是struct就用不着這個了,每一次 = 都是Clone
        public GeometryTransForm Clone()
        {
            return new GeometryTransForm() { Matrix = this.Matrix };
        }
    }
View Code

通過這個擴展函數,前面的變換可以簡化如下:

    var transForm = GeometryTransForm.Identity.Scale(2, 2).Translate(10, 20);

另外,這個類也支持直接和Point相乘,用起來還是蠻方便的。

 

UI的矩陣變換

由於篇幅所限,本文只介紹了WPF矩陣變換的基礎操作,下一篇文章中再介紹如何將矩陣變換應用到UI界面上


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM