矩阵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);
注意相乘的顺序
参数 | 说明 |
---|---|
order | Append:原矩阵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);
}
}
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);
}
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