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

原文:二维图形的矩阵变换(二)——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界面上

时间: 2025-01-21 12:39:27

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

matlab中绘制二维图形

  matlab中有时为了看清方程,更加系统的了解方程,常常需要画图表达,那么为了绘制二维图形就需要了解matlab中常用的图形功能,下面介绍一下matlab中的二维图形功能. plot(x) ------------根据向量绘制二维曲线,例如: x=[1,2,3,5,4,3.5,2,0]; plot(x) plot(x,y)------------根据向量x,y绘制二维图形; 在matlab中利用plot(x,y)绘制y=2x^2(0<=x<=10)d的图形 x=linspace(0,10,

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

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

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

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

Android简明开发教程八:引路蜂二维图形绘制实例功能定义

有了前面对Android平台的介绍,基本上可以开始编写Android应用了,这里将以绘制二维图形为例,对Android开发的一般方 法做过介绍,其中涉及到自定义Application类,扩展View,Intent定义,发送消息,Data Binding(Adapter),和基本UI设计 .示例没有使用Android平台自带的二维图形API,而是调用了引路蜂二维图形库,引路蜂二维图形库Graphics 2D API实现了移 动平台上图形引擎,它能够以一种统一的方式处理各种基本图形(Shape),路

c语言中怎么把一个大小不确定的二维数组当作参数传入函数中

问题描述 c语言中怎么把一个大小不确定的二维数组当作参数传入函数中 c语言中怎么把一个大小不确定的二维数组当作参数传入函数中,取大神,取大神,取大神 解决方案 用VC++新建一个程序,默认生成的main函数定义如下 int mian(int argc, char* args[]) 这就是一个例子. 解决方案二: 一个表示长度的参数,一个指向二维数组的指针 解决方案三: fun(args[][],int rows,int cols) 解决方案四: void Func(int array[][10]

二维图形基本变换-c程序转换为java程序,最好用图形界面实现

问题描述 c程序转换为java程序,最好用图形界面实现 #include #include #define N 50 #define M 3.14159265 void erwei(); void sanwei(); void main() { int w; printf("请输入是几维图形变换:二维(2)或三维(3): "); scanf_s("%d", &w); if(w == 2) erwei(); else if(w == 3) sanwei();

C++实现二维图形的傅里叶变换_C 语言

本文实例讲述了C++实现二维图形的傅里叶变换的方法.有一定的借鉴价值.分享给大家供大家参考. 具体代码如下: // Fourier.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include "stdio.h" #include "math.h" #include <cv.h> #include <highg

解析二维码-解密二维码,获取二维码的情景值ID

问题描述 解密二维码,获取二维码的情景值ID 怎么没有看到有二维码的文章啊,然后我在获取二维码"情景id" String eventKey_scan = requestMap.get("EventKey"); 时获取到的是"0"

生成二维码 并且在二维码上面加logo 求助

问题描述 我需要做二维码,同时需要加logo在二维码的正中间,求助,各位给个意见,最好详细点了,多谢 解决方案 解决方案二:是生成二维码?http://www.codeproject.com/KB/cs/qrcode.aspx这个就是了.至于中间只要不复盖所需的数据都没问题的解决方案三:这种二维码太常见了,能自定义么??解决方案四:如果你想自定义就要自己编码,而且还要自己做解码软件.加logo只要叠加上去就行,盖掉内容也没事,二维码有容错性,纠错码会搞定被盖掉的部分.解决方案五:下载:解决方案六