【学习笔记】Windows GDI绘图(四)矩阵Matrix详解

矩阵Matrix

基于矩阵在GDI绘图的重要性,所以想深入了学习矩阵的相关属性与方法。
先上个本文中所有的函数图例演示吧。
在这里插入图片描述
原型:

namespace System.Drawing.Drawing2D;public sealed unsafe class Matrix : MarshalByRefObject, IDisposable

Matrix类封装了一个表示几何变换的 3x3 仿射矩阵。
在这里插入图片描述

在GDI+中,可以将仿射变换存储在一个Matrix对象中。由于第三列是固定的(0,0,1),所以初始化一个Matrix时,只需要前两列的6个数字,如上图

Matrix myMatrix = new Matrix( 0, 1,-1, 0,3, 4);

注意,System.Drawing.Common 在.Net 6及之后的版本不支持在非Windows平台使用。

构造函数

Matrix()

原型:

public Matrix ();

初始一个单位矩阵(Identity Matrix)。

单位矩阵(Identity Matrix)
对角线上全是1:单位矩阵的主对角线上(从左上角到右下角)元素全是1。
非对角线上的元素全是0:除了主对角线上的元素,其他位置的元素全是0。

Matrix matrix=new Matrix();
Matrix:1	00	10	0

Matrix(Single, Single, Single, Single, Single, Single)

原型:

public Matrix (float m11, float m12, float m21, float m22, float dx, float dy);
参数说明
m11第1行、第1列
m12第1行、第2列
m21第2行、第1列
m22第2行、第2列
dx第3行、第1列
dy第3行、第2列
Matrix matrix = new Matrix(0, 1, -1, 0, 3, 4)
Matrix:0	1-1	03	4

Matrix(Rectangle,Point[])和Matrix(RectangleF,PointF[])

原型:

public Matrix (System.Drawing.Rectangle rect, System.Drawing.Point[] plgpts);
public Matrix (System.Drawing.RectangleF rect, System.Drawing.PointF[] plgpts);

初始化由指定矩形和点集(3个点)的仿射变换矩阵。

参数说明
rect待变换的矩形
plgpts三个Point构成的数组,
分别表示变换后平行四边形的左上角、右上角和左下角三个点
右下角的点由上角三个点自动计算生成
//原矩形
e.Graphics.DrawRectangle(Pens.Red, rect);
using(GraphicsPath path=new GraphicsPath())
{path.AddRectangle(rect);using(Matrix matrix=new Matrix(rect,plgpts)){Console.WriteLine($"Matrix:\r\n{ToString(matrix, 6)}");/*Matrix:0.800000	0.400000	0.333333	1.000000	-46.666670	-40.000000	*/path.Transform(matrix);//变换的平行四边形e.Graphics.DrawPath(Pens.Green, path);}
}
/// <summary>
/// 格式化输出矩阵
/// </summary>
/// <param name="m"></param>
/// <param name="decimalPlaces"></param>
/// <returns></returns>
private string ToString(Matrix m, int decimalPlaces = 0)
{var elements = m.Elements;return $"\t{ToString(elements[0], decimalPlaces)}\t{ToString(elements[1], decimalPlaces)}\r\n" +$"\t{ToString(elements[2], decimalPlaces)}\t{ToString(elements[3], decimalPlaces)}\r\n" +$"\t{ToString(elements[4], decimalPlaces)}\t{ToString(elements[5], decimalPlaces)}\r\n";
}/// <summary>
/// 格式化浮点型
/// </summary>
/// <param name="value">值</param>
/// <param name="decimalPlaces">小数点位数</param>
/// <returns></returns>
private string ToString(float value,int decimalPlaces=0)
{string format = $"F{decimalPlaces}";return value.ToString(format);
}

在这里插入图片描述

Matrix(Matrix3x2)

原型:

public Matrix (System.Numerics.Matrix3x2 matrix);

需要.NET高版本才支持,Matrix3x2的参数与Matrix(Single, Single, Single, Single, Single, Single)类似。

属性

Elements:矩阵元素值

原型:

public float[] Elements { get; }

获取表示该矩阵的浮点型数组,分别对应为m11, m12, m21, m22, dx, 和 dy 。

IsIdentity:是否为单位矩阵

原型:

public bool IsIdentity { get; }

获取当前矩阵是否为单位矩阵(主对角线为1,其他为0)

IsInvertible:是否可逆

原型:

public bool IsInvertible { get; }

获取当前矩阵是否可逆。

可逆矩阵
1、方阵:矩阵的行数和列数相等的矩阵,例如 2×2,3×3 等。
2、行列式:方阵可以计算行列式,这是一个标量值,可以提供关于矩阵性质的信息。
3、可逆性:如果一个方阵的行列式不为零,那么这个矩阵是可逆的,也就是说存在一个逆矩阵,使得原矩阵与其逆矩阵相乘的结果为单位矩阵。

MatrixElements

原型:

public System.Numerics.Matrix3x2 MatrixElements { get; set; }

高版本才支持,与Elements类似。

OffsetX水平偏移

原型:

public float OffsetX { get; }

获取矩阵的 x 平移值(dx或第3行,第1列元素值)。

OffsetY垂直偏移

原型:

public float OffsetY { get; }

获取矩阵的 y 平移值(dx或第3行,第2列元素值)。
在这里插入图片描述

方法

Clone()

原型:

public System.Drawing.Drawing2D.Matrix Clone ();
var matrixClone= matrix.Clone();

Equals(Object) 值是否相等

原型:

public override bool Equals (object? obj);

判断两个Matrix的Elements值是否相等,是的话,返回True,否则返回的False。

using (Matrix matrix = new Matrix(0, 1, -1, 0, 3, 4))
using (Matrix otherMatrix = new Matrix(0, 1, -1, 0, 3, 4))
{var matrixClone= matrix.Clone();int offset = 20;DrawString(e,$"IsEquals:{matrix.Equals(matrixClone)}",ref offset);//trueDrawString(e, $"IsEquals:{matrix.Equals(otherMatrix)}", ref offset);//truematrixClone.Translate(5, 6, MatrixOrder.Append);DrawMatrixElements(e, matrix, ref offset);DrawMatrixElements(e, matrixClone, ref offset);offset += 20;matrixClone.Dispose();
}           

Invert() 反转

原型:

public void Invert ();
if(matrix.IsInvertible)//是否可逆
{DrawMatrixElements(e, matrix, ref offset);matrix.Invert();//反转DrawMatrixElements(e, matrix, ref offset);
}

Multiply相乘

原型:

public void Multiply (System.Drawing.Drawing2D.Matrix matrix);//默认Prepend
public void Multiply (System.Drawing.Drawing2D.Matrix matrix, System.Drawing.Drawing2D.MatrixOrder order);

注意相乘的顺序

参数说明
orderAppend:原矩阵x新矩阵
Prepend:新矩阵x原矩阵(默认)
using (Matrix matrixA = new Matrix(1, 0, 0, 1, 30, 40))
using (Matrix matrixB = new Matrix(1, 0, 0, 1, 30, 40))
using (Matrix matrixRotate = new Matrix())
{//修改页面坐标e.Graphics.Transform = new Matrix(1, 0, 0, 1, 100, 100); var rect = new Rectangle(100, 0, 200, 120);//1、原矩形e.Graphics.DrawRectangle(Pens.Black, rect);//顺时针旋转30度matrixRotate.Rotate(30, MatrixOrder.Append);using (GraphicsPath  path = new GraphicsPath()){path.AddRectangle(rect);var pathClone = (GraphicsPath)path.Clone();pathClone.Transform(matrixA);//2A、平移(30,40)后的矩形e.Graphics.DrawPath(Pens.Red, pathClone);pathClone = (GraphicsPath)path.Clone();pathClone.Transform(matrixRotate);//3A、旋转30度e.Graphics.DrawPath(Pens.Blue, pathClone);//相乘顺序: matrixRotate * matrixA,先旋转,再平移matrixA.Multiply(matrixRotate);pathClone = (GraphicsPath)path.Clone();pathClone.Transform(matrixA);//3B、先旋转,再平移e.Graphics.DrawPath(Pens.Blue, pathClone);//相乘顺序:matrixB * matrixRotate,先平移,再旋转matrixB.Multiply(matrixRotate, MatrixOrder.Append);pathClone = (GraphicsPath)path.Clone();pathClone.Transform(matrixB);//2B、先平移,再旋转e.Graphics.DrawPath(Pens.Red, pathClone);}
}

Multiply

Reset()重置

原型:

public void Reset ();

将矩阵重置为一个单位矩阵。

Rotate绕原点旋转

原型:

public void Rotate (float angle);//默认Prepend
public void Rotate (float angle, System.Drawing.Drawing2D.MatrixOrder order);

绕原点(0,0)旋转(正数:顺时针,负数:逆时针)

using (Matrix matrixRotate = new Matrix())
{var rect = new Rectangle(100, 100, 200, 120);//1、原矩形e.Graphics.DrawRectangle(Pens.Black, rect);//顺时针旋转30度matrixRotate.Rotate(30, MatrixOrder.Append);e.Graphics.Transform = matrixRotate;e.Graphics.DrawRectangle(Pens.Red, rect);matrixRotate.Reset();//逆时针旋转30度matrixRotate.Rotate(-30, MatrixOrder.Append);e.Graphics.Transform = matrixRotate;e.Graphics.DrawRectangle(Pens.Blue, rect);
}

Rotate

RotateAt绕某点旋转

原型:

public void RotateAt (float angle, System.Drawing.PointF point);
public void RotateAt (float angle, System.Drawing.PointF point, System.Drawing.Drawing2D.MatrixOrder order);

绕指定的点旋转

using (Matrix matrixRotate = new Matrix())
{var rect = new Rectangle(100, 100, 200, 120);var center = new PointF((rect.Left + rect.Right) / 2f, (rect.Top + rect.Bottom) / 2f);//1、原矩形e.Graphics.DrawRectangle(Pens.Black, rect);//顺时针旋转45度matrixRotate.RotateAt(30, center, MatrixOrder.Append);e.Graphics.Transform = matrixRotate;e.Graphics.DrawRectangle(Pens.Red, rect);matrixRotate.Reset();//逆时针旋转45度matrixRotate.RotateAt(-30, center,MatrixOrder.Append);e.Graphics.Transform = matrixRotate;e.Graphics.DrawRectangle(Pens.Blue, rect);
}

在这里插入图片描述

Scale缩放

原型:

public void Scale (float scaleX, float scaleY);
public void Scale (float scaleX, float scaleY, System.Drawing.Drawing2D.MatrixOrder order);

对矩阵设置水平、垂直缩放。

using (Matrix matrixScale = new Matrix())
{var rect = new Rectangle(100, 100, 200, 120);//1、原矩形e.Graphics.DrawRectangle(Pens.Black, rect);//水平、垂直各缩小1倍matrixScale.Scale(0.5f, 0.5f, MatrixOrder.Append);e.Graphics.Transform = matrixScale;e.Graphics.DrawRectangle(Pens.Red, rect);matrixScale.Reset();//水平、垂直各放大1倍matrixScale.Scale(2, 2, MatrixOrder.Append);e.Graphics.Transform = matrixScale;e.Graphics.DrawRectangle(Pens.Blue, rect);
}

在这里插入图片描述

Shear剪切

原型:

public void Shear (float shearX, float shearY);
public void Shear (float shearX, float shearY, System.Drawing.Drawing2D.MatrixOrder order);

Shear变换(剪切变换)是一种几何变换,通常用于计算机图形学和图像处理领域。它通过在一个方向上平行移动各点的位置来改变图形的形状,而不改变其面积。这种变换在视觉上会使图形看起来像是被拉伸或压缩了。
在这里插入图片描述
仅当其中一个参数为0时,此方法中应用的变换才是纯剪切。
可用于绘制倾斜的文字。

 using (Matrix matrix = new Matrix())
{var rect = new Rectangle(100, 80, 200, 120);//1、原矩形e.Graphics.DrawRectangle(Pens.Black, rect);//垂直剪切(x'=x,y'=y+k*x)//原左上角(100,80)=>平行四边形左上角,x不变100,y=80+100*0.5=130,即:(100,130)//原右上角(300,80),x不变,y=80+300*0.5=230,即(300,230)matrix.Shear(0, 0.5f, MatrixOrder.Append);e.Graphics.Transform = matrix;e.Graphics.DrawRectangle(Pens.Red, rect);//绘制倾斜的文字 int offset = 20;DrawString(e, matrix.ToString(), ref offset);matrix.Reset();//水平剪切(x'=x+ky,y'=y)matrix.Shear(2, 0, MatrixOrder.Append);e.Graphics.Transform = matrix;e.Graphics.DrawRectangle(Pens.Blue, rect);
}

在这里插入图片描述

TransformPoints应用变换到点集中

原型:

public void TransformPoints (System.Drawing.Point[] pts);
public void TransformPoints (System.Drawing.PointF[] pts);
public void VectorTransformPoints (System.Drawing.Point[] pts);

将仿射变换应用到给点的Point数组中

//定义多个点构成一个矩形,(100,80,200,120);var points = new Point[]{new Point(100,80),new Point(300,80),new Point(300,200),new Point(100,200),new Point(100,80)};//1、原矩形e.Graphics.DrawLines(Pens.Black, points);using (var matrix = new Matrix()){matrix.Scale(0.5f, 2, MatrixOrder.Append);//变换矩形应用到点集上matrix.TransformPoints(points);e.Graphics.DrawLines(Pens.Red, points);}

在这里插入图片描述

TransformVectors应用变换到点集中(忽略平移)

原型:

public void TransformVectors (System.Drawing.Point[] pts);
public void TransformVectors (System.Drawing.PointF[] pts);

就矩阵(忽略平移,第三行)应用到点集上

using (Matrix matrixScale = new Matrix())
{//定义多个点构成一个矩形,(100,80,200,120);var points = new Point[]{new Point(100,80),new Point(300,80),new Point(300,200),new Point(100,200),new Point(100,80)};//1、原矩形e.Graphics.DrawLines(Pens.Black, points);using (var matrix = new Matrix()){matrix.Rotate(30, MatrixOrder.Append);matrix.Scale(0.5f,0.5f, MatrixOrder.Append);matrix.Translate(100, 50);//变换矩形应用到点集上var ptsClone = points.Clone() as Point[];matrix.TransformPoints(ptsClone);e.Graphics.DrawLines(Pens.Red, ptsClone);//忽略平移matrix.TransformVectors(points);e.Graphics.DrawLines(Pens.Blue, points);}
}

在这里插入图片描述

Translate平移

原型:

public void Translate (float offsetX, float offsetY);
public void Translate (float offsetX, float offsetY, System.Drawing.Drawing2D.MatrixOrder order);

平移矩阵

var rect = new Rectangle(100, 80, 200, 120);
//1、原矩形
e.Graphics.DrawRectangle(Pens.Black, rect);using(var matrix=new Matrix())
{//平称矩阵matrix.Translate(100, 120, MatrixOrder.Append);e.Graphics.Transform = matrix;e.Graphics.DrawRectangle(Pens.Red, rect);
}

在这里插入图片描述

https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-drawing-drawing2d-matrix
https://learn.microsoft.com/en-us/dotnet/api/system.drawing.drawing2d.matrix?view=net-8.0

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/14823.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

系统架构师-考试-基础题-错题集锦2

108.总线-全双工、半双工&#xff1a; 109.软件配置管理-产品配置&#xff1a; 产品配置&#xff1a;指一个产品在其生命周期各个阶段所产生的各种形式和各种版本的文档、计算机程序、部件及数据的集合。 注意&#xff1a;选项中的需求规格说明、设计说明等均可归属于文档。 …

Netty学习02----使用多线程优化Selector

背景前置 在单线程环境下&#xff0c;使用一个线程同时绑定多个事件&#xff1a;连接事件、读事件、写事件。不能充分发挥多核CPU的优势&#xff0c;考虑使用多个线程&#xff0c;每个线程专门负责处理不同的事件&#xff0c;如下图所示&#xff1a;一个线程专门负责连接&#…

【ARK Survival Evolved】方舟:生存进化一键使用服务器开服联机教程

1、进入控制面板 2、第一次购买服务器会安装游戏端&#xff0c;大约5分钟左右&#xff0c;如果长时间处于安装状态请联系客服 3、设置游戏端口 方舟生存进化的设置需要三个端口&#xff0c;它们用于游戏端口&#xff08;必须为首选端口&#xff09;&#xff0c;查询端口&#…

uniapp中使用mockjs模拟接口测试总结(swiper轮播图示例)

完整总结下在uni-app中如何使用Mock.js模拟接口测试&#xff0c;这在后台接口未就绪的情况下非常有用。同时也给出个首页swiper轮播图的mock接口使用。网上的文章都不太完整&#xff0c;这里总结下完整的使用示例&#xff0c;同时也支持h5和小程序平台&#xff0c;分享给需要的…

webpack5 splitChunks分割代码

首先明确webpack 自身的打包行为 当splitChunks为false时&#xff0c;此时不启用任何打包设置 可以看到&#xff0c;静态引入全都打到一个chunk里&#xff0c;动态引入会拆分出来一个chunk,这是纯webpack无配置的打包&#xff0c; webpack会给每个模块打上标记 ,如下 { m…

Python使用multiprocessing实现多进程

大家好&#xff0c;当我们工作中涉及到处理大量数据、并行计算或并发任务时&#xff0c;Python的multiprocessing模块是一个强大而实用的工具。通过它&#xff0c;我们可以轻松地利用多核处理器的优势&#xff0c;将任务分配给多个进程并同时执行&#xff0c;从而提高程序的性能…

基于transformers框架实践Bert系列3-单选题

本系列用于Bert模型实践实际场景&#xff0c;分别包括分类器、命名实体识别、选择题、文本摘要等等。&#xff08;关于Bert的结构和详细这里就不做讲解&#xff0c;但了解Bert的基本结构是做实践的基础&#xff0c;因此看本系列之前&#xff0c;最好了解一下transformers和Bert…

【JavaEE】加法计算器与用户登录实战演练

目录 综合练习加法计算器1. 准备工作2. 约定前后端交互接口3. 服务器代码 用户登录1. 准备工作2. 约定前后端交互接口3. 服务器代码4. 调整前端页面代码 综合练习 理解前后端交互过程接⼝传参, 数据返回, 以及⻚⾯展⽰ 加法计算器 需求: 输⼊两个整数, 点击"点击相加&q…

56. UE5 RPG 给敌人添加AI实现跟随玩家

在这一篇里&#xff0c;我们要实现一下敌人的AI&#xff0c;敌人也需要一系列的行为&#xff0c;比如朝向英雄攻击&#xff0c;移动&#xff0c;在满足条件时施放技能。这些敌人的行为可以通过使用UE的内置的AI系统去实现。 在UE里&#xff0c;只要是基于Character类创建的蓝图…

安卓绕过限制直接使用Android/data无需授权,支持安卓14(部分)

大家都知道&#xff0c;安卓每次更新都会给权限划分的更细、收的更紧。   早在安卓11的时候还可以直接通过授权Android/data来实现操作其他软件的目录&#xff0c;没有之前安卓11授权的图了&#xff0c;反正都长一个样&#xff0c;就直接贴新图了。   后面到了安卓12~13的…

信息系统项目管理师0128:输出(8项目整合管理—8.6管理项目知识—8.6.3输出)

点击查看专栏目录 文章目录 8.6.3 输出 8.6.3 输出 经验教训登记册 经验教训登记册可以包含执行情况的类别和详细的描述&#xff0c;还可包括与执行情况相关的影响、建议和行动方案。经验教训登记册可以记录遇到的挑战、问题、意识到的风险和机会以及其他适用的内容。经验教训…

Debezium+Kafka:Oracle 11g 数据实时同步至 DolphinDB 解决方案

随着越来越多用户使用 DolphinDB&#xff0c;各式各样的应用场景对 DolphinDB 的数据接入提出了不同的要求。部分用户需要将 Oracle 11g 的数据实时同步到 DolphinDB 中来&#xff0c;以满足在 DolphinDB 中实时使用数据的需求。本篇教程将介绍使用 Debezium 来实时捕获和发布 …

npm介绍、常用命令详解以及什么是全局目录

目录 npm介绍、常用命令详解以及什么是全局目录一、介绍npm的主要功能npm仓库npm的配置npm的版本控制 二、命令1. npm init: 初始化一个新的Node.js项目&#xff0c;创建package.json文件。package.json是一个描述项目信息和依赖关系的文件。2. npm install <package_name&g…

LeetCode算法题:42. 接雨水(Java)

题目描述 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 示例 1&#xff1a; 输入&#xff1a;height [0,1,0,2,1,0,1,3,2,1,2,1] 输出&#xff1a;6 解释&#xff1a;上面是由数组 [0,1,0,2,1,0,1,3…

基于vue3速学angular

因为工作原因&#xff0c;需要接手新的项目&#xff0c;新的项目是angular框架的&#xff0c;自学下和vue3的区别&#xff0c;写篇博客记录下&#xff1a; 参考&#xff1a;https://zhuanlan.zhihu.com/p/546843290?utm_id0 1.结构上&#xff1a; vue3:一个vue文件&#xff…

python:pycharm虚拟解释器报错环境位置目录为空

目录 解释器分控制台解释器 和 pycharm解释器 控制台解释器切换&#xff1a; pycharm解释器 解释器分控制台解释器 和 pycharm解释器 控制台解释器切换&#xff1a; 切换到解释器下 激活解释器 查看解释器 where python 激活成功 这时在控制台使用python xxx.py 可以…

​​​【收录 Hello 算法】10.1 二分查找

目录 10.1 二分查找 10.1.1 区间表示方法 10.1.2 优点与局限性 10.1 二分查找 二分查找&#xff08;binary search&#xff09;是一种基于分治策略的高效搜索算法。它利用数据的有序性&#xff0c;每轮缩小一半搜索范围&#xff0c;直至找到目标元素或搜索区间为空…

​​​【收录 Hello 算法】第 10 章 搜索

目录 第 10 章 搜索 本章内容 第 10 章 搜索 搜索是一场未知的冒险&#xff0c;我们或许需要走遍神秘空间的每个角落&#xff0c;又或许可以快速锁定目标。 在这场寻觅之旅中&#xff0c;每一次探索都可能得到一个未曾料想的答案。 本章内容 10.1 二分查找10.2 二…

恶劣天候激光雷达点云模拟方法论文整理

恶劣天候点云模拟方法论文整理 模拟雨天点云&#xff1a;【AAAI2024】模拟雪天点云&#xff1a;【CVPR 2022 oral】模拟雾天点云&#xff1a;【ICCV2021】模拟点云恶劣天候的散射现象&#xff1a;【Arxiv 2021】模拟积水地面的水花飞溅点云&#xff1a;【RAL2022】 模拟雨天点云…

蓝桥杯Web开发【模拟题三】15届

1.创意广告牌 在"绮幻山谷"的历史和"梦幻海湾"的繁华交汇之处&#xff0c;一块创意广告牌傲然矗立。它以木质纹理的背景勾勒出古朴氛围&#xff0c;上方倾斜的牌子写着"绮幻山谷的风吹到了梦幻海湾"&#xff0c;瞬间串联了过去与现在&#xff0…