二维图形的矩阵变换(二)——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 };
        }
    }

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

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

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

UI的矩阵变换

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

时间: 2024-10-27 05:27:20

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

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

UIElement和RenderTransform 首先,我们来看看什么样的对象可以进行变换.在WPF中,用于呈现给用户的对象的基类为Visual类,但是Visual对象并不具有变换功能,具有变换功能的是它的子类UIElement.这个类也是非常底层的类了,几乎我们所有的常用控件都是继承自它,也就是说,基本上所有的UI对象都是可以应用变换的. 然后,我们在再来看看UIElement中变换种类.UIElement支持两种变换:RenderTransform和LayoutTransform,其中La

二维图形的矩阵变换(一)——基本概念

基本的二维变换可包括旋转.缩放.扭曲,和平移四种,              而这些几何运算则可以转换为一些基本的矩阵运算: 这几个变换都是线性的,但平移运算不是线性的,不能通过2*2矩阵运算完成.若要将点 (2, 1)在 x 方向将其平移 3 个单位,在 y 方向将其平移 4 个单位. 可通过先使用矩阵乘法再使用矩阵加法来完成此操作. 综合这几种基本运算,数学家们将其统一为一个3*3矩阵,存储形式如下: 由于表示仿射变换的矩阵的第三列总是(0,0,1),在存储矩阵的时候,大多只存成一个2*3的

图形学_二维图形的剪裁_Sutherland-Hodgeman_Cohen—Sutherland

一.Cohen-Sutherland剪裁算法 1.基本思想 对于每条线段P1P2分为三种情况处理: (1)若P1P2完全在窗口内,则显示该线段P1P2. (2)若P1P2明显在窗口外,则丢弃该线段. (3)若线段不满足(1)或(2)的条件,则在交点处把线段分为两段.其中一段完全在窗口外,可弃之.然后对另一段重复上述处理. 为快速判断,采用如下编码方法: 将窗口边线两边沿长,得到九个区域,每一个区域都用一个四位二进制数标识,直线的端点都按其所处区域赋予相应的区域码,用来标识出端点相对于裁剪矩形边界

二维图形旋转公式的推导

关于二维图形旋转可能在非常多计算机图形学相关的书籍上都会介绍,然而真正理解公式推导过程的却讲得不多. 那么怎样推导出二维图形绕某一点旋转的公式呢?我在这里就将其推导过程简要的说明一下. 事实上推导过程比較简单,首先我们来看一幅图,看看怎样推导出二维图形绕原点进行旋转的公式. 上图画的比較粗略,只是能说明问题就够了.如果旋转前的点位于P处.旋转之后的点位于P'处. 怎样求旋转之后的点P'坐标? 在图中.旋转之前P的方向角是a,旋转之后P'的方向角就变为a+b,这里b就是旋转的角度.所谓方向角是改点

二维图形变换

5.1二维图形变化 一.向量 是具有长度和方向的实体 二.特殊的线性组合 (1)仿射组合 (2)凸组合(对仿射组合加以更多的限制) 三.向量的点积和叉积 (1)点积 两个向量夹角的余弦值等于两个单位向量的点积 (2)叉积 两个向量的叉积是另一个三维向量,且与两个向量均正交 利用叉积求平面的法向量,三点可确定一个平面 5.2 图形坐标系 1.世界坐标系 是一个公共坐标系,是现实中物体或场景的统一参考系 2.建模坐标系 又称局部坐标系,每个物体有自己的局部中心和坐标系 3.观察坐标系 从观察者的角度

二维图形的几何变换【转】

转自:lab104_yifan http://blog.csdn.net/accelerator_/article/details/39253983 1.基本几何变换及变换矩阵 基本几何变换都是相对于坐标原点和坐标轴进行的几何变换,有平移.比例.旋转.反射和错切等. 1.1 平移变换 是指将p点沿直线路径从一个坐标位置移到另一个坐标位置的重定位过程.他是一种不产生变形而移动物体的刚体变换(rigid-body transformation),如下图所示. 图1-1 平移变换 推导: 求得平移变换

假设客车的座位数是9行4列,使用二维数组在控制台应用程序中实现简单的客车售票系统。

具体要求为: 使用一个二维数组记录客车售票系统中的所有座位号,并在每个座位号上都显示有票,然后用户输入一个坐标位置,按Enter键,即可将该座位号显示为已售. 首先我定义的输入格式为:1,2 个人认为主要知识点伪代码如下 1.字符串分割 char[] separator = { ',' }; splitstrings = str.Split(separator); 2.字符串前后去空 str.Trim() 3.转换类型,如果不是int类型则为false,可以处理异常情况. int columnN

即将开源,码晒客/疯狂创意二维码,个性二维码底层。

二维码: 二维码(Two-dimensional code),又称二维条码,它是用特定的几何图形按一定规律在平面(二维方向)上分布的黑白相间的图形,是所有信息数据的一把钥匙.在现代商业活动中,可实现的应用十分广泛,如:产品防伪/溯源.广告推送.网站链接.数据下载.商品交易.定位/导航.电子凭证.车辆管理.信息传递.名片交流.wifi共享等.如今智能手机扫一扫(简称313)功能的应用使得二维码更加普遍. 二维条码(二维码)是用某种特定的几何图形按一定规律在平面(二维方向)分布的黑白相间的图形记录数

Android实例-实现扫描二维码并生成二维码(XE8+小米5)

相关资料: 第三方资料太大没法写在博文上,请下载CSDN的程序包. 程序包下载: 过几天,刚上传的包,都没有办法显示. 注意事项: 如果只加了Lib,然没有改AndroidManifest.xml,App在呼叫BarCode时会ANR没反应.开始可能没有官方的classes.dex,但如果发现编译出错后,请再检查一下.TMessageManager须加System.Messaging单元. 使用DelphiXE7加入JavaLibrary后,呼叫Zxing相机1.新建一个DelphiXE工程,双