博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
二维图形的矩阵变换(二)——WPF中的矩阵变换基础
阅读量:5334 次
发布时间:2019-06-15

本文共 3958 字,大约阅读时间需要 13 分钟。

在前文中已经介绍过二维图像矩阵变换的一些基础知识,本文中主要介绍一下如何在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; }        }        ///         ///  获取一个恒等变换        ///         public static GeometryTransForm Identity        {            get { return new GeometryTransForm(); }        }        ///         /// 以指定点为中心旋转指定的角度。        ///         /// 要旋转的角度(单位为度)。        /// 要围绕其旋转的点的 x 坐标。        /// 要围绕其旋转的点的 y 坐标。        public GeometryTransForm Rotate(double angle, double centerX = 0, double centerY = 0)        {            _matrix.RotateAt(angle, centerX, centerY);            return this;        }        ///         /// 围绕指定的点按指定的量缩放        ///         /// 沿 x 轴的缩放量        /// 沿 y 轴的缩放量        /// 缩放操作中心点的 x 坐标        /// 缩放操作中心点的 y 坐标        public GeometryTransForm Scale(double scaleX, double scaleY, double centerX = 0, double centerY = 0)        {            _matrix.ScaleAt(scaleX, scaleY, centerX, centerY);            return this;        }        ///         /// 在 x 和 y 维中指定角度的扭曲。        ///         /// 用于扭曲此的 x 维角度        /// 用于扭曲此的 y 维角度        public GeometryTransForm Skew(double skewX, double skewY)        {            _matrix.Skew(skewX, skewY);            return this;        }        ///         /// 按指定偏移量的平移        ///         /// 沿 x 轴的偏移量        /// 沿 y 轴的偏移量        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;        }        ///         /// 反转变换        ///         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界面上

转载于:https://www.cnblogs.com/TianFang/p/3930235.html

你可能感兴趣的文章
Windwos中的线程同步
查看>>
删除重复记录
查看>>
LeetCode : Reverse Vowels of a String
查看>>
代码托管服务器-软工第一次翻转课堂
查看>>
ECharts树图节点过多时取消缩放,调整容器高度自适应内容变化
查看>>
本地启动项目后cookie跨域获取不到的处理方式
查看>>
Codeforces 806 D.Prishable Roads
查看>>
Linux 一些表达式和运算符
查看>>
Android中的六大布局
查看>>
ZZNUOJ-2157: 水滴来袭-【干扰阅读-卡模糊精度1e-8的问题】
查看>>
个人自定义的快捷键 - 记录
查看>>
IIS部署SSL,.crt .key 的证书,怎么部署到IIS,记录一下,以免忘记。
查看>>
MVC框架 Struts
查看>>
每日软件进度报告—12月5日
查看>>
ruby关于require路径
查看>>
android gridview和gallery的例子
查看>>
Leetcode Unique Word Abbreviation
查看>>
centos 双网卡双IP设置
查看>>
时间戳与日期的相互转换
查看>>
获取手机当前经纬度的方法
查看>>