原文:二维图形的矩阵变换(二)——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 = , double centerY = )
{
_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 = , double centerY = )
{
_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 };
}
}

通过这个扩展函数,前面的变换可以简化如下:

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

另外,这个类也支持直接和Point相乘,用起来还是蛮方便的。

UI的矩阵变换

由于篇幅所限,本文只介绍了WPF矩阵变换的基础操作,下一篇文章中再介绍如何将矩阵变换应用到UI界面上

二维图形的矩阵变换(二)——WPF中的矩阵变换基础的更多相关文章

  1. 二维图形的矩阵变换(三)——在WPF中的应用矩阵变换

    原文:二维图形的矩阵变换(三)--在WPF中的应用矩阵变换 UIElement和RenderTransform 首先,我们来看看什么样的对象可以进行变换.在WPF中,用于呈现给用户的对象的基类为Vis ...

  2. 通过Matrix进行二维图形仿射变换

    Affine Transformation是一种二维坐标到二维坐标之间的线性变换,保持二维图形的"平直性"和"平行性".仿射变换可以通过一系列的原子变换的复合来 ...

  3. matlab绘制二维图形

    常用的二维图形命令: plot:绘制二维图形 loglog:用全对数坐标绘图 semilogx:用半对数坐标(X)绘图 semilogy:用半对数坐标(Y)绘图 fill:绘制二维多边填充图形 pol ...

  4. 3ds max学习笔记(十五)-- 二维图形的操作

    (二维图形的创建) 1,在命令面板的[新建],单击第二个按钮: 从中选择对象名称,在视图种单击拖动进行创建,特殊:线:摁[shift]限制水平,垂直方向: 2,二维对象参数: 在渲染中启用:显示二维线 ...

  5. VS2008集成QT的OpenGL开发(实现二维图形的旋转)

    主要是利用Qt中的定时器实现了二维图形的旋转功能: #ifndef QGLTEST_H #define QGLTEST_H #include <QGLWidget> #include &l ...

  6. C#生成二维码,把二维码图片放入Excel中

    /// <summary> /// 把图片保存到excel中 /// </summary> /// <param name="excelFilePath&quo ...

  7. 微信长按识别二维码,在 vue 项目中的实现

    微信长按识别二维码是 QQ 浏览器的内置功能,该功能的基础一定要使用 img 标签引入图片,其他方式的二维码无法识别. 在 vue 中使用 QrcodeVue 插件 demo1 在 template ...

  8. 钉钉登录二维码嵌套在vue页面中

    转自 https://www.csdn.net/tags/OtDacg3sMjQ2NTgtYmxvZwO0O0OO0O0O.html 钉钉登录二维码嵌套在vue页面中 2021-09-04 14:42 ...

  9. 在UniApp的H5项目中,生成二维码和扫描二维码的操作处理

    在我们基于UniApp的H5项目中,需要生成一些二维码进行展示,另外也需要让用户可以扫码进行一定的快捷操作,本篇随笔介绍一下二维码的生成处理和基于H5的扫码进行操作.二维码的生成,使用了JS文件wea ...

随机推荐

  1. 几个linux命令

    常用linux命令: 普通用户命令: 一.文件和目录查看类命令 1. ls (常用参数 -l 和-h) 蓝颜色:表示目录 绿颜色:表示可执行文件 红颜色:表示压缩文件 白颜色:表示普通文件 青色:表示 ...

  2. 关于C++对汉字拼音的处理——终结篇(补充)

    需要补充的有三个方面: 1.新华字典数据获取方法1: 点击这里 2.新华字典数据获取方法2: 点击这里 3.比较稳定的其它的汉字转拼音的方法: 点击这里 *注:由于内容较多3个部分分文3篇博客进行分别 ...

  3. ubuntu lua安装

    #解压 tar -xzvf lua5.2.2.tar.gz #进入lua5.2.2文件夹 cd lua5.2.2 #执行make sudo make linux #提示如下错误: #lua.c:67: ...

  4. jQuery中模拟用户操作

    有时为了节省不想手动操作网页,但又想看到用户操作时的效果,可以用到jQuery提供的trigger方法.见下图代码 在不点击按钮时仍然想弹出this.value 我们只需要在后面加上.trigger( ...

  5. Keil 4 与Proteus 7.8联调

    实验环境: windows 8.1 pro with Keil 4 and Proteus 7.8 both cracked. 步骤: 下载联调工具Vdmagdi,安装. keil下Option/De ...

  6. iOS应用数据存储的常用方式

    iOS应用 数据存储的常用方式 XML属性列表 plist Preference 偏好设置 NSKeyedArchiver 归档 Core Data SQLite3 应用沙盒: Layer:     ...

  7. Cassandra1.2文档学习(8)—— 数据管理

    数据参考:http://www.datastax.com/documentation/cassandra/1.2/webhelp/index.html#cassandra/dml/dml_manage ...

  8. POJ2255二叉树

    题目大意就是给出你一个二叉树的前序和中序,要你求后序. 思路:二叉树的排序就是根据根节点的位置来定义的.所以找到二叉树的根节点是最重要的,二叉树的左子树和右子树也可以看成是二叉树,以此递归: #inc ...

  9. php结合jquery异步上传图片(ajaxSubmit)

    php结合jquery异步上传图片(ajaxSubmit),以下为提交页面代码: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transi ...

  10. Python 中模块间全局变量的使用上的注意

    最近用Python写代码,需要用到模块间的全局变量. 网上四处搜索,发现普遍做法是把全局变量放到一个独立的模块中,使用时,导入此全局变量模块即可. 但是在实际使用过程中发现了些小问题:在使用如下代码导 ...