【学习笔记】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	0
	0	1
	0	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	0
	3	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);//true
    DrawString(e, $"IsEquals:{matrix.Equals(otherMatrix)}", ref offset);//true

    matrixClone.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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

(Java企业 / 公司项目)配置Linux网络-导入虚拟机

公司给了我一个IP地址 &#xff0c;提供了一个虚拟机或者自己搭建虚拟机&#xff0c;还有提供登录的账号密码 可以查看我之前的文章 VMware Workstation Pro 17虚拟机超级详细搭建&#xff08;含redis&#xff0c;nacos&#xff0c;docker, rabbitmq&#xff0c;sentinel&…

民国漫画杂志《时代漫画》第16期.PDF

时代漫画16.PDF: https://url03.ctfile.com/f/1779803-1248612470-6a05f0?p9586 (访问密码: 9586) 《时代漫画》的杂志在1934年诞生了&#xff0c;截止1937年6月战争来临被迫停刊共发行了39期。 ps:资源来源网络&#xff01;

EMQX 的初始IP改为自己的实际IP

分类 EMQX Dashboard&#xff08;控制台&#xff09;: Dashboard提供了一个Web界面&#xff0c;用于管理和监控EMQX的运行状态。您可以通过配置dashboard.listeners.http.bind来设置Dashboard的监听地址和端口。例如&#xff0c;如果您想要Dashboard在所有网络接口上监听&#…

【oracle004】oracle内置函数手册总结(已更新)

1.熟悉、梳理、总结下oracle相关知识体系。 2.日常研发过程中使用较少&#xff0c;随着时间的推移&#xff0c;很快就忘得一干二净&#xff0c;所以梳理总结下&#xff0c;以备日常使用参考 3.欢迎批评指正&#xff0c;跪谢一键三连&#xff01; 总结源文件资源下载地址&#x…

Scala的简单学习一

一 相关知识 1.1 scala的安装 1.在idea中导入依赖&#xff0c;并在Idea下载scala插件 1.2 scala基础知识点 1.scala代码中一行语句的结束是以换行符为标准&#xff0c;可以不用写分号 2.class是一个普通的类&#xff0c;object相当于一个单例对象&#xff0c;object类中的…

基于GA遗传优化的CNN-GRU的时间序列回归预测matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 CNN-GRU模型架构 4.2 GA优化CNN-GRU流程 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 MATLAB2022a 3.部分核心程序 ...........................................…

类和对象的基本概念

类和对象的基本概念 C和C中struct区别类的封装封装访问权限总结struct和class的区别 将成员变量设置为private C和C中struct区别 C语言struct只有变量C语言struct 既有变量&#xff0c;也有函数 类的封装 封装 把变量&#xff08;属性&#xff09;和函数&#xff08;操作&a…

【软件工程】【23.10】p3

关键字&#xff1a; 软件工程定义及目的、需求规约定义及性质、模块的控制域及作用域、类和类图、调试特征、瀑布模型

Star CCM+分配零部件至区域后交界面丢失-更新找回

前言 在工程应用中&#xff0c;将零部件分配至区域后&#xff0c;一般常规的操作需要对交界面进行检查。偶尔会发现交界面丢失。遇到此类问题&#xff0c;在没有做其他操作前&#xff08;比如画网格&#xff09;&#xff0c;可以选择先删除所有区域在重新分配至区域。若已经进…

手把手教学,一站式安装ubuntu及配置服务器

应用背景&#xff1a;实验室刚弄了一台4090的电脑&#xff0c;老师让我们搞成服务器 一、制作ubuntu启动盘 1.1 清华开源影像站下载ubuntu桌面版本Index of /ubuntu-releases/22.04/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror 1.2 下载UltralSO软件 https://…

【C语言回顾】文件操作

前言1. 文件打开模式2. 示例代码2.1 打开和关闭文件2.2 读写文件2.3 二进制文件操作 结语 #include<GUIQU.h> int main { 上期回顾: 【C语言回顾】动态内存管理 个人主页&#xff1a;C_GUIQU 专栏&#xff1a;【C语言学习】 return 一键三连; } 前言 各位小伙伴大家好&…

融资融券大揭秘:两融入门操作最新指南!

#引言# 随着中国资本市场日新月异的发展进程&#xff0c;融资融券交易已崭露头角&#xff0c;成为投资者们瞩目的焦点。作为一种颇具影响力的投资方式&#xff0c;它正逐渐吸引越来越多的投资者关注。本文旨在为大家深入剖析融资融券交易的核心概念、详尽的操作步骤以及必须留意…

基础widgets

1.widgets_文本和字体 在flutter当中几乎所有的对象都是widget,他跟原生开发的控线不一样,flutter开发当中,widget的概念更广泛一点, 不仅可以表示ui元素,也可以表示一些功能性的组件,例如手势检测等 基础组件 文本和字体 对于html当中对应就是lab或者label或者span这样的行内元…

基于yolov2深度学习网络的昆虫检测算法matlab仿真,并输出昆虫数量和大小判决

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022A 3.部分核心程序 .......................................................... for i 1:12 % 遍历结…

Julia编程01:Julia语言介绍

在2020上半年&#xff0c;因为疫情无法返校&#xff0c;所以在家待了半年&#xff0c;期间学习一点了R语言、Python、Julia、linux和C语言&#xff0c;只是学习基础语法并没有项目练习&#xff0c;因此返校半年后差不多都不记得了&#xff0c;现在重新捡起Julia丰富下当时写的笔…

Python 将文件夹中的图片信息导入到 Excel 的表格

引言 在数据处理和管理的日常任务中&#xff0c;经常需要将文件夹中的图片文件信息&#xff08;如文件名、路径、创建日期、大小、分辨率等&#xff09;整理成一个 Excel 表格。这篇博客将介绍如何使用 Python 中的 wxPython 模块创建一个 GUI 应用&#xff0c;用户可以通过这…

用Intellij实现web登录页面时,servlet已经配置好了,但是还是报404

今天看到一个404问题&#xff1a; 用Intellij实现web登录页面时&#xff0c;代码如下图所示。点击运行后会跳转到浏览器&#xff0c;但是输入/login时&#xff0c;浏览器显示404&#xff0c;且无法在控制面板上打印内容&#xff1b;输入/index时&#xff0c;也无法在浏览器上显…

Vue的router.addRoutes不起作用

Vue的router.addRoutes()不起作用解决方案 最近在学习制作后台管理系统的时候&#xff0c;涉及到了权限&#xff0c;在通过后台获取到数据后使用router.addRoutes()时不起作用。 最终发现左侧菜单组件中的路由是根据this.$router.options.routes来渲染的&#xff0c;最终使用…

UDP协议与TCP协议1.2

UDP UDP数据报UDP报头UDP载荷 UDP的报文格式&#xff1a; 这里的UDP长度&#xff0c;描述了整个UDP数据报&#xff0c;占多少个字节&#xff0c;这里整个UDP长度最多是64kb 在UDP中校验和就是使用CRC的方式来完成的 数据在网络传输中是可能会出现错误的&#xff0c;例如比特翻…