From 49038f5d428b03a13dc8e1010b6b6962ff51ca43 Mon Sep 17 00:00:00 2001
From: Christopher Whitley <103014489+AristurtleDev@users.noreply.github.com>
Date: Mon, 27 May 2024 15:44:38 -0400
Subject: [PATCH] Replace `Matrix2` with `Matrix3x2` (#870)
* Replace `Matrix2` with `Matrix3x2`
* Update benchmarks
* Add XML documentation for `Matrix3x2`
---
.gitignore | 2 +-
Directory.Build.props | 4 +-
benchmarks/Directory.Build.props | 22 +
...Game.Extended.Benchmarks.Collisions.csproj | 5 -
.../Matrix3x2Benchmarks.cs | 195 +++
.../MonoGame.Extended.Benchmarks.csproj | 14 +
.../MonoGame.Extended.Benchmarks/Program.cs | 7 +
.../CollisionComponent.cs | 4 +-
.../MonoGame.Extended.Graphics/Batcher2D.cs | 36 +-
.../Geometry/GeometryBuilder2D.cs | 2 +-
.../Math/BoundingRectangle.cs | 12 +-
source/MonoGame.Extended/Math/Matrix2.cs | 1038 ----------------
source/MonoGame.Extended/Math/Matrix3x2.cs | 1082 +++++++++++++++++
.../Math/OrientedRectangle.cs | 18 +-
.../Math/PrimitivesHelper.cs | 6 +-
source/MonoGame.Extended/Math/RectangleF.cs | 8 +-
source/MonoGame.Extended/Math/ShapeF.cs | 2 +-
source/MonoGame.Extended/Transform.cs | 34 +-
.../MonoGame.Extended.Tests/Math/Matrix3x2.cs | 20 +
.../Primitives/BoundingRectangleTests.cs | 8 +-
.../Primitives/OrientedRectangleTests.cs | 56 +-
.../Primitives/RectangleFTests.cs | 12 +-
.../Primitives/ShapeTests.cs | 10 +-
23 files changed, 1447 insertions(+), 1150 deletions(-)
create mode 100644 benchmarks/Directory.Build.props
create mode 100644 benchmarks/MonoGame.Extended.Benchmarks/Matrix3x2Benchmarks.cs
create mode 100644 benchmarks/MonoGame.Extended.Benchmarks/MonoGame.Extended.Benchmarks.csproj
create mode 100644 benchmarks/MonoGame.Extended.Benchmarks/Program.cs
delete mode 100644 source/MonoGame.Extended/Math/Matrix2.cs
create mode 100644 source/MonoGame.Extended/Math/Matrix3x2.cs
create mode 100644 tests/MonoGame.Extended.Tests/Math/Matrix3x2.cs
diff --git a/.gitignore b/.gitignore
index d64f1efd8..456e6515f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -20,7 +20,7 @@
################################################################################
### Build artifacts directory
################################################################################
-.artifacts/
+*.[Aa]rtifacts/
################################################################################
### OS specific auto generated files
diff --git a/Directory.Build.props b/Directory.Build.props
index 52d9ed9e5..f600fa288 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -32,7 +32,7 @@
-
+
diff --git a/benchmarks/Directory.Build.props b/benchmarks/Directory.Build.props
new file mode 100644
index 000000000..0381bf797
--- /dev/null
+++ b/benchmarks/Directory.Build.props
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+ $(SolutionDirectory).artifacts/benchmarks
+ false
+ false
+ NU1701
+ true
+
+
+
+
+
+
+
+
diff --git a/benchmarks/MonoGame.Extended.Benchmarks.Collisions/MonoGame.Extended.Benchmarks.Collisions.csproj b/benchmarks/MonoGame.Extended.Benchmarks.Collisions/MonoGame.Extended.Benchmarks.Collisions.csproj
index 530bd13c6..8d095d327 100644
--- a/benchmarks/MonoGame.Extended.Benchmarks.Collisions/MonoGame.Extended.Benchmarks.Collisions.csproj
+++ b/benchmarks/MonoGame.Extended.Benchmarks.Collisions/MonoGame.Extended.Benchmarks.Collisions.csproj
@@ -7,11 +7,6 @@
enable
-
-
-
-
-
diff --git a/benchmarks/MonoGame.Extended.Benchmarks/Matrix3x2Benchmarks.cs b/benchmarks/MonoGame.Extended.Benchmarks/Matrix3x2Benchmarks.cs
new file mode 100644
index 000000000..301cfbdc2
--- /dev/null
+++ b/benchmarks/MonoGame.Extended.Benchmarks/Matrix3x2Benchmarks.cs
@@ -0,0 +1,195 @@
+using System.Runtime.CompilerServices;
+using BenchmarkDotNet.Attributes;
+using Microsoft.Xna.Framework;
+
+namespace MonoGame.Extended.Benchmarks;
+
+[MemoryDiagnoser]
+public class Matrix3x2Benchmarks
+{
+ private Matrix2 _matrix2;
+ private Matrix3x2 _matrix3x2;
+
+ [GlobalSetup]
+ public void Setup()
+ {
+ _matrix2 = new Matrix2(1, 2, 3, 4, 5, 6);
+ _matrix3x2 = new Matrix3x2(1, 2, 3, 4, 5, 6);
+ }
+
+ [Benchmark]
+ public Vector2 Matrix2_getTranslation() => _matrix2.Translation;
+
+ [Benchmark]
+ public Vector2 Matrix3x2_getTranslation() => _matrix3x2.Translation;
+
+ // [Benchmark]
+ // public float Matrix2_getRotation() => _matrix2.Rotation;
+
+ // [Benchmark]
+ // public float Matrix3x2_getRotation() => _matrix3x2.Rotation;
+
+ // [Benchmark]
+ // public Vector2 Matrix2_getScale() => _matrix2.Scale;
+
+ // [Benchmark]
+ // public Vector2 Matrix3x2_getScale() => _matrix3x2.Scale;
+
+ // [Benchmark]
+ // public (Vector2, float, Vector2) Matrix2_Decompose()
+ // {
+ // Vector2 translation = _matrix2.Translation;
+ // float rotation = _matrix2.Rotation;
+ // Vector2 scale = _matrix2.Scale;
+ // return (translation, rotation, scale);
+ // }
+
+ // [Benchmark]
+ // public (Vector2, float, Vector2) Matrix3x2_Decompose()
+ // {
+ // _matrix3x2.Decompose(out Vector2 translation, out float rotation, out Vector2 scale);
+ // return (translation, rotation, scale);
+ // }
+
+ // [Benchmark]
+ // public Vector2 Matrix2_Transform() => _matrix2.Transform(Vector2.One);
+
+ // [Benchmark]
+ // public Vector2 Matrix3x2_Transform() => _matrix3x2.Transform(Vector2.One);
+
+ // [Benchmark]
+ // public float Matrix2_Determinant() => _matrix2.Determinant();
+
+ // [Benchmark]
+ // public float Matrix3x2_Determinant() => _matrix3x2.Determinant();
+
+ // [Benchmark]
+ // public Matrix2 Matrix2_CreateFrom()
+ // {
+ // Matrix2.CreateFrom(Vector2.Zero, 1.0f, Vector2.One, Vector2.Zero, out Matrix2 result);
+ // return result;
+ // }
+
+ // [Benchmark]
+ // public Matrix3x2 Matrix3x2_CreateFrom()
+ // {
+ // Matrix3x2.CreateFrom(Vector2.Zero, 1.0f, Vector2.One, Vector2.Zero, out Matrix3x2 result);
+ // return result;
+ // }
+
+ // [Benchmark]
+ // public Matrix2 Matrix2_CreateRotationZ()
+ // {
+ // Matrix2.CreateRotationZ(1.0f, out Matrix2 result);
+ // return result;
+ // }
+
+ // [Benchmark]
+ // public Matrix3x2 Matrix3x2_CreateRotationZ()
+ // {
+ // Matrix3x2.CreateRotationZ(1.0f, out Matrix3x2 result);
+ // return result;
+ // }
+
+ // [Benchmark]
+ // public Matrix2 Matrix2_CreateScale()
+ // {
+ // Matrix2.CreateScale(1.0f, out Matrix2 result);
+ // return result;
+ // }
+
+ // [Benchmark]
+ // public Matrix3x2 Matrix3x2_CreateScale()
+ // {
+ // Matrix3x2.CreateScale(1.0f, out Matrix3x2 result);
+ // return result;
+ // }
+
+ // [Benchmark]
+ // public Matrix2 Matrix2_CreateTranslation()
+ // {
+ // Matrix2.CreateTranslation(1.0f, 1.0f, out Matrix2 result);
+ // return result;
+ // }
+
+ // [Benchmark]
+ // public Matrix3x2 Matrix3x2_CreateTranslation()
+ // {
+ // Matrix3x2.CreateTranslation(1.0f, 1.0f, out Matrix3x2 result);
+ // return result;
+ // }
+
+ // [Benchmark]
+ // public Matrix2 Matrix2_Invert()
+ // {
+ // Matrix2.Invert(ref _matrix2, out Matrix2 result);
+ // return result;
+ // }
+
+ // [Benchmark]
+ // public Matrix3x2 Matrix3x2_Invert()
+ // {
+ // Matrix3x2.Invert(_matrix3x2);
+ // return _matrix3x2;
+ // }
+
+ // [Benchmark]
+ // public Matrix2 Matrix2_Add()
+ // {
+ // return Matrix2.Add(_matrix2, _matrix2);
+ // }
+
+ // [Benchmark]
+ // public Matrix3x2 Matrix3x2_Add()
+ // {
+ // return Matrix3x2.Add(_matrix3x2, _matrix3x2);
+ // }
+
+ // [Benchmark]
+ // public Matrix2 Matrix2_Subtract()
+ // {
+ // return Matrix2.Subtract(_matrix2, _matrix2);
+ // }
+
+ // [Benchmark]
+ // public Matrix3x2 Matrix3x2_Subtract()
+ // {
+ // return Matrix3x2.Subtract(_matrix3x2, _matrix3x2);
+ // }
+
+ // [Benchmark]
+ // public Matrix2 Matrix2_Multiply()
+ // {
+ // return Matrix2.Subtract(_matrix2, _matrix2);
+ // }
+
+ // [Benchmark]
+ // public Matrix3x2 Matrix3x2_Multiply()
+ // {
+ // return Matrix3x2.Multiply(_matrix3x2, _matrix3x2);
+ // }
+
+ // [Benchmark]
+ // public Matrix2 Matrix2_Divide()
+ // {
+ // return Matrix2.Divide(_matrix2, _matrix2);
+ // }
+
+ // [Benchmark]
+ // public Matrix3x2 Matrix3x2_Divide()
+ // {
+ // return Matrix3x2.Divide(_matrix3x2, _matrix3x2);
+ // }
+
+ // [Benchmark]
+ // public Matrix Matrix2_ToMatrix()
+ // {
+ // return _matrix2.ToMatrix();
+ // }
+
+ // [Benchmark]
+ // public Matrix Matrix3x2_ToMatrix()
+ // {
+ // return _matrix3x2.ToMatrix();
+ // }
+}
diff --git a/benchmarks/MonoGame.Extended.Benchmarks/MonoGame.Extended.Benchmarks.csproj b/benchmarks/MonoGame.Extended.Benchmarks/MonoGame.Extended.Benchmarks.csproj
new file mode 100644
index 000000000..04b670df2
--- /dev/null
+++ b/benchmarks/MonoGame.Extended.Benchmarks/MonoGame.Extended.Benchmarks.csproj
@@ -0,0 +1,14 @@
+
+
+
+ Exe
+ net8.0
+ enable
+ enable
+
+
+
+
+
+
+
diff --git a/benchmarks/MonoGame.Extended.Benchmarks/Program.cs b/benchmarks/MonoGame.Extended.Benchmarks/Program.cs
new file mode 100644
index 000000000..79fbe5488
--- /dev/null
+++ b/benchmarks/MonoGame.Extended.Benchmarks/Program.cs
@@ -0,0 +1,7 @@
+using BenchmarkDotNet.Running;
+using MonoGame.Extended.Benchmarks;
+
+
+BenchmarkRunner.Run();
+
+Console.WriteLine("finished");
diff --git a/source/MonoGame.Extended.Collisions/CollisionComponent.cs b/source/MonoGame.Extended.Collisions/CollisionComponent.cs
index 51467d9d9..d5393ba94 100644
--- a/source/MonoGame.Extended.Collisions/CollisionComponent.cs
+++ b/source/MonoGame.Extended.Collisions/CollisionComponent.cs
@@ -273,13 +273,13 @@ private static Vector2 PenetrationVector(CircleF circ, RectangleF rect)
private static Vector2 PenetrationVector(CircleF circleA, OrientedRectangle orientedRectangleB)
{
- var rotation = Matrix2.CreateRotationZ(orientedRectangleB.Orientation.Rotation);
+ var rotation = Matrix3x2.CreateRotationZ(orientedRectangleB.Orientation.Rotation);
var circleCenterInRectangleSpace = rotation.Transform(circleA.Center - orientedRectangleB.Center);
var circleInRectangleSpace = new CircleF(circleCenterInRectangleSpace, circleA.Radius);
var boundingRectangle = new BoundingRectangle(new Point2(), orientedRectangleB.Radii);
var penetrationVector = PenetrationVector(circleInRectangleSpace, boundingRectangle);
- var inverseRotation = Matrix2.CreateRotationZ(-orientedRectangleB.Orientation.Rotation);
+ var inverseRotation = Matrix3x2.CreateRotationZ(-orientedRectangleB.Orientation.Rotation);
var transformedPenetration = inverseRotation.Transform(penetrationVector);
return transformedPenetration;
diff --git a/source/MonoGame.Extended.Graphics/Batcher2D.cs b/source/MonoGame.Extended.Graphics/Batcher2D.cs
index e7ec533f7..aeb03c61c 100644
--- a/source/MonoGame.Extended.Graphics/Batcher2D.cs
+++ b/source/MonoGame.Extended.Graphics/Batcher2D.cs
@@ -91,7 +91,7 @@ protected override void SortDrawCallsAndBindBuffers()
// Upload the indices to the GPU and then select that index stream for drawing
_indexBuffer.SetData(_sortedIndices, 0, _indexCount);
GraphicsDevice.Indices = _indexBuffer;
-
+
_indexCount = 0;
_vertexCount = 0;
}
@@ -136,12 +136,12 @@ protected override void InvokeDrawCall(ref DrawCallInfo drawCall)
}
///
- /// Draws a sprite using a specified , transform , source
+ /// Draws a sprite using a specified , transform , source
/// , and an optional
/// , origin , , and depth .
///
/// The .
- /// The transform .
+ /// The transform .
///
/// The texture region of the . Use
/// null
to use the entire .
@@ -151,7 +151,7 @@ protected override void InvokeDrawCall(ref DrawCallInfo drawCall)
/// The depth . The default value is 0
.
/// The method has not been called.
/// is null.
- public void DrawSprite(Texture2D texture, ref Matrix2 transformMatrix, ref Rectangle sourceRectangle,
+ public void DrawSprite(Texture2D texture, ref Matrix3x2 transformMatrix, ref Rectangle sourceRectangle,
Color? color = null, FlipFlags flags = FlipFlags.None, float depth = 0)
{
_geometryBuilder.BuildSprite(_vertexCount, ref transformMatrix, texture, ref sourceRectangle, color, flags, depth);
@@ -159,17 +159,17 @@ public void DrawSprite(Texture2D texture, ref Matrix2 transformMatrix, ref Recta
}
///
- /// Draws a using the specified transform and an optional
+ /// Draws a using the specified transform and an optional
/// , origin , , and depth .
///
/// The .
- /// The transform .
+ /// The transform .
/// The . Use null
to use the default .
/// The . The default value is .
/// The depth . The default value is 0
.
/// The method has not been called.
/// is null.
- public void DrawTexture(Texture2D texture, ref Matrix2 transformMatrix, Color? color = null,
+ public void DrawTexture(Texture2D texture, ref Matrix3x2 transformMatrix, Color? color = null,
FlipFlags flags = FlipFlags.None, float depth = 0)
{
var rectangle = default(Rectangle);
@@ -193,12 +193,12 @@ private void EnqueueBuiltGeometry(Texture2D texture, float depth)
///
/// Draws unicode (UTF-16) characters as sprites using the specified , text
- /// , transform and optional , origin
+ /// , transform and optional , origin
/// , , and depth .
///
/// The .
/// The text .
- /// The transform .
+ /// The transform .
///
/// The . Use null
to use the default
/// .
@@ -207,7 +207,7 @@ private void EnqueueBuiltGeometry(Texture2D texture, float depth)
/// The depth . The default value is 0f
.
/// The method has not been called.
/// is null or is null.
- public void DrawString(BitmapFont bitmapFont, StringBuilder text, ref Matrix2 transformMatrix,
+ public void DrawString(BitmapFont bitmapFont, StringBuilder text, ref Matrix3x2 transformMatrix,
Color? color = null, FlipFlags flags = FlipFlags.None, float depth = 0f)
{
EnsureHasBegun();
@@ -316,19 +316,19 @@ public void DrawString(BitmapFont bitmapFont, StringBuilder text, Vector2 positi
float rotation = 0f, Vector2? origin = null, Vector2? scale = null,
FlipFlags flags = FlipFlags.None, float depth = 0f)
{
- Matrix2 transformMatrix;
- Matrix2.CreateFrom(position, rotation, scale, origin, out transformMatrix);
+ Matrix3x2 transformMatrix;
+ Matrix3x2.CreateFrom(position, rotation, scale, origin, out transformMatrix);
DrawString(bitmapFont, text, ref transformMatrix, color, flags, depth);
}
///
/// Draws unicode (UTF-16) characters as sprites using the specified , text
- /// , transform and optional , origin
+ /// , transform and optional , origin
/// , , and depth .
///
/// The .
/// The text .
- /// The transform .
+ /// The transform .
///
/// The . Use null
to use the default
/// .
@@ -337,7 +337,7 @@ public void DrawString(BitmapFont bitmapFont, StringBuilder text, Vector2 positi
/// The depth . The default value is 0f
/// The method has not been called.
/// is null or is null.
- public void DrawString(BitmapFont bitmapFont, string text, ref Matrix2 transformMatrix, Color? color = null,
+ public void DrawString(BitmapFont bitmapFont, string text, ref Matrix3x2 transformMatrix, Color? color = null,
FlipFlags flags = FlipFlags.None, float depth = 0f)
{
EnsureHasBegun();
@@ -394,8 +394,8 @@ public void DrawString(BitmapFont bitmapFont, string text, Vector2 position, Col
float rotation = 0f, Vector2? origin = null, Vector2? scale = null,
FlipFlags flags = FlipFlags.None, float depth = 0f)
{
- Matrix2 matrix;
- Matrix2.CreateFrom(position, rotation, scale, origin, out matrix);
+ Matrix3x2 matrix;
+ Matrix3x2.CreateFrom(position, rotation, scale, origin, out matrix);
DrawString(bitmapFont, text, ref matrix, color, flags, depth);
}
@@ -447,4 +447,4 @@ public int CompareTo(DrawCallInfo other)
}
}
}
-}
\ No newline at end of file
+}
diff --git a/source/MonoGame.Extended.Graphics/Geometry/GeometryBuilder2D.cs b/source/MonoGame.Extended.Graphics/Geometry/GeometryBuilder2D.cs
index c113fbe03..a0eb4a0f3 100644
--- a/source/MonoGame.Extended.Graphics/Geometry/GeometryBuilder2D.cs
+++ b/source/MonoGame.Extended.Graphics/Geometry/GeometryBuilder2D.cs
@@ -12,7 +12,7 @@ public GeometryBuilder2D(int maximumVerticesCount, int maximumIndicesCount)
{
}
- public void BuildSprite(int indexOffset, ref Matrix2 transformMatrix, Texture2D texture,
+ public void BuildSprite(int indexOffset, ref Matrix3x2 transformMatrix, Texture2D texture,
ref Rectangle sourceRectangle,
Color? color = null, FlipFlags flags = FlipFlags.None, float depth = 0)
{
diff --git a/source/MonoGame.Extended/Math/BoundingRectangle.cs b/source/MonoGame.Extended/Math/BoundingRectangle.cs
index 324ebb24e..ca4af01d9 100644
--- a/source/MonoGame.Extended/Math/BoundingRectangle.cs
+++ b/source/MonoGame.Extended/Math/BoundingRectangle.cs
@@ -5,7 +5,7 @@
namespace MonoGame.Extended
{
- // Real-Time Collision Detection, Christer Ericson, 2005. Chapter 4.2; Bounding Volumes - Axis-aligned Bounding Boxes (AABBs). pg 77
+ // Real-Time Collision Detection, Christer Ericson, 2005. Chapter 4.2; Bounding Volumes - Axis-aligned Bounding Boxes (AABBs). pg 77
///
/// An axis-aligned, four sided, two dimensional box defined by a centre and a radii
@@ -112,7 +112,7 @@ public static BoundingRectangle CreateFrom(IReadOnlyList points)
///
/// Computes the from the specified transformed by
/// the
- /// specified .
+ /// specified .
///
/// The bounding rectangle.
/// The transform matrix.
@@ -129,7 +129,7 @@ public static BoundingRectangle CreateFrom(IReadOnlyList points)
///
///
public static void Transform(ref BoundingRectangle boundingRectangle,
- ref Matrix2 transformMatrix, out BoundingRectangle result)
+ ref Matrix3x2 transformMatrix, out BoundingRectangle result)
{
PrimitivesHelper.TransformRectangle(ref boundingRectangle.Center, ref boundingRectangle.HalfExtents, ref transformMatrix);
result.Center = boundingRectangle.Center;
@@ -139,7 +139,7 @@ public static void Transform(ref BoundingRectangle boundingRectangle,
///
/// Computes the from the specified transformed by
/// the
- /// specified .
+ /// specified .
///
/// The bounding rectangle.
/// The transform matrix.
@@ -155,7 +155,7 @@ public static void Transform(ref BoundingRectangle boundingRectangle,
///
///
public static BoundingRectangle Transform(BoundingRectangle boundingRectangle,
- ref Matrix2 transformMatrix)
+ ref Matrix3x2 transformMatrix)
{
BoundingRectangle result;
Transform(ref boundingRectangle, ref transformMatrix, out result);
@@ -576,4 +576,4 @@ public override string ToString()
internal string DebugDisplayString => ToString();
}
-}
\ No newline at end of file
+}
diff --git a/source/MonoGame.Extended/Math/Matrix2.cs b/source/MonoGame.Extended/Math/Matrix2.cs
deleted file mode 100644
index cb5671098..000000000
--- a/source/MonoGame.Extended/Math/Matrix2.cs
+++ /dev/null
@@ -1,1038 +0,0 @@
-using System;
-using System.Diagnostics;
-using System.Runtime.CompilerServices;
-using Microsoft.Xna.Framework;
-
-// ReSharper disable CompareOfFloatsByEqualityOperator
-
-namespace MonoGame.Extended
-{
- // https://en.wikipedia.org/wiki/Matrix_(mathematics)
- // "Immersive Linear Algebra"; Jacob Ström, Kalle Åström & Tomas Akenine-Möller; 2015-2016. Chapter 6: The Matrix. http://immersivemath.com/ila/ch06_matrices/ch06.html
- // "Real-Time Collision Detection"; Christer Ericson; 2005. Chapter 3.1: A Math and Geometry Primer - Matrices. pg 23-34
-
- // Original code was from Matrix2D.cs in the Nez Library: https://github.com/prime31/Nez/
-
- ///
- /// Defines a 3x3 matrix using floating point numbers which can store two dimensional translation, scale and rotation
- /// information in a right-handed coordinate system.
- ///
- ///
- ///
- /// Matrices use a row vector layout in the XNA / MonoGame Framework but, in general, matrices can be either have
- /// a row vector or column vector layout. Row vector matrices view vectors as a row from left to right, while
- /// column vector matrices view vectors as a column from top to bottom. For example, the
- /// corresponds to the fields and .
- ///
- ///
- /// The fields M13 and M23 always have a value of 0.0f
, and thus are removed from the
- /// to reduce its memory footprint. Same is true for the field M33, except it always has a
- /// value of 1.0f
.
- ///
- ///
- [DebuggerDisplay("{DebugDisplayString,nq}")]
- public struct Matrix2 : IEquatable, IEquatableByRef
- {
- public float M11; // x scale, also used for rotation
- public float M12; // used for rotation
-
- public float M21; // used for rotation
- public float M22; // y scale, also used for rotation
-
- public float M31; // x translation
- public float M32; // y translation
-
- ///
- /// Gets the identity matrix.
- ///
- ///
- /// The identity matrix.
- ///
- public static Matrix2 Identity { get; } = new Matrix2(1f, 0f, 0f, 1f, 0f, 0f);
-
- ///
- /// Gets the translation.
- ///
- ///
- /// The translation.
- ///
- /// The is equal to the vector (M31, M32)
.
- public Vector2 Translation => new Vector2(M31, M32);
-
- ///
- /// Gets the rotation angle in radians.
- ///
- ///
- /// The rotation angle in radians.
- ///
- ///
- /// The is equal to Atan2(M21, M11)
.
- ///
- public float Rotation => (float)Math.Atan2(M21, M11);
-
- ///
- /// Gets the scale.
- ///
- ///
- /// The scale.
- ///
- ///
- /// The is equal to the vector
- /// (Sqrt(M11 * M11 + M21 * M21), Sqrt(M12 * M12 + M22 * M22))
.
- ///
- public Vector2 Scale
- {
- get
- {
- var scaleX = (float)Math.Sqrt(M11 * M11 + M21 * M21);
- var scaleY = (float)Math.Sqrt(M12 * M12 + M22 * M22);
- return new Vector2(scaleX, scaleY);
- }
- }
-
- ///
- /// Initializes a new instance of the struct.
- ///
- /// The value to initialize to.
- /// The value to initialize to.
- /// The value to initialize to.
- /// The value to initialize to.
- /// The value to initialize to.
- /// The value to initialize to.
- ///
- ///
- /// The fields M13 and M23 always have a value of 0.0f
, and thus are removed from the
- /// to reduce its memory footprint. Same is true for the field M33, except it always has a
- /// value of 1.0f
.
- ///
- ///
- public Matrix2(float m11, float m12, float m21, float m22, float m31, float m32)
- {
- M11 = m11;
- M12 = m12;
-
- M21 = m21;
- M22 = m22;
-
- M31 = m31;
- M32 = m32;
- }
-
- ///
- /// Transforms the specified by this .
- ///
- /// The vector.
- /// The resulting .
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public Vector2 Transform(Vector2 vector)
- {
- Vector2 result;
- Transform(vector, out result);
- return result;
- }
-
- ///
- /// Transforms the specified by this .
- ///
- /// The vector.
- /// The resulting .
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void Transform(Vector2 vector, out Vector2 result)
- {
- result.X = vector.X * M11 + vector.Y * M21 + M31;
- result.Y = vector.X * M12 + vector.Y * M22 + M32;
- }
-
- ///
- /// Transforms the specified by this .
- ///
- /// The x value of the vector.
- /// The y value of the vector.
- /// The resulting .
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void Transform(float x, float y, out Vector2 result)
- {
- result.X = x * M11 + y * M21 + M31;
- result.Y = x * M12 + y * M22 + M32;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void Transform(float x, float y, ref Vector3 result)
- {
- result.X = x * M11 + y * M21 + M31;
- result.Y = x * M12 + y * M22 + M32;
- }
-
- ///
- /// Initializes a new instance of the struct that can be used to translate, rotate, and scale a set of vertices in two dimensions.
- ///
- /// The amounts to translate by on the x and y axes.
- /// The amount, in radians, in which to rotate around the z-axis.
- /// The amount to scale by on the x and y axes.
- /// The point which to rotate and scale around.
- /// The resulting
- public static void CreateFrom(Vector2 position, float rotation, Vector2? scale, Vector2? origin,
- out Matrix2 transformMatrix)
- {
- transformMatrix = Identity;
-
- if (origin.HasValue)
- {
- transformMatrix.M31 = -origin.Value.X;
- transformMatrix.M32 = -origin.Value.Y;
- }
-
- if (scale.HasValue)
- {
- var scaleMatrix = CreateScale(scale.Value);
- Multiply(ref transformMatrix, ref scaleMatrix, out transformMatrix);
- }
-
- // ReSharper disable once CompareOfFloatsByEqualityOperator
- if (rotation != 0f)
- {
- var rotationMatrix = CreateRotationZ(-rotation);
- Multiply(ref transformMatrix, ref rotationMatrix, out transformMatrix);
- }
-
- var translationMatrix = CreateTranslation(position);
- Multiply(ref transformMatrix, ref translationMatrix, out transformMatrix);
- }
-
- ///
- /// Initializes a new instance of the struct that can be used to translate, rotate, and scale a set of vertices in two dimensions.
- ///
- /// The amounts to translate by on the x and y axes.
- /// The amount, in radians, in which to rotate around the z-axis.
- /// The amount to scale by on the x and y axes.
- /// The point which to rotate and scale around.
- /// The resulting .
- public static Matrix2 CreateFrom(Vector2 position, float rotation, Vector2? scale = null, Vector2? origin = null)
- {
- var transformMatrix = Identity;
-
- if (origin.HasValue)
- {
- transformMatrix.M31 = -origin.Value.X;
- transformMatrix.M32 = -origin.Value.Y;
- }
-
- if (scale.HasValue)
- {
- var scaleMatrix = CreateScale(scale.Value);
- transformMatrix = Multiply(transformMatrix, scaleMatrix);
- }
-
- // ReSharper disable once CompareOfFloatsByEqualityOperator
- if (rotation != 0f)
- {
- var rotationMatrix = CreateRotationZ(-rotation);
- transformMatrix = Multiply(transformMatrix, rotationMatrix);
- }
-
- var translationMatrix = CreateTranslation(position);
- transformMatrix = Multiply(transformMatrix, translationMatrix);
-
- return transformMatrix;
- }
-
- ///
- /// Initializes a new instance of the struct that can be used to rotate a set of vertices
- /// around the z-axis.
- ///
- /// The amount, in radians, in which to rotate around the z-axis.
- /// The resulting .
- public static Matrix2 CreateRotationZ(float radians)
- {
- Matrix2 result;
- CreateRotationZ(radians, out result);
- return result;
- }
-
- ///
- /// Calculates the struct that can be used to rotate a set of vertices around the z-axis.
- ///
- /// The amount, in radians, in which to rotate around the z-axis.
- /// The resulting .
- public static void CreateRotationZ(float radians, out Matrix2 result)
- {
- var val1 = (float)Math.Cos(radians);
- var val2 = (float)Math.Sin(radians);
-
- result = new Matrix2
- {
- M11 = val1,
- M12 = val2,
- M21 = -val2,
- M22 = val1,
- M31 = 0,
- M32 = 0
- };
- }
-
- ///
- /// Initializes a new instance of the struct that can be used to scale a set vertices.
- ///
- /// The amount to scale by on the x and y axes.
- /// The resulting .
- public static Matrix2 CreateScale(float scale)
- {
- Matrix2 result;
- CreateScale(scale, scale, out result);
- return result;
- }
-
- ///
- /// Calculates the struct that can be used to scale a set vertices.
- ///
- /// The amount to scale by on the x and y axes.
- /// The resulting .
- public static void CreateScale(float scale, out Matrix2 result)
- {
- CreateScale(scale, scale, out result);
- }
-
- ///
- /// Initializes a new instance of the struct that can be used to scale a set vertices.
- ///
- /// The amount to scale by on the x-axis.
- /// The amount to scale by on the y-axis.
- /// The resulting .
- public static Matrix2 CreateScale(float xScale, float yScale)
- {
- Matrix2 result;
- CreateScale(xScale, yScale, out result);
- return result;
- }
-
- ///
- /// Calculates the struct that can be used to scale a set vertices.
- ///
- /// The amount to scale by on the x-axis.
- /// The amount to scale by on the y-axis.
- /// The resulting .
- public static void CreateScale(float xScale, float yScale, out Matrix2 result)
- {
- result = new Matrix2
- {
- M11 = xScale,
- M12 = 0,
- M21 = 0,
- M22 = yScale,
- M31 = 0,
- M32 = 0
- };
- }
-
- ///
- /// Initializes a new instance of the struct that can be used to scale a set vertices.
- ///
- /// The amounts to scale by on the x and y axes.
- /// The resulting .
- public static Matrix2 CreateScale(Vector2 scale)
- {
- Matrix2 result;
- CreateScale(ref scale, out result);
- return result;
- }
-
- ///
- /// Calculates the struct that can be used to scale a set vertices.
- ///
- /// The amounts to scale by on the x and y axes.
- /// The resulting .
- public static void CreateScale(ref Vector2 scale, out Matrix2 result)
- {
- result = new Matrix2
- {
- M11 = scale.X,
- M12 = 0,
- M21 = 0,
- M22 = scale.Y,
- M31 = 0,
- M32 = 0
- };
- }
-
- ///
- /// Initializes a new instance of the struct that can be used to translate a set vertices.
- ///
- /// The amount to translate by on the x-axis.
- /// The amount to translate by on the y-axis.
- /// The resulting .
- public static Matrix2 CreateTranslation(float xPosition, float yPosition)
- {
- Matrix2 result;
- CreateTranslation(xPosition, yPosition, out result);
- return result;
- }
-
- ///
- /// Calculates the struct that can be used to translate a set vertices.
- ///
- /// The amount to translate by on the x-axis.
- /// The amount to translate by on the y-axis.
- /// The resulting .
- public static void CreateTranslation(float xPosition, float yPosition, out Matrix2 result)
- {
- result = new Matrix2
- {
- M11 = 1,
- M12 = 0,
- M21 = 0,
- M22 = 1,
- M31 = xPosition,
- M32 = yPosition
- };
- }
-
- ///
- /// Initializes a new instance of the struct that can be used to translate a set vertices.
- ///
- /// The amounts to translate by on the x and y axes.
- /// The resulting .
- public static Matrix2 CreateTranslation(Vector2 position)
- {
- Matrix2 result;
- CreateTranslation(ref position, out result);
- return result;
- }
-
- ///
- /// Calculates the struct that can be used to translate a set vertices.
- ///
- /// The amounts to translate by on the x and y axes.
- /// The resulting .
- public static void CreateTranslation(ref Vector2 position, out Matrix2 result)
- {
- result = new Matrix2
- {
- M11 = 1,
- M12 = 0,
- M21 = 0,
- M22 = 1,
- M31 = position.X,
- M32 = position.Y
- };
- }
-
- ///
- /// Calculates the determinant of the .
- ///
- /// The determinant of the .
- public float Determinant()
- {
- return M11 * M22 - M12 * M21;
- }
-
- ///
- /// Initializes a new instance of the struct with the summation of two
- /// s.
- ///
- /// The first .
- /// The second .
- /// The resulting .
- public static Matrix2 Add(Matrix2 matrix1, Matrix2 matrix2)
- {
- matrix1.M11 += matrix2.M11;
- matrix1.M12 += matrix2.M12;
-
- matrix1.M21 += matrix2.M21;
- matrix1.M22 += matrix2.M22;
-
- matrix1.M31 += matrix2.M31;
- matrix1.M32 += matrix2.M32;
-
- return matrix1;
- }
-
- ///
- /// Calculates the summation of two s.
- ///
- /// The first .
- /// The second .
- /// The resulting .
- public static void Add(ref Matrix2 matrix1, ref Matrix2 matrix2, out Matrix2 result)
- {
- result = new Matrix2
- {
- M11 = matrix1.M11 + matrix2.M11,
- M12 = matrix1.M12 + matrix2.M12,
- M21 = matrix1.M21 + matrix2.M21,
- M22 = matrix1.M22 + matrix2.M22,
- M31 = matrix1.M31 + matrix2.M31,
- M32 = matrix1.M32 + matrix2.M32
- };
- }
-
- ///
- /// Initializes a new instance of the struct with the summation of two
- /// s.
- ///
- /// The first .
- /// The second .
- /// The resulting .
- public static Matrix2 operator +(Matrix2 matrix1, Matrix2 matrix2)
- {
- matrix1.M11 = matrix1.M11 + matrix2.M11;
- matrix1.M12 = matrix1.M12 + matrix2.M12;
-
- matrix1.M21 = matrix1.M21 + matrix2.M21;
- matrix1.M22 = matrix1.M22 + matrix2.M22;
-
- matrix1.M31 = matrix1.M31 + matrix2.M31;
- matrix1.M32 = matrix1.M32 + matrix2.M32;
-
- return matrix1;
- }
-
- ///
- /// Initializes a new instance of the struct with the substraction of two
- ///
- /// s.
- ///
- /// The first .
- /// The second .
- /// The resulting .
- public static Matrix2 Subtract(Matrix2 matrix1, Matrix2 matrix2)
- {
- matrix1.M11 = matrix1.M11 - matrix2.M11;
- matrix1.M12 = matrix1.M12 - matrix2.M12;
-
- matrix1.M21 = matrix1.M21 - matrix2.M21;
- matrix1.M22 = matrix1.M22 - matrix2.M22;
-
- matrix1.M31 = matrix1.M31 - matrix2.M31;
- matrix1.M32 = matrix1.M32 - matrix2.M32;
- return matrix1;
- }
-
- ///
- /// Calculates the substraction of two s.
- ///
- /// The first .
- /// The second .
- /// The resulting .
- public static void Subtract(ref Matrix2 matrix1, ref Matrix2 matrix2, out Matrix2 result)
- {
- result = new Matrix2
- {
- M11 = matrix1.M11 - matrix2.M11,
- M12 = matrix1.M12 - matrix2.M12,
- M21 = matrix1.M21 - matrix2.M21,
- M22 = matrix1.M22 - matrix2.M22,
- M31 = matrix1.M31 - matrix2.M31,
- M32 = matrix1.M32 - matrix2.M32
- };
- }
-
- ///
- /// Initializes a new instance of the struct with the substraction of two
- ///
- /// s.
- ///
- /// The first .
- /// The second .
- /// The resulting .
- public static Matrix2 operator -(Matrix2 matrix1, Matrix2 matrix2)
- {
- matrix1.M11 = matrix1.M11 - matrix2.M11;
- matrix1.M12 = matrix1.M12 - matrix2.M12;
-
- matrix1.M21 = matrix1.M21 - matrix2.M21;
- matrix1.M22 = matrix1.M22 - matrix2.M22;
-
- matrix1.M31 = matrix1.M31 - matrix2.M31;
- matrix1.M32 = matrix1.M32 - matrix2.M32;
- return matrix1;
- }
-
- ///
- /// Initializes a new instance of the struct with the multiplication of two
- ///
- /// s.
- ///
- /// The first .
- /// The second .
- /// The resulting .
- public static Matrix2 Multiply(Matrix2 matrix1, Matrix2 matrix2)
- {
- var m11 = matrix1.M11 * matrix2.M11 + matrix1.M12 * matrix2.M21;
- var m12 = matrix1.M11 * matrix2.M12 + matrix1.M12 * matrix2.M22;
-
- var m21 = matrix1.M21 * matrix2.M11 + matrix1.M22 * matrix2.M21;
- var m22 = matrix1.M21 * matrix2.M12 + matrix1.M22 * matrix2.M22;
-
- var m31 = matrix1.M31 * matrix2.M11 + matrix1.M32 * matrix2.M21 + matrix2.M31;
- var m32 = matrix1.M31 * matrix2.M12 + matrix1.M32 * matrix2.M22 + matrix2.M32;
-
- matrix1.M11 = m11;
- matrix1.M12 = m12;
-
- matrix1.M21 = m21;
- matrix1.M22 = m22;
-
- matrix1.M31 = m31;
- matrix1.M32 = m32;
-
- return matrix1;
- }
-
- ///
- /// Calculates the multiplication of two s.
- ///
- /// The first .
- /// The second .
- /// The resulting .
- public static void Multiply(ref Matrix2 matrix1, ref Matrix2 matrix2, out Matrix2 result)
- {
- var m11 = matrix1.M11 * matrix2.M11 + matrix1.M12 * matrix2.M21;
- var m12 = matrix1.M11 * matrix2.M12 + matrix1.M12 * matrix2.M22;
-
- var m21 = matrix1.M21 * matrix2.M11 + matrix1.M22 * matrix2.M21;
- var m22 = matrix1.M21 * matrix2.M12 + matrix1.M22 * matrix2.M22;
-
- var m31 = matrix1.M31 * matrix2.M11 + matrix1.M32 * matrix2.M21 + matrix2.M31;
- var m32 = matrix1.M31 * matrix2.M12 + matrix1.M32 * matrix2.M22 + matrix2.M32;
-
- result = new Matrix2
- {
- M11 = m11,
- M12 = m12,
- M21 = m21,
- M22 = m22,
- M31 = m31,
- M32 = m32
- };
- }
-
- ///
- /// Initializes a new instance of the struct with the division of a by
- /// a scalar.
- ///
- /// The .
- /// The amount to divide the by.
- /// The resulting .
- public static Matrix2 Multiply(Matrix2 matrix, float scalar)
- {
- matrix.M11 *= scalar;
- matrix.M12 *= scalar;
-
- matrix.M21 *= scalar;
- matrix.M22 *= scalar;
-
- matrix.M31 *= scalar;
- matrix.M32 *= scalar;
- return matrix;
- }
-
- ///
- /// Calculates the multiplication of a by a scalar.
- ///
- /// The .
- /// The amount to multiple the by.
- /// The resulting .
- public static void Multiply(ref Matrix2 matrix, float scalar, out Matrix2 result)
- {
- result = new Matrix2
- {
- M11 = matrix.M11 * scalar,
- M12 = matrix.M12 * scalar,
- M21 = matrix.M21 * scalar,
- M22 = matrix.M22 * scalar,
- M31 = matrix.M31 * scalar,
- M32 = matrix.M32 * scalar
- };
- }
-
- ///
- /// Initializes a new instance of the struct with the multiplication of two
- ///
- /// s.
- ///
- /// The first .
- /// The second .
- /// The resulting .
- public static Matrix2 operator *(Matrix2 matrix1, Matrix2 matrix2)
- {
- var m11 = matrix1.M11 * matrix2.M11 + matrix1.M12 * matrix2.M21;
- var m12 = matrix1.M11 * matrix2.M12 + matrix1.M12 * matrix2.M22;
-
- var m21 = matrix1.M21 * matrix2.M11 + matrix1.M22 * matrix2.M21;
- var m22 = matrix1.M21 * matrix2.M12 + matrix1.M22 * matrix2.M22;
-
- var m31 = matrix1.M31 * matrix2.M11 + matrix1.M32 * matrix2.M21 + matrix2.M31;
- var m32 = matrix1.M31 * matrix2.M12 + matrix1.M32 * matrix2.M22 + matrix2.M32;
-
- matrix1.M11 = m11;
- matrix1.M12 = m12;
-
- matrix1.M21 = m21;
- matrix1.M22 = m22;
-
- matrix1.M31 = m31;
- matrix1.M32 = m32;
-
- return matrix1;
- }
-
- ///
- /// Initializes a new instance of the struct with the division of a by
- /// a scalar.
- ///
- /// The .
- /// The amount to divide the by.
- /// The resulting .
- public static Matrix2 operator *(Matrix2 matrix, float scalar)
- {
- matrix.M11 = matrix.M11 * scalar;
- matrix.M12 = matrix.M12 * scalar;
-
- matrix.M21 = matrix.M21 * scalar;
- matrix.M22 = matrix.M22 * scalar;
-
- matrix.M31 = matrix.M31 * scalar;
- matrix.M32 = matrix.M32 * scalar;
-
- return matrix;
- }
-
- ///
- /// Initializes a new instance of the struct with the division of two
- /// s.
- ///
- /// The first .
- /// The second .
- /// The resulting .
- public static Matrix2 Divide(Matrix2 matrix1, Matrix2 matrix2)
- {
- matrix1.M11 = matrix1.M11 / matrix2.M11;
- matrix1.M12 = matrix1.M12 / matrix2.M12;
-
- matrix1.M21 = matrix1.M21 / matrix2.M21;
- matrix1.M22 = matrix1.M22 / matrix2.M22;
-
- matrix1.M31 = matrix1.M31 / matrix2.M31;
- matrix1.M32 = matrix1.M32 / matrix2.M32;
- return matrix1;
- }
-
- ///
- /// Calculates the division of two s.
- ///
- /// The first .
- /// The second .
- /// The resulting .
- public static void Divide(ref Matrix2 matrix1, ref Matrix2 matrix2, out Matrix2 result)
- {
- result = new Matrix2
- {
- M11 = matrix1.M11 / matrix2.M11,
- M12 = matrix1.M12 / matrix2.M12,
- M21 = matrix1.M21 / matrix2.M21,
- M22 = matrix1.M22 / matrix2.M22,
- M31 = matrix1.M31 / matrix2.M31,
- M32 = matrix1.M32 / matrix2.M32
- };
- }
-
- ///
- /// Initializes a new instance of the struct with the division of a by
- /// a scalar.
- ///
- /// The .
- /// The amount to divide the by.
- /// The resulting .
- public static Matrix2 Divide(Matrix2 matrix, float scalar)
- {
- var num = 1f / scalar;
- matrix.M11 = matrix.M11 * num;
- matrix.M12 = matrix.M12 * num;
-
- matrix.M21 = matrix.M21 * num;
- matrix.M22 = matrix.M22 * num;
-
- matrix.M31 = matrix.M31 * num;
- matrix.M32 = matrix.M32 * num;
-
- return matrix;
- }
-
- ///
- /// Calculates the division of a by a scalar.
- ///
- /// The .
- /// The amount to divide the by.
- /// The resulting .
- public static void Divide(ref Matrix2 matrix, float scalar, out Matrix2 result)
- {
- var num = 1f / scalar;
- result = new Matrix2
- {
- M11 = matrix.M11 * num,
- M12 = matrix.M12 * num,
- M21 = matrix.M21 * num,
- M22 = matrix.M22 * num,
- M31 = matrix.M31 * num,
- M32 = matrix.M32 * num
- };
- }
-
- ///
- /// Initializes a new instance of the struct with the division of two
- /// s.
- ///
- /// The first .
- /// The second .
- /// The resulting .
- public static Matrix2 operator /(Matrix2 matrix1, Matrix2 matrix2)
- {
- matrix1.M11 = matrix1.M11 / matrix2.M11;
- matrix1.M12 = matrix1.M12 / matrix2.M12;
-
- matrix1.M21 = matrix1.M21 / matrix2.M21;
- matrix1.M22 = matrix1.M22 / matrix2.M22;
-
- matrix1.M31 = matrix1.M31 / matrix2.M31;
- matrix1.M32 = matrix1.M32 / matrix2.M32;
- return matrix1;
- }
-
- ///
- /// Initializes a new instance of the struct with the division of a by
- /// a scalar.
- ///
- /// The .
- /// The amount to divide the by.
- /// The resulting .
- public static Matrix2 operator /(Matrix2 matrix, float scalar)
- {
- var num = 1f / scalar;
- matrix.M11 = matrix.M11 * num;
- matrix.M12 = matrix.M12 * num;
-
- matrix.M21 = matrix.M21 * num;
- matrix.M22 = matrix.M22 * num;
-
- matrix.M31 = matrix.M31 * num;
- matrix.M32 = matrix.M32 * num;
- return matrix;
- }
-
- ///
- /// Initializes a new instance of the struct with the inversion of a .
- ///
- /// The .
- /// The resulting .
- public static Matrix2 Invert(Matrix2 matrix)
- {
- var det = 1 / matrix.Determinant();
-
- var m11 = matrix.M22 * det;
- var m12 = -matrix.M12 * det;
-
- var m21 = -matrix.M21 * det;
- var m22 = matrix.M11 * det;
-
- var m31 = (matrix.M32 * matrix.M21 - matrix.M31 * matrix.M22) * det;
- var m32 = -(matrix.M32 * matrix.M11 - matrix.M31 * matrix.M12) * det;
-
- return new Matrix2(m11, m12, m21, m22, m31, m32);
- }
-
- ///
- /// Calculates the inversion of a .
- ///
- /// The .
- /// The resulting .
- public static void Invert(ref Matrix2 matrix, out Matrix2 result)
- {
- var det = 1 / matrix.Determinant();
-
- result = new Matrix2
- {
- M11 = matrix.M22 * det,
- M12 = -matrix.M12 * det,
- M21 = -matrix.M21 * det,
- M22 = matrix.M11 * det,
- M31 = (matrix.M32 * matrix.M21 - matrix.M31 * matrix.M22) * det,
- M32 = -(matrix.M32 * matrix.M11 - matrix.M31 * matrix.M12) * det
- };
- }
-
- ///
- /// Initializes a new instance of the struct with the inversion of a .
- ///
- /// The .
- /// The resulting .
- public static Matrix2 operator -(Matrix2 matrix)
- {
- matrix.M11 = -matrix.M11;
- matrix.M12 = -matrix.M12;
-
- matrix.M21 = -matrix.M21;
- matrix.M22 = -matrix.M22;
-
- matrix.M31 = -matrix.M31;
- matrix.M32 = -matrix.M32;
- return matrix;
- }
-
- ///
- /// Compares a for equality with another without any tolerance.
- ///
- /// The first .
- /// The second .
- /// true if the s are equal; false otherwise.
- public static bool operator ==(Matrix2 matrix1, Matrix2 matrix2)
- {
- return (matrix1.M11 == matrix2.M11) && (matrix1.M12 == matrix2.M12) && (matrix1.M21 == matrix2.M21) &&
- (matrix1.M22 == matrix2.M22) && (matrix1.M31 == matrix2.M31) && (matrix1.M32 == matrix2.M32);
- }
-
- ///
- /// Compares a for inequality with another without any tolerance.
- ///
- /// The first .
- /// The second .
- /// true if the s are not equal; false otherwise.
- public static bool operator !=(Matrix2 matrix1, Matrix2 matrix2)
- {
- return (matrix1.M11 != matrix2.M11) || (matrix1.M12 != matrix2.M12) || (matrix1.M21 != matrix2.M21) ||
- (matrix1.M22 != matrix2.M22) || (matrix1.M31 != matrix2.M31) || (matrix1.M32 != matrix2.M32);
- }
-
- ///
- /// Returns a value that indicates whether the current is equal to a specified
- /// .
- ///
- /// The with which to make the comparison.
- ///
- /// true if the current is equal to the specified ;
- /// false otherwise.
- ///
- public bool Equals(ref Matrix2 matrix)
- {
- return (M11 == matrix.M11) && (M12 == matrix.M12) && (M21 == matrix.M21) && (M22 == matrix.M22) &&
- (M31 == matrix.M31) && (M32 == matrix.M32);
- }
-
- ///
- /// Returns a value that indicates whether the current is equal to a specified
- /// .
- ///
- /// The with which to make the comparison.
- ///
- /// true if the current is equal to the specified ;
- /// false otherwise.
- ///
- public bool Equals(Matrix2 matrix)
- {
- return Equals(ref matrix);
- }
-
- ///
- /// Returns a value that indicates whether the current is equal to a specified object.
- ///
- /// The object with which to make the comparison.
- ///
- /// true if the current is equal to the specified object;
- /// false otherwise.
- ///
- public override bool Equals(object obj)
- {
- return obj is Matrix2 && Equals((Matrix2)obj);
- }
-
- ///
- /// Returns a hash code for this .
- ///
- ///
- /// A hash code for this , suitable for use in hashing algorithms and data structures like a
- /// hash table.
- ///
- public override int GetHashCode()
- {
- // ReSharper disable NonReadonlyMemberInGetHashCode
- return M11.GetHashCode() + M12.GetHashCode() + M21.GetHashCode() + M22.GetHashCode() + M31.GetHashCode() +
- M32.GetHashCode();
- // ReSharper restore NonReadonlyMemberInGetHashCode
- }
-
- ///
- /// Performs an implicit conversion from to .
- ///
- /// The .
- ///
- /// The resulting .
- ///
- public static implicit operator Matrix(Matrix2 matrix)
- {
- return new Matrix(matrix.M11, matrix.M12, 0, 0, matrix.M21, matrix.M22, 0, 0, 0, 0, 1, 0, matrix.M31,
- matrix.M32, 0, 1);
- }
-
- ///
- /// Performs an explicit conversion from a specified to a .
- ///
- /// The .
- /// The depth value.
- /// The resulting .
- public static void ToMatrix(ref Matrix2 matrix, float depth, out Matrix result)
- {
- result.M11 = matrix.M11;
- result.M12 = matrix.M12;
- result.M13 = 0;
- result.M14 = 0;
-
- result.M21 = matrix.M21;
- result.M22 = matrix.M22;
- result.M23 = 0;
- result.M24 = 0;
-
- result.M31 = 0;
- result.M32 = 0;
- result.M33 = 1;
- result.M34 = 0;
-
- result.M41 = matrix.M31;
- result.M42 = matrix.M32;
- result.M43 = depth;
- result.M44 = 1;
- }
-
- ///
- /// Performs an explicit conversion from a specified to a .
- ///
- /// The depth value.
- /// The resulting .
- public Matrix ToMatrix(float depth = 0)
- {
- Matrix result;
- ToMatrix(ref this, depth, out result);
- return result;
- }
-
- ///
- /// Gets the debug display string.
- ///
- ///
- /// The debug display string.
- ///
- internal string DebugDisplayString => this == Identity
- ? "Identity"
- : $"T:({Translation.X:0.##},{Translation.Y:0.##}), R:{MathHelper.ToDegrees(Rotation):0.##}°, S:({Scale.X:0.##},{Scale.Y:0.##})"
- ;
-
- ///
- /// Returns a that represents this .
- ///
- ///
- /// A that represents this .
- ///
- public override string ToString()
- {
- return $"{{M11:{M11} M12:{M12}}} {{M21:{M21} M22:{M22}}} {{M31:{M31} M32:{M32}}}";
- }
- }
-}
\ No newline at end of file
diff --git a/source/MonoGame.Extended/Math/Matrix3x2.cs b/source/MonoGame.Extended/Math/Matrix3x2.cs
new file mode 100644
index 000000000..3a6d52098
--- /dev/null
+++ b/source/MonoGame.Extended/Math/Matrix3x2.cs
@@ -0,0 +1,1082 @@
+using System;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.CompilerServices;
+using Microsoft.Xna.Framework;
+
+namespace MonoGame.Extended;
+
+///
+/// Represents a 3x2 matrix using floating point values for each component that can store two dimensional translation,
+/// scale, and rotation information for a right-handed coordinate system.
+///
+///
+///
+/// Matrices use a row vector layout in the XNA / MonoGame Framework but, in general, matrices can be either
+/// have a row vector or column vector layout. Row vector matrices view vectors as a row from left to right,
+/// while column vector matrices view vectors as a column from top to bottom. For example, the
+/// corresponds to the fields and .
+///
+///
+/// The fields see M13 and M23 always have a value of 0.0f, and thus are removed from
+/// the to reduce its memory footprint. Same is true for the field M33, except
+/// it always has a value of 1.0f.
+///
+///
+[DebuggerDisplay($"{nameof(DebugDisplayString)},nq")]
+public struct Matrix3x2 : IEquatable
+{
+ /// The first element of the first row.
+ /// Represents the scaling factor on the x-axis or a combination of scaling and rotation.
+ public float M11;
+
+ /// The second element of the first row.
+ /// Represents the shearing factor on the y-axis or a combination of shearing and rotation.
+ public float M12;
+
+ /// The first element of the second row.
+ /// Represents the shearing factor on the x-axis or a combination of shear and rotation.
+ public float M21;
+
+ /// The second element of the second row.
+ /// Represents the scaling factor on the y-axis or a combination of scale and rotation.
+ public float M22;
+
+ /// The first element of the third row.
+ /// Represents the translation on the x-axis
+ public float M31;
+
+ /// The second element of the third row.
+ /// Represents the translation on the y-axis
+ public float M32;
+
+ ///
+ /// Gets or Sets the vector formed by the first row of this
+ ///
+ ///
+ ///
+ /// The component of the vector represents the scaling factor on the x-axis or a
+ /// combination of scaling and rotation.
+ ///
+ ///
+ /// The component of the vector represents the shearing factor on the y-axis or a
+ /// combination of shearing and rotation.
+ ///
+ ///
+ public Vector2 X
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ readonly get => Unsafe.As(ref Unsafe.AsRef(in M11));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set => Unsafe.As(ref M11) = value;
+ }
+
+ ///
+ /// Gets the vector formed by the second row of this
+ ///
+ ///
+ ///
+ /// The component of the vector represents the shearing factor on the x-axis or a
+ /// combination of shearing and rotation.
+ ///
+ ///
+ /// The component of the vector represents the scaling factor on the y-axis or a
+ /// combination of scaling and rotation.
+ ///
+ ///
+ public Vector2 Y
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ readonly get => Unsafe.As(ref Unsafe.AsRef(in M21));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set => Unsafe.As(ref M21) = value;
+ }
+
+ ///
+ /// Gets or Sets the vector formed by the third row of this
+ ///
+ ///
+ ///
+ /// The component of the vector represents the translation on the x-axis.
+ ///
+ ///
+ /// The component of the vector represents the translation on the y-axis.
+ ///
+ ///
+ public Vector2 Z
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ readonly get => Unsafe.As(ref Unsafe.AsRef(in M31));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set => Unsafe.As(ref M31) = value;
+ }
+
+ ///
+ /// Gets the multiplicative identity matrix.
+ ///
+ ///
+ /// The first row of the identity matrix is equal to
+ /// The second row of the identity matrix is equal to
+ /// The third row of the identity matrix is equal to
+ ///
+ public static readonly Matrix3x2 Identity = new Matrix3x2(Vector2.UnitX, Vector2.UnitY, Vector2.Zero);
+
+ ///
+ /// Gets the translation component of this .
+ ///
+ ///
+ /// The translation is equal to the third row vector composed of the and
+ /// values.
+ ///
+ [Obsolete("Use Decompose method. This property will be removed in 4.0")]
+ public readonly Vector2 Translation
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => Z;
+ }
+
+ ///
+ /// Gets the rotation component of this .
+ ///
+ ///
+ /// The rotation is equal to the arctangent of the and .
+ /// Math.Atan2(M21, M11);
+ ///
+ [Obsolete("Use Decompose method. This property will be removed in 4.0")]
+ public readonly float Rotation
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => (float)Math.Atan2(M21, M11);
+ }
+
+ ///
+ /// Gets the scale component of this .
+ ///
+ ///
+ /// The scale is equal to equal to the square root of the sum of the squares of matrix elements, with sign
+ /// adjustment.
+ ///
+ [Obsolete("Use Decompose method. This property will be removed in 4.0")]
+ public readonly Vector2 Scale
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get
+ {
+ var xSign = Math.Sign((M11 * M11) + (M21 * M21)) < 0 ? -1 : 1;
+ var ySign = Math.Sign((M11 * M12) + (M22 * M22)) < 0 ? -1 : 1;
+
+ Vector2 scale;
+ scale.X = xSign * (float)Math.Sqrt((M11 * M11) + (M21 * M21));
+ scale.Y = ySign * (float)Math.Sqrt((M11 * M12) + (M22 * M22));
+
+ return scale;
+ }
+ }
+
+ ///
+ /// Creates a 3x2 matrix from the specified components.
+ ///
+ /// The value to assign to the first element of the first row.
+ /// The value to assign to the second element of the first row.
+ /// The value to assign to the first element of the second row.
+ /// The value to assign to the second element of the second row.
+ /// The value to assign to the first element of the third row.
+ /// The value to assign to the second element of the third row.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Matrix3x2(float m11, float m12,
+ float m21, float m22,
+ float m31, float m32)
+ {
+ M11 = m11;
+ M12 = m12;
+ M21 = m21;
+ M22 = m22;
+ M31 = m31;
+ M32 = m32;
+ }
+
+ ///
+ /// Creates a new 3x2 matrix from the specified components.
+ ///
+ /// The value to assign to the elements of the first row.
+ /// The value to assign to the elements of the second row.
+ /// The value to assign to the elements of the third row.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Matrix3x2(Vector2 x, Vector2 y, Vector2 z)
+ : this(x.X, x.Y, y.X, y.Y, z.X, z.Y) { }
+
+
+ ///
+ /// Transforms the given vector by this
+ ///
+ /// The vector to transform.
+ /// The result of the transformation.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Vector2 Transform(Vector2 vector) => Transform(vector.X, vector.Y);
+
+ ///
+ /// Transforms the given vector by this
+ ///
+ /// The vector to transform.
+ ///
+ /// When this method returns, contains the result of the transformation. This parameter is passed uninitialized.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Transform(Vector2 vector, out Vector2 result) => Transform(vector.X, vector.Y, out result);
+
+ ///
+ /// Transforms a vector with the specified x- and y-coordinate component values by this
+ ///
+ /// The x-coordinate component value of the vector to transform.
+ /// The y-coordinate component value of the vector to transform.
+ /// The result of the transformation.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Vector2 Transform(in float x, in float y)
+ {
+ Vector2 result;
+ Transform(x, y, out result);
+ return result;
+ }
+
+ ///
+ /// Transforms a vector with the specified x- and y-coordinate component values by this
+ ///
+ /// The x-coordinate component value of the vector to transform.
+ /// The y-coordinate component value of the vector to transform.
+ ///
+ /// When this method returns, contains the result of the transformation. This parameter is passed uninitialized.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Transform(in float x, in float y, out Vector2 result)
+ {
+ result.X = (x * M11) + (y * M21) + M31;
+ result.Y = (x * M12) + (y * M22) + M32;
+ }
+
+ ///
+ /// Transforms a vector with the specified x- and y-coordinate component values by this
+ ///
+ /// The x-coordinate component value of the vector to transform.
+ /// The y-coordinate component value of the vector to transform.
+ /// When this method returns, contains the result of the transformation.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Transform(in float x, in float y, ref Vector3 result)
+ {
+ result.X = (x * M11) + (y * M21) + M31;
+ result.Y = (x * M12) + (y * M22) + M32;
+ }
+
+ ///
+ /// Calculates the determinant of this .
+ ///
+ ///
+ /// The determinant is calculated by expanding this matrix with a third column whose values are (0, 0, 1).
+ ///
+ /// The determinant of this .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public float Determinant() => (M11 * M22) - (M12 * M21);
+
+ ///
+ /// Deconstructs this into its translation, rotation, and scale component representations.
+ ///
+ ///
+ /// When this method returns, contains the translation component of this . This parameter is
+ /// passed uninitialized.
+ ///
+ ///
+ /// When this method returns, contains the rotation component of this . This parameter is
+ /// passed uninitialized.
+ ///
+ ///
+ /// When this method returns, contains the scale component of this . This parameter is
+ /// passed uninitialized.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Decompose(out Vector2 translation, out float rotation, out Vector2 scale)
+ {
+ translation.X = M31;
+ translation.Y = M31;
+
+ rotation = (float)Math.Atan2(M21, M11);
+
+ var x = M11 * M11 + M21 * M21;
+ var y = M12 * M12 + M22 * M22;
+
+ var xSign = Math.Sign(x) < 0 ? -1 : 1;
+ var ySign = Math.Sign(y) < 0 ? -1 : 1;
+
+ scale.X = xSign * (float)Math.Sqrt(x);
+ scale.Y = ySign * (float)Math.Sqrt(y);
+ }
+
+ ///
+ /// Creates a new value for 2D translation, rotation, and scale.
+ ///
+ /// Rotation is performed along the z-axis.
+ /// The amount to translate the matrix by on the x- and y-axis.
+ /// The amount to rotate, in radians, the matrix along the z-axis.
+ /// The amount to scale the matrix along the x- and y-axis.
+ /// The origin point at which to scale and rotate the matrix around.
+ /// The resulting value created by this method.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Matrix3x2 CreateFrom(Vector2 position, in float rotation, Vector2? scale, Vector2? origin)
+ {
+ CreateFrom(position, rotation, scale, origin, out Matrix3x2 result);
+ return result;
+ }
+
+ ///
+ /// Creates a new value for 2D translation, rotation, and scale.
+ ///
+ /// Rotation is performed along the z-axis.
+ /// The amount to translate the matrix by on the x- and y-axis.
+ /// The amount to rotate, in radians, the matrix along the z-axis.
+ /// The amount to scale the matrix along the x- and y-axis.
+ /// The origin point at which to scale and rotate the matrix around.
+ ///
+ /// When this method returns, contains the resulting value for 2D translation rotation, and
+ /// scale. This parameter is passed uninitialized.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void CreateFrom(Vector2 position, in float rotation, Vector2? scale, Vector2? origin, out Matrix3x2 result)
+ {
+ result = Identity;
+
+ if (origin.HasValue)
+ {
+ result.Z = -origin.Value;
+ }
+
+ if (scale.HasValue)
+ {
+ CreateScale(scale.Value, out Matrix3x2 scaleMatrix);
+ Multiply(result, scaleMatrix, out result);
+ }
+
+ if (rotation != 0.0f)
+ {
+ CreateRotationZ(-rotation, out Matrix3x2 rotationMatrix);
+ Multiply(result, rotationMatrix, out result);
+ }
+
+ CreateTranslation(position, out Matrix3x2 translationMatrix);
+ Multiply(result, translationMatrix, out result);
+ }
+
+ ///
+ /// Creates a value for 2D rotation.
+ ///
+ /// Rotation is performed along the z-axis.
+ /// The mount to rotate, in radians, the matrix along the z-axis.
+ /// The resulting value created by this method.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Matrix3x2 CreateRotationZ(in float radians)
+ {
+ CreateRotationZ(radians, out Matrix3x2 result);
+ return result;
+ }
+
+ ///
+ /// Creates a value for 2D rotation.
+ ///
+ /// Rotation is performed along the z-axis.
+ /// The mount to rotate, in radians, the matrix along the z-axis.
+ ///
+ /// When this method returns, contains the resulting value for 2D rotation. This parameter
+ /// is passed uninitialized.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void CreateRotationZ(in float radians, out Matrix3x2 result)
+ {
+ var cos = (float)Math.Cos(radians);
+ var sin = (float)Math.Sin(radians);
+
+ result.M11 = cos;
+ result.M12 = sin;
+
+ result.M21 = -sin;
+ result.M22 = cos;
+
+ result.M31 = 0;
+ result.M32 = 0;
+ }
+
+ ///
+ /// Creates a value for 2D scaling.
+ ///
+ /// The amount to scale the matrix along the x- and y-axis.
+ /// The value created by this method.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Matrix3x2 CreateScale(in float scale)
+ {
+ CreateScale(scale, scale, out Matrix3x2 result);
+ return result;
+ }
+
+ ///
+ /// Creates a value for 2D scaling.
+ ///
+ /// The amount to scale the matrix along the x- and y-axis.
+ ///
+ /// When this method returns, contains the resulting value for 2D scaling created. This
+ /// parameter is passed uninitialized.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void CreateScale(in float scale, out Matrix3x2 result) => CreateScale(scale, scale, out result);
+
+ ///
+ /// Creates a value for 2D scaling.
+ ///
+ /// A vector that represents the x- and y-axis scale factors.
+ /// The value created by this method.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Matrix3x2 CreateScale(Vector2 scale)
+ {
+ CreateScale(scale.X, scale.Y, out Matrix3x2 result);
+ return result;
+ }
+
+ ///
+ /// Creates a value for 2D scaling.
+ ///
+ /// A vector that represents the x- and y-axis scale factors.
+ ///
+ /// When this method returns, contains the resulting value for 2D scaling. This parameter
+ /// is passed uninitialized.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void CreateScale(in Vector2 scale, out Matrix3x2 result) =>
+ CreateScale(scale.X, scale.Y, out result);
+
+ ///
+ /// Creates a value for 2D scaling.
+ ///
+ /// The scale factor for the x-axis.
+ /// The scale factor for the y-axis.
+ /// The value created by this method.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Matrix3x2 CreateScale(in float xScale, in float yScale)
+ {
+ CreateScale(xScale, yScale, out Matrix3x2 result);
+ return result;
+ }
+
+ ///
+ /// Creates a value for 2D scaling.
+ ///
+ /// The scale factor for the x-axis.
+ /// The scale factor for the y-axis.
+ ///
+ /// When this method returns, contains the resulting value for 2D scaling. This parameter
+ /// is passed uninitialized.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void CreateScale(in float xScale, in float yScale, out Matrix3x2 result)
+ {
+ result.M11 = xScale;
+ result.M12 = 0;
+
+ result.M21 = 0;
+ result.M22 = yScale;
+
+ result.M31 = 0;
+ result.M32 = 0;
+ }
+
+ ///
+ /// Creates a value for 2D translation.
+ ///
+ /// The translation vector
+ /// The resulting value for 2D translation.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Matrix3x2 CreateTranslation(Vector2 vector) => CreateTranslation(vector.X, vector.Y);
+
+ ///
+ /// Creates a for 2D translation.
+ ///
+ /// The translation vector
+ ///
+ /// When this method returns, contains the resulting value for 2D translation. This
+ /// parameter is passed uninitialized.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void CreateTranslation(Vector2 vector, out Matrix3x2 result) =>
+ CreateTranslation(vector.X, vector.Y, out result);
+
+ ///
+ /// Creates a value for 2D translation.
+ ///
+ /// The X-coordinate of the translation vector.
+ /// The Y-coordinate of the translation vector.
+ /// The resulting value for 2D translation.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Matrix3x2 CreateTranslation(in float x, in float y)
+ {
+ CreateTranslation(x, y, out Matrix3x2 result);
+ return result;
+ }
+
+ ///
+ /// Creates a value for 2D translation.
+ ///
+ /// The X-coordinate of the translation vector.
+ /// The Y-coordinate of the translation vector.
+ ///
+ /// When this method returns, contains the resulting value. This parameter is passed
+ /// uninitialized.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void CreateTranslation(in float x, in float y, out Matrix3x2 result)
+ {
+ result.M11 = 1;
+ result.M12 = 0;
+
+ result.M21 = 0;
+ result.M22 = 1;
+
+ result.M31 = x;
+ result.M32 = y;
+ }
+
+ ///
+ /// Inverts the provided
+ ///
+ /// The value to invert.
+ /// The result of inverting the .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Matrix3x2 Invert(Matrix3x2 matrix)
+ {
+ Invert(ref matrix);
+ return matrix;
+ }
+
+ ///
+ /// Inverts the provided value.
+ ///
+ /// The value to invert.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void Invert(ref Matrix3x2 matrix)
+ {
+ var det = 1.0f / matrix.Determinant();
+
+ matrix.M11 = matrix.M22 * det;
+ matrix.M12 = -matrix.M12 * det;
+
+ matrix.M21 = -matrix.M21 * det;
+ matrix.M22 = matrix.M11 * det;
+
+ matrix.M31 = (matrix.M32 * matrix.M21 - matrix.M31 * matrix.M22) * det;
+ matrix.M32 = -(matrix.M32 * matrix.M11 - matrix.M31 * matrix.M12) * det;
+ }
+
+ ///
+ /// Adds the elements of two values.
+ ///
+ ///
+ /// This operation is performed component-wise.
+ ///
+ /// The first value.
+ /// The second value.
+ /// The result of the addition.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Matrix3x2 Add(Matrix3x2 left, Matrix3x2 right) => left + right;
+
+ ///
+ /// Adds the elements of two values.
+ ///
+ ///
+ /// This operation is performed component-wise.
+ ///
+ /// The first value.
+ /// The second value.
+ ///
+ /// When this method returns, contains the result of the addition. This parameter is passed uninitialized.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void Add(Matrix3x2 left, Matrix3x2 right, out Matrix3x2 result) => result = Add(left, right);
+
+ ///
+ /// Subtracts the elements of a from the corresponding elements of another
+ /// .
+ ///
+ ///
+ /// This operation is performed component-wise.
+ ///
+ /// The first value.
+ /// The second value.
+ /// The result of the subtraction.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Matrix3x2 Subtract(Matrix3x2 left, Matrix3x2 right) => left - right;
+
+ ///
+ /// Subtracts the elements of a from the corresponding elements of another
+ /// .
+ ///
+ ///
+ /// This operation is performed component-wise.
+ ///
+ /// The first value.
+ /// The second value.
+ ///
+ /// When this method returns, contains the result of the subtraction. This method is passed uninitialized.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void Subtract(Matrix3x2 left, Matrix3x2 right, out Matrix3x2 result) => result = Subtract(left, right);
+
+ ///
+ /// Multiplies the elements of a by the elements of another .
+ ///
+ ///
+ /// This operation performs matrix multiplication.
+ ///
+ /// The first value.
+ /// The second value.
+ /// The result of the multiplication.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Matrix3x2 Multiply(Matrix3x2 left, Matrix3x2 right) => left * right;
+
+ ///
+ /// Multiplies the elements of a by the elements of another .
+ ///
+ ///
+ /// This operation performs matrix multiplication.
+ ///
+ /// The first value.
+ /// The second value.
+ ///
+ /// When this method returns, contains the result of the multiplication. This parameter is passed uninitialized.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void Multiply(Matrix3x2 left, Matrix3x2 right, out Matrix3x2 result) => result = left * right;
+
+ ///
+ /// Multiplies the elements of a by the elements of another .
+ ///
+ ///
+ /// This operation performs matrix multiplication.
+ ///
+ /// The first value.
+ /// The second value.
+ ///
+ /// When this method returns, contains the result of the multiplication. This parameter is passed uninitialized.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void Multiply(ref Matrix3x2 left, ref Matrix3x2 right, out Matrix3x2 result) => result = left * right;
+
+ ///
+ /// Multiplies the elements of a by a scalar value.
+ ///
+ ///
+ /// This operation is performed component-wise.
+ ///
+ /// The source .
+ /// The scalar value.
+ /// The result of the multiplication.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Matrix3x2 Multiply(Matrix3x2 matrix, in float scalar) => matrix * scalar;
+
+ ///
+ /// Multiplies the elements of a by a scalar value.
+ ///
+ ///
+ /// This operation is performed component-wise.
+ ///
+ /// The source .
+ /// The scalar value.
+ ///
+ /// When this method returns, contains the result of the multiplication. This parameter is passed uninitialized.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void Multiply(Matrix3x2 matrix, in float scalar, out Matrix3x2 result) => result = Multiply(matrix, scalar);
+
+ ///
+ /// Divides the elements of a by the elements of another .
+ ///
+ ///
+ /// This operation is performed component-wise.
+ ///
+ /// The first value.
+ /// The second value.
+ /// The result of the division.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Matrix3x2 Divide(Matrix3x2 left, Matrix3x2 right) => left / right;
+
+ ///
+ /// Divides the elements of a by the elements of another .
+ ///
+ ///
+ /// This operation is performed component-wise.
+ ///
+ /// The first value.
+ /// The second value.
+ ///
+ /// When this method returns, contains the result of the division. This parameter is passed uninitialized.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void Divide(Matrix3x2 left, Matrix3x2 right, out Matrix3x2 result) => result = Divide(left, right);
+
+ ///
+ /// Divides the elements of a by a scalar value.
+ ///
+ ///
+ /// This operation is performed component-wise.
+ ///
+ /// The source .
+ /// The scalar value.
+ /// The result of the division.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Matrix3x2 Divide(Matrix3x2 matrix, in float scalar) => matrix / scalar;
+
+ ///
+ /// Divides the elements of a by a scalar value.
+ ///
+ ///
+ /// This operation is performed component-wise.
+ ///
+ /// The source .
+ /// The scalar value.
+ ///
+ /// When this method returns, contains the result of the division. This parameter is passed uninitialized.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void Divide(Matrix3x2 matrix, in float scalar, out Matrix3x2 result) => result = Divide(matrix, scalar);
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public override readonly bool Equals([NotNullWhen(true)] object obj) => obj is Matrix3x2 other && Equals(other);
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public readonly bool Equals(Matrix3x2 other) => this == other;
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public override readonly int GetHashCode() => HashCode.Combine(X, Y, Z);
+
+ ///
+ /// Converts the specified value into a value.
+ ///
+ ///
+ /// The third row of the resulting is set to (0, 0, 1, 0), and the fourth row is set to
+ /// (, , 0, 1).
+ ///
+ /// The resulting value.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Matrix ToMatrix() => ToMatrix(0.0f);
+
+ ///
+ /// Converts the specified value into a value.
+ ///
+ ///
+ /// The third row of the resulting is set to (0, 0, 1, 0), and the fourth row is set to
+ /// (, , , 1).
+ ///
+ ///
+ /// The depth value to be used for the third row of the resulting value.
+ ///
+ /// The resulting value.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Matrix ToMatrix(in float depth)
+ {
+ ToMatrix(depth, out Matrix result);
+ return result;
+ }
+
+ ///
+ /// Converts the specified value into a value.
+ ///
+ ///
+ /// The third row of the resulting is set to (0, 0, 1, 0), and the fourth row is set to
+ /// (, , 0, 1).
+ ///
+ ///
+ /// When this method returns, contains the resulting value. This parameter is passed
+ /// uninitialized.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void ToMatrix(out Matrix result) => ToMatrix(0.0f, out result);
+
+ ///
+ /// Converts the specified value into a value.
+ ///
+ ///
+ /// The third row of the resulting is set to (0, 0, 1, 0), and the fourth row is set to
+ /// (, , , 1).
+ ///
+ ///
+ /// The depth value to be used for the third row of the resulting value.
+ ///
+ ///
+ /// When this method returns, contains the resulting value. This parameter is passed
+ /// uninitialized.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void ToMatrix(in float depth, out Matrix result) => ToMatrix(this, depth, out result);
+
+ ///
+ /// Converts the specified value into a value.
+ ///
+ ///
+ /// The third row of the resulting is set to (0, 0, 1, 0), and the fourth row is set to
+ /// (, , 0, 1).
+ ///
+ /// The source value.
+ /// The resulting value.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Matrix ToMatrix(Matrix3x2 matrix) => ToMatrix(matrix, 0.0f);
+
+ ///
+ /// Converts the specified value into a value.
+ ///
+ ///
+ /// The third row of the resulting is set to (0, 0, 1, 0), and the fourth row is set to
+ /// (, , , 1).
+ ///
+ /// The source value.
+ ///
+ /// The depth value to be used for the third row of the resulting value.
+ ///
+ /// The resulting value.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Matrix ToMatrix(Matrix3x2 matrix, in float depth)
+ {
+ ToMatrix(matrix, depth, out Matrix result);
+ return result;
+ }
+
+ ///
+ /// Converts the specified value into a value.
+ ///
+ ///
+ /// The third row of the resulting is set to (0, 0, 1, 0), and the fourth row is set to
+ /// (, , 0, 1).
+ ///
+ /// The source value.
+ ///
+ /// When this method returns, contains the resulting value. This parameter is passed
+ /// uninitialized.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void ToMatrix(Matrix3x2 matrix, out Matrix result) => ToMatrix(matrix, 0.0f, out result);
+
+ ///
+ /// Converts the specified value into a value.
+ ///
+ ///
+ /// The third row of the resulting is set to (0, 0, 1, 0), and the fourth row is set to
+ /// (, , , 1).
+ ///
+ /// The source value.
+ ///
+ /// The depth value to be used for the third row of the resulting value.
+ ///
+ ///
+ /// When this method returns, contains the resulting value. This parameter is passed
+ /// uninitialized.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void ToMatrix(Matrix3x2 matrix, in float depth, out Matrix result)
+ {
+ result.M11 = matrix.M11;
+ result.M12 = matrix.M12;
+ result.M13 = 0;
+ result.M14 = 0;
+
+ result.M21 = matrix.M21;
+ result.M22 = matrix.M22;
+ result.M23 = 0;
+ result.M24 = 0;
+
+ result.M31 = 0;
+ result.M32 = 0;
+ result.M33 = 1;
+ result.M34 = 0;
+
+ result.M41 = matrix.M31;
+ result.M42 = matrix.M32;
+ result.M43 = depth;
+ result.M44 = 1;
+ }
+
+ ///
+ /// Converts a value to a value.
+ ///
+ /// The source value.
+ /// The resulting value.
+ public static implicit operator Matrix(Matrix3x2 matrix) => ToMatrix(matrix, 0.0f);
+
+ ///
+ /// Checks if two values are equal.
+ ///
+ ///
+ /// Two values are considered equal if all their corresponding elements are equal.
+ ///
+ /// The first value.
+ /// The second value.
+ /// True if the values are equal; otherwise, false.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool operator ==(Matrix3x2 left, Matrix3x2 right) =>
+ (left.X == right.X) && (left.Y == right.Y) && (left.Z == right.Z);
+
+ ///
+ /// Checks if two values are not equal.
+ ///
+ ///
+ /// Two values are considered not equal if any of their corresponding elements differ.
+ ///
+ /// The first value.
+ /// The second value.
+ /// True if the values are not equal; otherwise, false.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool operator !=(Matrix3x2 left, Matrix3x2 right) =>
+ (left.X != right.X) || (left.Y != right.Y) || (left.Z != right.Z);
+
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Matrix3x2 operator +(Matrix3x2 left, Matrix3x2 right)
+ {
+ Matrix3x2 result;
+
+ result.M11 = left.M11 + right.M11;
+ result.M12 = left.M12 + right.M12;
+
+ result.M21 = left.M21 + right.M21;
+ result.M22 = left.M22 + right.M22;
+
+ result.M31 = left.M31 + right.M31;
+ result.M32 = left.M32 + right.M32;
+
+ return result;
+ }
+
+ ///
+ public static Matrix3x2 operator -(Matrix3x2 left, Matrix3x2 right)
+ {
+ Matrix3x2 result;
+
+ result.M11 = left.M11 - right.M11;
+ result.M12 = left.M12 - right.M12;
+
+ result.M21 = left.M21 - right.M21;
+ result.M22 = left.M22 - right.M22;
+
+ result.M31 = left.M31 - right.M31;
+ result.M32 = left.M32 - right.M32;
+
+ return result;
+ }
+
+ ///
+ /// Negates the elements of a .
+ ///
+ ///
+ /// This operation is performed component-wise.
+ ///
+ /// The source .
+ /// The result of the negation.
+ public static Matrix3x2 operator -(Matrix3x2 matrix)
+ {
+ Matrix3x2 result;
+
+ result.M11 = -matrix.M11;
+ result.M12 = -matrix.M12;
+
+ result.M21 = -matrix.M21;
+ result.M22 = -matrix.M22;
+
+ result.M31 = -matrix.M31;
+ result.M32 = -matrix.M32;
+
+ return result;
+ }
+
+ ///
+ public static Matrix3x2 operator *(Matrix3x2 left, Matrix3x2 right)
+ {
+ Matrix3x2 result;
+
+ result.M11 = left.M11 * right.M11 + left.M12 * right.M21;
+ result.M12 = left.M11 * right.M12 + left.M12 * right.M22;
+
+ result.M21 = left.M21 * right.M11 + left.M22 * right.M21;
+ result.M22 = left.M21 * right.M12 + left.M22 * right.M22;
+
+ result.M31 = left.M31 * right.M11 + left.M32 * right.M21 + right.M31;
+ result.M32 = left.M31 * right.M12 + left.M32 * right.M22 + right.M32;
+
+ return result;
+ }
+
+ ///
+ public static Matrix3x2 operator *(Matrix3x2 matrix, in float scalar)
+ {
+ Matrix3x2 result;
+
+ result.M11 = matrix.M11 * scalar;
+ result.M12 = matrix.M12 * scalar;
+
+ result.M21 = matrix.M21 * scalar;
+ result.M22 = matrix.M22 * scalar;
+
+ result.M31 = matrix.M31 * scalar;
+ result.M32 = matrix.M32 * scalar;
+
+ return result;
+ }
+
+ ///
+ public static Matrix3x2 operator /(Matrix3x2 left, Matrix3x2 right)
+ {
+ Matrix3x2 result;
+
+ result.M11 = left.M11 / right.M11;
+ result.M12 = left.M12 / right.M12;
+
+ result.M21 = left.M21 / right.M21;
+ result.M22 = left.M22 / right.M22;
+
+ result.M31 = left.M31 / right.M31;
+ result.M32 = left.M32 / right.M32;
+
+ return result;
+ }
+
+ ///
+ public static Matrix3x2 operator /(Matrix3x2 matrix, in float scalar)
+ {
+ var num = 1.0f / scalar;
+ Matrix3x2 result;
+
+ result.M11 = matrix.M11 * num;
+ result.M12 = matrix.M12 * num;
+
+ result.M21 = matrix.M21 * num;
+ result.M22 = matrix.M22 * num;
+
+ result.M31 = matrix.M31 * num;
+ result.M32 = matrix.M32 * num;
+
+ return result;
+ }
+
+ ///
+ /// Returns a string representation of this
+ ///
+ /// The string representation of this
+ public override string ToString() =>
+ $"{{M11:{M11} M12:{M12}}} {{M21:{M21} M22:{M22}}} {{M31:{M31} M32:{M32}}}";
+
+ internal string DebugDisplayString()
+ {
+ if (this == Identity)
+ {
+ return nameof(Identity);
+ }
+
+ Decompose(out Vector2 translation, out float rotation, out Vector2 scale);
+ return $"T:({translation.X:0.##},{translation.Y:0.##}), R:{MathHelper.ToDegrees(rotation):0.##}°, S:({scale.X:0.##},{scale.Y:0.##})";
+ }
+}
diff --git a/source/MonoGame.Extended/Math/OrientedRectangle.cs b/source/MonoGame.Extended/Math/OrientedRectangle.cs
index 1439e9f7e..9bd909f2d 100644
--- a/source/MonoGame.Extended/Math/OrientedRectangle.cs
+++ b/source/MonoGame.Extended/Math/OrientedRectangle.cs
@@ -29,9 +29,9 @@ public struct OrientedRectangle : IEquatable, IShapeF
public Vector2 Radii;
///
- /// The rotation matrix of the bounding rectangle .
+ /// The rotation matrix of the bounding rectangle .
///
- public Matrix2 Orientation;
+ public Matrix3x2 Orientation;
///
/// Initializes a new instance of the structure from the specified centre
@@ -39,8 +39,8 @@ public struct OrientedRectangle : IEquatable, IShapeF
///
/// The centre .
/// The radii .
- /// The orientation .
- public OrientedRectangle(Point2 center, Size2 radii, Matrix2 orientation)
+ /// The orientation .
+ public OrientedRectangle(Point2 center, Size2 radii, Matrix3x2 orientation)
{
Center = center;
Radii = radii;
@@ -82,15 +82,15 @@ public Point2 Position
/// transformed by .
///
/// The to transform.
- /// The transformation.
+ /// The transformation.
/// A new .
- public static OrientedRectangle Transform(OrientedRectangle rectangle, ref Matrix2 transformMatrix)
+ public static OrientedRectangle Transform(OrientedRectangle rectangle, ref Matrix3x2 transformMatrix)
{
Transform(ref rectangle, ref transformMatrix, out var result);
return result;
}
- private static void Transform(ref OrientedRectangle rectangle, ref Matrix2 transformMatrix, out OrientedRectangle result)
+ private static void Transform(ref OrientedRectangle rectangle, ref Matrix3x2 transformMatrix, out OrientedRectangle result)
{
PrimitivesHelper.TransformOrientedRectangle(
ref rectangle.Center,
@@ -169,14 +169,14 @@ public static explicit operator OrientedRectangle(RectangleF rectangle)
var radii = new Size2(rectangle.Width * 0.5f, rectangle.Height * 0.5f);
var centre = new Point2(rectangle.X + radii.Width, rectangle.Y + radii.Height);
- return new OrientedRectangle(centre, radii, Matrix2.Identity);
+ return new OrientedRectangle(centre, radii, Matrix3x2.Identity);
}
public static explicit operator RectangleF(OrientedRectangle orientedRectangle)
{
var topLeft = -orientedRectangle.Radii;
var rectangle = new RectangleF(topLeft, orientedRectangle.Radii * 2);
- var orientation = orientedRectangle.Orientation * Matrix2.CreateTranslation(orientedRectangle.Center);
+ var orientation = orientedRectangle.Orientation * Matrix3x2.CreateTranslation(orientedRectangle.Center);
return RectangleF.Transform(rectangle, ref orientation);
}
diff --git a/source/MonoGame.Extended/Math/PrimitivesHelper.cs b/source/MonoGame.Extended/Math/PrimitivesHelper.cs
index ed082708e..0180943ba 100644
--- a/source/MonoGame.Extended/Math/PrimitivesHelper.cs
+++ b/source/MonoGame.Extended/Math/PrimitivesHelper.cs
@@ -60,7 +60,7 @@ internal static void CreateRectangleFromPoints(IReadOnlyList points, out
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static void TransformRectangle(ref Point2 center, ref Vector2 halfExtents, ref Matrix2 transformMatrix)
+ internal static void TransformRectangle(ref Point2 center, ref Vector2 halfExtents, ref Matrix3x2 transformMatrix)
{
// Real-Time Collision Detection, Christer Ericson, 2005. Chapter 4.2; Bounding Volumes - Axis-aligned Bounding Boxes (AABBs). pg 86-87
@@ -74,8 +74,8 @@ internal static void TransformRectangle(ref Point2 center, ref Vector2 halfExten
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void TransformOrientedRectangle(
ref Point2 center,
- ref Matrix2 orientation,
- ref Matrix2 transformMatrix)
+ ref Matrix3x2 orientation,
+ ref Matrix3x2 transformMatrix)
{
// Real-Time Collision Detection, Christer Ericson, 2005. Chapter 4.4; Oriented Bounding Boxes (OBBs), pg 101-105.
diff --git a/source/MonoGame.Extended/Math/RectangleF.cs b/source/MonoGame.Extended/Math/RectangleF.cs
index 1a1d6859e..77d91ad97 100644
--- a/source/MonoGame.Extended/Math/RectangleF.cs
+++ b/source/MonoGame.Extended/Math/RectangleF.cs
@@ -223,7 +223,7 @@ public static RectangleF CreateFrom(IReadOnlyList points)
///
/// Computes the from the specified transformed by
- /// the specified .
+ /// the specified .
///
/// The rectangle to be transformed.
/// The transform matrix.
@@ -240,7 +240,7 @@ public static RectangleF CreateFrom(IReadOnlyList points)
///
///
public static void Transform(ref RectangleF rectangle,
- ref Matrix2 transformMatrix, out RectangleF result)
+ ref Matrix3x2 transformMatrix, out RectangleF result)
{
var center = rectangle.Center;
var halfExtents = (Vector2)rectangle.Size * 0.5f;
@@ -256,7 +256,7 @@ public static void Transform(ref RectangleF rectangle,
///
/// Computes the from the specified transformed by
/// the
- /// specified .
+ /// specified .
///
/// The bounding rectangle.
/// The transform matrix.
@@ -271,7 +271,7 @@ public static void Transform(ref RectangleF rectangle,
/// not desired.
///
///
- public static RectangleF Transform(RectangleF rectangle, ref Matrix2 transformMatrix)
+ public static RectangleF Transform(RectangleF rectangle, ref Matrix3x2 transformMatrix)
{
RectangleF result;
Transform(ref rectangle, ref transformMatrix, out result);
diff --git a/source/MonoGame.Extended/Math/ShapeF.cs b/source/MonoGame.Extended/Math/ShapeF.cs
index 7478f759d..662930380 100644
--- a/source/MonoGame.Extended/Math/ShapeF.cs
+++ b/source/MonoGame.Extended/Math/ShapeF.cs
@@ -74,7 +74,7 @@ public static bool Intersects(CircleF circle, RectangleF rectangle)
/// True if the circle and oriented bounded rectangle intersects, otherwise false.
public static bool Intersects(CircleF circle, OrientedRectangle orientedRectangle)
{
- var rotation = Matrix2.CreateRotationZ(orientedRectangle.Orientation.Rotation);
+ var rotation = Matrix3x2.CreateRotationZ(orientedRectangle.Orientation.Rotation);
var circleCenterInRectangleSpace = rotation.Transform(circle.Center - orientedRectangle.Center);
var circleInRectangleSpace = new CircleF(circleCenterInRectangleSpace, circle.Radius);
var boundingRectangle = new BoundingRectangle(new Point2(), orientedRectangle.Radii);
diff --git a/source/MonoGame.Extended/Transform.cs b/source/MonoGame.Extended/Transform.cs
index b0a0be4ee..2f6eae5b5 100644
--- a/source/MonoGame.Extended/Transform.cs
+++ b/source/MonoGame.Extended/Transform.cs
@@ -45,10 +45,10 @@ internal BaseTransform()
}
///
- /// Gets the model-to-local space .
+ /// Gets the model-to-local space .
///
///
- /// The model-to-local space .
+ /// The model-to-local space .
///
public TMatrix LocalMatrix
{
@@ -60,10 +60,10 @@ public TMatrix LocalMatrix
}
///
- /// Gets the local-to-world space .
+ /// Gets the local-to-world space .
///
///
- /// The local-to-world space .
+ /// The local-to-world space .
///
public TMatrix WorldMatrix
{
@@ -106,9 +106,9 @@ public BaseTransform Parent
public event Action TranformUpdated; // observer pattern for after the world (or local) matrix was re-calculated
///
- /// Gets the model-to-local space .
+ /// Gets the model-to-local space .
///
- /// The model-to-local space .
+ /// The model-to-local space .
public void GetLocalMatrix(out TMatrix matrix)
{
RecalculateLocalMatrixIfNecessary();
@@ -116,9 +116,9 @@ public void GetLocalMatrix(out TMatrix matrix)
}
///
- /// Gets the local-to-world space .
+ /// Gets the local-to-world space .
///
- /// The local-to-world space .
+ /// The local-to-world space .
public void GetWorldMatrix(out TMatrix matrix)
{
RecalculateWorldMatrixIfNecessary();
@@ -189,7 +189,7 @@ private void RecalculateLocalMatrixIfNecessary()
///
/// Represents the position, rotation, and scale of a two-dimensional game object.
///
- ///
+ ///
///
///
///
@@ -200,7 +200,7 @@ private void RecalculateLocalMatrixIfNecessary()
/// objects hierarchically.
///
///
- public class Transform2 : BaseTransform, IMovable, IRotatable, IScalable
+ public class Transform2 : BaseTransform, IMovable, IRotatable, IScalable
{
private Vector2 _position;
private float _rotation;
@@ -298,12 +298,12 @@ public Vector2 Scale
}
}
- protected internal override void RecalculateWorldMatrix(ref Matrix2 localMatrix, out Matrix2 matrix)
+ protected internal override void RecalculateWorldMatrix(ref Matrix3x2 localMatrix, out Matrix3x2 matrix)
{
if (Parent != null)
{
Parent.GetWorldMatrix(out matrix);
- Matrix2.Multiply(ref localMatrix, ref matrix, out matrix);
+ Matrix3x2.Multiply(ref localMatrix, ref matrix, out matrix);
}
else
{
@@ -311,11 +311,11 @@ protected internal override void RecalculateWorldMatrix(ref Matrix2 localMatrix,
}
}
- protected internal override void RecalculateLocalMatrix(out Matrix2 matrix)
+ protected internal override void RecalculateLocalMatrix(out Matrix3x2 matrix)
{
- matrix = Matrix2.CreateScale(_scale) *
- Matrix2.CreateRotationZ(_rotation) *
- Matrix2.CreateTranslation(_position);
+ matrix = Matrix3x2.CreateScale(_scale) *
+ Matrix3x2.CreateRotationZ(_rotation) *
+ Matrix3x2.CreateTranslation(_position);
}
public override string ToString()
@@ -453,4 +453,4 @@ public override string ToString() {
return $"Position: {Position}, Rotation: {Rotation}, Scale: {Scale}";
}
}
-}
\ No newline at end of file
+}
diff --git a/tests/MonoGame.Extended.Tests/Math/Matrix3x2.cs b/tests/MonoGame.Extended.Tests/Math/Matrix3x2.cs
new file mode 100644
index 000000000..56ab1e7b1
--- /dev/null
+++ b/tests/MonoGame.Extended.Tests/Math/Matrix3x2.cs
@@ -0,0 +1,20 @@
+using Microsoft.Xna.Framework;
+
+namespace MonoGame.Extended.Tests;
+
+public sealed class Matrix3x2Tests
+{
+ [Fact]
+ public void ConstructorTest()
+ {
+ Vector2 x = new Vector2(1, 2);
+ Vector2 y = new Vector2(3, 4);
+ Vector2 z = new Vector2(5, 6);
+
+ var matrix = new Matrix3x2(x.X, x.Y, y.X, y.Y, z.X, z.Y);
+
+ Assert.Equal(x, matrix.X);
+ Assert.Equal(y, matrix.Y);
+ Assert.Equal(z, matrix.Z);
+ }
+}
diff --git a/tests/MonoGame.Extended.Tests/Primitives/BoundingRectangleTests.cs b/tests/MonoGame.Extended.Tests/Primitives/BoundingRectangleTests.cs
index 6f95cf573..2d6dc5b1c 100644
--- a/tests/MonoGame.Extended.Tests/Primitives/BoundingRectangleTests.cs
+++ b/tests/MonoGame.Extended.Tests/Primitives/BoundingRectangleTests.cs
@@ -5,7 +5,7 @@
//namespace MonoGame.Extended.Tests.Primitives
//{
-//
+//
// public class BoundingRectangleTests
// {
// public IEnumerable ConstructorTestCases
@@ -88,11 +88,11 @@
// get
// {
// yield return
-// new TestCaseData(new BoundingRectangle(), Matrix2.Identity, new BoundingRectangle()).SetName(
+// new TestCaseData(new BoundingRectangle(), Matrix3x2.Identity, new BoundingRectangle()).SetName(
// "The bounding rectangle created from the empty bounding rectangle transformed by the identity matrix is the empty bounding rectangle.")
// ;
// yield return
-// new TestCaseData(new BoundingRectangle(new Point2(0, 0), new Size2(20, 20)), Matrix2.CreateScale(2), new BoundingRectangle(new Point2(0, 0), new Size2(40, 40))).SetName(
+// new TestCaseData(new BoundingRectangle(new Point2(0, 0), new Size2(20, 20)), Matrix3x2.CreateScale(2), new BoundingRectangle(new Point2(0, 0), new Size2(40, 40))).SetName(
// "The bounding rectangle created from a non-empty bounding rectangle transformed by a non-identity matrix is the expected bounding rectangle.")
// ;
// }
@@ -100,7 +100,7 @@
// [Fact]
// [TestCaseSource(nameof(CreateFromTransformedTestCases))]
-// public void CreateFromTransformed(BoundingRectangle boundingRectangle, Matrix2 transformMatrix,
+// public void CreateFromTransformed(BoundingRectangle boundingRectangle, Matrix3x2 transformMatrix,
// BoundingRectangle expectedBoundingRectangle)
// {
// var actualBoundingRectangle = BoundingRectangle.Transform(boundingRectangle, ref transformMatrix);
diff --git a/tests/MonoGame.Extended.Tests/Primitives/OrientedRectangleTests.cs b/tests/MonoGame.Extended.Tests/Primitives/OrientedRectangleTests.cs
index e3b40c8c9..44b6b9b72 100644
--- a/tests/MonoGame.Extended.Tests/Primitives/OrientedRectangleTests.cs
+++ b/tests/MonoGame.Extended.Tests/Primitives/OrientedRectangleTests.cs
@@ -10,11 +10,11 @@ public class OrientedRectangleTests
[Fact]
public void Initializes_oriented_rectangle()
{
- var rectangle = new OrientedRectangle(new Point2(1, 2), new Size2(3, 4), new Matrix2(5, 6, 7, 8, 9, 10));
+ var rectangle = new OrientedRectangle(new Point2(1, 2), new Size2(3, 4), new Matrix3x2(5, 6, 7, 8, 9, 10));
Assert.Equal(new Point2(1, 2), rectangle.Center);
Assert.Equal(new Vector2(3, 4), rectangle.Radii);
- Assert.Equal(new Matrix2(5, 6, 7, 8, 9, 10), rectangle.Orientation);
+ Assert.Equal(new Matrix3x2(5, 6, 7, 8, 9, 10), rectangle.Orientation);
CollectionAssert.Equal(
new List
{
@@ -31,14 +31,14 @@ public void Initializes_oriented_rectangle()
new object[]
{
"empty compared with empty is true",
- new OrientedRectangle(Point2.Zero, Size2.Empty, Matrix2.Identity),
- new OrientedRectangle(Point2.Zero, Size2.Empty, Matrix2.Identity)
+ new OrientedRectangle(Point2.Zero, Size2.Empty, Matrix3x2.Identity),
+ new OrientedRectangle(Point2.Zero, Size2.Empty, Matrix3x2.Identity)
},
new object[]
{
"initialized compared with initialized true",
- new OrientedRectangle(new Point2(1, 2), new Size2(3, 4), new Matrix2(5, 6, 7, 8, 9, 10)),
- new OrientedRectangle(new Point2(1, 2), new Size2(3, 4), new Matrix2(5, 6, 7, 8, 9, 10))
+ new OrientedRectangle(new Point2(1, 2), new Size2(3, 4), new Matrix3x2(5, 6, 7, 8, 9, 10)),
+ new OrientedRectangle(new Point2(1, 2), new Size2(3, 4), new Matrix3x2(5, 6, 7, 8, 9, 10))
}
};
@@ -57,8 +57,8 @@ public class Transform
[Fact]
public void Center_point_is_not_translated()
{
- var rectangle = new OrientedRectangle(new Point2(1, 2), new Size2(), Matrix2.Identity);
- var transform = Matrix2.Identity;
+ var rectangle = new OrientedRectangle(new Point2(1, 2), new Size2(), Matrix3x2.Identity);
+ var transform = Matrix3x2.Identity;
var result = OrientedRectangle.Transform(rectangle, ref transform);
@@ -68,8 +68,8 @@ public void Center_point_is_not_translated()
[Fact]
public void Center_point_is_translated()
{
- var rectangle = new OrientedRectangle(new Point2(0, 0), new Size2(), new Matrix2());
- var transform = Matrix2.CreateTranslation(1, 2);
+ var rectangle = new OrientedRectangle(new Point2(0, 0), new Size2(), new Matrix3x2());
+ var transform = Matrix3x2.CreateTranslation(1, 2);
var result = OrientedRectangle.Transform(rectangle, ref transform);
@@ -79,8 +79,8 @@ public void Center_point_is_translated()
[Fact]
public void Radii_is_not_changed_by_identity_transform()
{
- var rectangle = new OrientedRectangle(new Point2(), new Size2(10, 20), new Matrix2());
- var transform = Matrix2.Identity;
+ var rectangle = new OrientedRectangle(new Point2(), new Size2(10, 20), new Matrix3x2());
+ var transform = Matrix3x2.Identity;
var result = OrientedRectangle.Transform(rectangle, ref transform);
@@ -90,8 +90,8 @@ public void Radii_is_not_changed_by_identity_transform()
[Fact]
public void Radii_is_not_changed_by_translation()
{
- var rectangle = new OrientedRectangle(new Point2(1, 2), new Size2(10, 20), new Matrix2());
- var transform = Matrix2.CreateTranslation(1, 2);
+ var rectangle = new OrientedRectangle(new Point2(1, 2), new Size2(10, 20), new Matrix3x2());
+ var transform = Matrix3x2.CreateTranslation(1, 2);
var result = OrientedRectangle.Transform(rectangle, ref transform);
@@ -101,22 +101,22 @@ public void Radii_is_not_changed_by_translation()
[Fact]
public void Orientation_is_rotated_45_degrees_left()
{
- var rectangle = new OrientedRectangle(new Point2(), new Size2(), Matrix2.Identity);
- var transform = Matrix2.CreateRotationZ(MathHelper.PiOver4);
+ var rectangle = new OrientedRectangle(new Point2(), new Size2(), Matrix3x2.Identity);
+ var transform = Matrix3x2.CreateRotationZ(MathHelper.PiOver4);
var result = OrientedRectangle.Transform(rectangle, ref transform);
Assert.Equal(new Point2(), result.Center);
Assert.Equal(new Vector2(), result.Radii);
- Assert.Equal(Matrix2.CreateRotationZ(MathHelper.PiOver4), result.Orientation);
+ Assert.Equal(Matrix3x2.CreateRotationZ(MathHelper.PiOver4), result.Orientation);
}
[Fact]
public void Orientation_is_rotated_to_45_degrees_from_180()
{
- var rectangle = new OrientedRectangle(new Point2(), new Size2(), Matrix2.CreateRotationZ(MathHelper.Pi));
- var transform = Matrix2.CreateRotationZ(-3 * MathHelper.PiOver4);
- var expectedOrientation = Matrix2.CreateRotationZ(MathHelper.PiOver4);
+ var rectangle = new OrientedRectangle(new Point2(), new Size2(), Matrix3x2.CreateRotationZ(MathHelper.Pi));
+ var transform = Matrix3x2.CreateRotationZ(-3 * MathHelper.PiOver4);
+ var expectedOrientation = Matrix3x2.CreateRotationZ(MathHelper.PiOver4);
var result = OrientedRectangle.Transform(rectangle, ref transform);
@@ -133,8 +133,8 @@ public void Orientation_is_rotated_to_45_degrees_from_180()
[Fact]
public void Points_are_same_as_center()
{
- var rectangle = new OrientedRectangle(new Point2(1, 2), new Size2(), Matrix2.Identity);
- var transform = Matrix2.Identity;
+ var rectangle = new OrientedRectangle(new Point2(1, 2), new Size2(), Matrix3x2.Identity);
+ var transform = Matrix3x2.Identity;
var result = OrientedRectangle.Transform(rectangle, ref transform);
@@ -152,8 +152,8 @@ public void Points_are_same_as_center()
[Fact]
public void Points_are_translated()
{
- var rectangle = new OrientedRectangle(new Point2(0, 0), new Size2(2, 4), Matrix2.Identity);
- var transform = Matrix2.CreateTranslation(10, 20);
+ var rectangle = new OrientedRectangle(new Point2(0, 0), new Size2(2, 4), Matrix3x2.Identity);
+ var transform = Matrix3x2.CreateTranslation(10, 20);
var result = OrientedRectangle.Transform(rectangle, ref transform);
@@ -207,11 +207,11 @@ public void Applies_rotation_and_translation()
* :
* :
*/
- var rectangle = new OrientedRectangle(new Point2(1, 2), new Size2(2, 4), Matrix2.Identity);
+ var rectangle = new OrientedRectangle(new Point2(1, 2), new Size2(2, 4), Matrix3x2.Identity);
var transform =
- Matrix2.CreateRotationZ(MathHelper.PiOver2)
+ Matrix3x2.CreateRotationZ(MathHelper.PiOver2)
*
- Matrix2.CreateTranslation(10, 20);
+ Matrix3x2.CreateTranslation(10, 20);
var result = OrientedRectangle.Transform(rectangle, ref transform);
@@ -219,7 +219,7 @@ public void Applies_rotation_and_translation()
Assert.Equal(21, result.Center.Y, 6);
Assert.Equal(2, result.Radii.X, 6);
Assert.Equal(4, result.Radii.Y, 6);
- Assert.Equal(Matrix2.CreateRotationZ(MathHelper.PiOver2), result.Orientation);
+ Assert.Equal(Matrix3x2.CreateRotationZ(MathHelper.PiOver2), result.Orientation);
CollectionAssert.Equal(
new List
{
diff --git a/tests/MonoGame.Extended.Tests/Primitives/RectangleFTests.cs b/tests/MonoGame.Extended.Tests/Primitives/RectangleFTests.cs
index 9121d6ada..ddc6db756 100644
--- a/tests/MonoGame.Extended.Tests/Primitives/RectangleFTests.cs
+++ b/tests/MonoGame.Extended.Tests/Primitives/RectangleFTests.cs
@@ -38,7 +38,7 @@ public class Transform
public void Center_point_is_not_translated()
{
var rectangle = new RectangleF(new Point2(0, 0), new Size2(20, 30));
- var transform = Matrix2.Identity;
+ var transform = Matrix3x2.Identity;
var result = RectangleF.Transform(rectangle, ref transform);
@@ -49,7 +49,7 @@ public void Center_point_is_not_translated()
public void Center_point_is_translated()
{
var rectangleF = new RectangleF(new Point2(0, 0), new Size2(20, 30));
- var transform = Matrix2.CreateTranslation(1, 2);
+ var transform = Matrix3x2.CreateTranslation(1, 2);
var result = RectangleF.Transform(rectangleF, ref transform);
@@ -60,7 +60,7 @@ public void Center_point_is_translated()
public void Size_is_not_changed_by_identity_transform()
{
var rectangle = new RectangleF(new Point2(0, 0), new Size2(20, 30));
- var transform = Matrix2.Identity;
+ var transform = Matrix3x2.Identity;
var result = RectangleF.Transform(rectangle, ref transform);
@@ -71,7 +71,7 @@ public void Size_is_not_changed_by_identity_transform()
public void Size_is_not_changed_by_translation()
{
var rectangle = new RectangleF(new Point2(0, 0), new Size2(20, 30));
- var transform = Matrix2.CreateTranslation(1, 2);
+ var transform = Matrix3x2.CreateTranslation(1, 2);
var result = RectangleF.Transform(rectangle, ref transform);
@@ -119,9 +119,9 @@ public void Applies_rotation_and_translation()
*/
var rectangle = new RectangleF(new Point2(0, 0), new Size2(2, 4));
var transform =
- Matrix2.CreateRotationZ(MathHelper.PiOver2)
+ Matrix3x2.CreateRotationZ(MathHelper.PiOver2)
*
- Matrix2.CreateTranslation(10, 20);
+ Matrix3x2.CreateTranslation(10, 20);
var result = RectangleF.Transform(rectangle, ref transform);
diff --git a/tests/MonoGame.Extended.Tests/Primitives/ShapeTests.cs b/tests/MonoGame.Extended.Tests/Primitives/ShapeTests.cs
index 37b2fc4c2..54c3ca8bf 100644
--- a/tests/MonoGame.Extended.Tests/Primitives/ShapeTests.cs
+++ b/tests/MonoGame.Extended.Tests/Primitives/ShapeTests.cs
@@ -99,7 +99,7 @@ public void Axis_aligned_rectangle_intersects_circle()
* :
* :
*/
- IShapeF rectangle = new OrientedRectangle(Point2.Zero, new Size2(1, 1), Matrix2.Identity);
+ IShapeF rectangle = new OrientedRectangle(Point2.Zero, new Size2(1, 1), Matrix3x2.Identity);
var circle = new CircleF(Point2.Zero, 1);
Assert.True(rectangle.Intersects(circle));
@@ -117,7 +117,7 @@ public void Axis_aligned_rectangle_does_not_intersect_circle_in_top_left()
* :
* :
*/
- IShapeF rectangle = new OrientedRectangle(Point2.Zero, new Size2(1, 1), Matrix2.Identity);
+ IShapeF rectangle = new OrientedRectangle(Point2.Zero, new Size2(1, 1), Matrix3x2.Identity);
var circle = new CircleF(new Point2(-2, 1), .99f);
Assert.False(rectangle.Intersects(circle));
@@ -135,7 +135,7 @@ public void Rectangle_rotated_45_degrees_does_not_intersect_circle_in_bottom_rig
* * *
* :* *
*/
- IShapeF rectangle = new OrientedRectangle(new Point2(-1, 1), new Size2(1.42f, 1.42f), Matrix2.CreateRotationZ(-MathHelper.PiOver4));
+ IShapeF rectangle = new OrientedRectangle(new Point2(-1, 1), new Size2(1.42f, 1.42f), Matrix3x2.CreateRotationZ(-MathHelper.PiOver4));
var circle = new CircleF(new Point2(1, -1), 1.4f);
Assert.False(rectangle.Intersects(circle));
@@ -153,7 +153,7 @@ public void Axis_aligned_rectangle_does_not_intersect_rectangle()
* :**
* :
*/
- IShapeF rectangle = new OrientedRectangle(new Point2(-1, 0), new Size2(1, 1), Matrix2.Identity);
+ IShapeF rectangle = new OrientedRectangle(new Point2(-1, 0), new Size2(1, 1), Matrix3x2.Identity);
var rect = new RectangleF(new Point2(0.001f, 0), new Size2(2, 2));
Assert.False(rectangle.Intersects(rect));
@@ -171,7 +171,7 @@ public void Axis_aligned_rectangle_intersects_rectangle()
* :**
* :
*/
- IShapeF rectangle = new OrientedRectangle(new Point2(-1, 0), new Size2(1, 1), Matrix2.Identity);
+ IShapeF rectangle = new OrientedRectangle(new Point2(-1, 0), new Size2(1, 1), Matrix3x2.Identity);
var rect = new RectangleF(new Point2(0, 0), new Size2(2, 2));
Assert.True(rectangle.Intersects(rect));