【学习笔记】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

  • 25
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

图南科技

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值