/* * Copyright (C) 2012-2020 CypherCore * Copyright (C) 2003-2004 Eran Kampf eran@ekampf.com http://www.ekampf.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Runtime.InteropServices; using System.Text.RegularExpressions; namespace Framework.GameMath { /// /// Represents a 2-dimentional single-precision floating point matrix. /// [Serializable] [StructLayout(LayoutKind.Sequential)] [TypeConverter(typeof(ExpandableObjectConverter))] public struct Matrix2 : ICloneable { #region Private Fields private float _m11, _m12; private float _m21, _m22; #endregion #region Constructors /// /// Initializes a new instance of the structure with the specified values. /// public Matrix2(float m11, float m12, float m21, float m22) { _m11 = m11; _m12 = m12; _m21 = m21; _m22 = m22; } /// /// Initializes a new instance of the structure with the specified values. /// /// An array containing the matrix values in row-major order. public Matrix2(float[] elements) { Debug.Assert(elements != null); Debug.Assert(elements.Length >= 4); _m11 = elements[0]; _m12 = elements[1]; _m21 = elements[2]; _m22 = elements[3]; } /// /// Initializes a new instance of the structure with the specified values. /// /// An array containing the matrix values in row-major order. public Matrix2(List elements) { Debug.Assert(elements != null); Debug.Assert(elements.Count >= 4); _m11 = elements[0]; _m12 = elements[1]; _m21 = elements[2]; _m22 = elements[3]; } /// /// Initializes a new instance of the structure with the specified values. /// /// A instance holding values for the first column. /// A instance holding values for the second column. public Matrix2(Vector2 column1, Vector2 column2) { _m11 = column1.X; _m12 = column2.X; _m21 = column1.Y; _m22 = column2.Y; } /// /// Initializes a new instance of the class using a given matrix. /// public Matrix2(Matrix2 m) { _m11 = m.M11; _m12 = m.M12; _m21 = m.M21; _m22 = m.M22; } #endregion #region Constants /// /// 4-dimentional single-precision floating point zero matrix. /// public static readonly Matrix2 Zero = new(0, 0, 0, 0); /// /// 4-dimentional single-precision floating point identity matrix. /// public static readonly Matrix2 Identity = new(1, 0, 0, 1); #endregion #region Public Properties /// /// Gets or sets the value of the [1,1] matrix element. /// /// A single-precision floating-point number. public float M11 { get { return _m11; } set { _m11 = value; } } /// /// Gets or sets the value of the [1,2] matrix element. /// /// A single-precision floating-point number. public float M12 { get { return _m12; } set { _m12 = value; } } /// /// Gets or sets the value of the [2,1] matrix element. /// /// A single-precision floating-point number. public float M21 { get { return _m21; } set { _m21 = value; } } /// /// Gets or sets the value of the [2,2] matrix element. /// /// A single-precision floating-point number. public float M22 { get { return _m22; } set { _m22 = value; } } /// /// Gets the matrix's trace value. /// /// A single-precision floating-point number. public float Trace { get { return _m11 + _m22; } } #endregion #region ICloneable Members /// /// Creates an exact copy of this object. /// /// The object this method creates, cast as an object. object ICloneable.Clone() { return new Matrix2(this); } /// /// Creates an exact copy of this object. /// /// The object this method creates. public Matrix2 Clone() { return new Matrix2(this); } #endregion #region Public Static Parse Methods private const string regularExp = @"2x2\s*\[(?.*),(?.*),(?.*),(?.*)\]"; /// /// Converts the specified string to its equivalent. /// /// A string representation of a . /// A that represents the vector specified by the parameter. /// /// The string should be in the following form: "2x2..matrix elements..>".
/// Exmaple : "2x2[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]" ///
public static Matrix2 Parse(string value) { Regex r = new(regularExp, RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace); Match m = r.Match(value); if (m.Success) { return new Matrix2( float.Parse(m.Result("${m11}")), float.Parse(m.Result("${m12}")), float.Parse(m.Result("${m21}")), float.Parse(m.Result("${m22}")) ); } else { throw new Exception("Unsuccessful Match."); } } /// /// Converts the specified string to its equivalent. /// A return value indicates whether the conversion succeeded or failed. /// /// A string representation of a . /// /// When this method returns, if the conversion succeeded, /// contains a representing the vector specified by . /// /// if value was converted successfully; otherwise, . /// /// The string should be in the following form: "2x2..matrix elements..>".
/// Exmaple : "2x2[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]" ///
public static bool TryParse(string value, out Matrix2 result) { Regex r = new(regularExp, RegexOptions.Singleline); Match m = r.Match(value); if (m.Success) { result = new Matrix2( float.Parse(m.Result("${m11}")), float.Parse(m.Result("${m12}")), float.Parse(m.Result("${m21}")), float.Parse(m.Result("${m22}")) ); return true; } result = Matrix2.Zero; return false; } #endregion #region Public Static Matrix Arithmetics /// /// Adds two matrices. /// /// A instance. /// A instance. /// A new instance containing the sum. public static Matrix2 Add(Matrix2 left, Matrix2 right) { return new Matrix2( left.M11 + right.M11, left.M12 + right.M12, left.M21 + right.M21, left.M22 + right.M22 ); } /// /// Adds a matrix and a scalar. /// /// A instance. /// A single-precision floating-point number. /// A new instance containing the sum. public static Matrix2 Add(Matrix2 matrix, float scalar) { return new Matrix2( matrix.M11 + scalar, matrix.M12 + scalar, matrix.M21 + scalar, matrix.M22 + scalar ); } /// /// Adds two matrices and put the result in a third matrix. /// /// A instance. /// A instance. /// A instance to hold the result. public static void Add(Matrix2 left, Matrix2 right, ref Matrix2 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; } /// /// Adds a matrix and a scalar and put the result in a third matrix. /// /// A instance. /// A single-precision floating-point number. /// A instance to hold the result. public static void Add(Matrix2 matrix, float scalar, ref Matrix2 result) { result.M11 = matrix.M11 + scalar; result.M12 = matrix.M12 + scalar; result.M21 = matrix.M21 + scalar; result.M22 = matrix.M22 + scalar; } /// /// Subtracts a matrix from a matrix. /// /// A instance to subtract from. /// A instance to subtract. /// A new instance containing the difference. /// result[x][y] = left[x][y] - right[x][y] public static Matrix2 Subtract(Matrix2 left, Matrix2 right) { return new Matrix2( left.M11 - right.M11, left.M12 - right.M12, left.M21 - right.M21, left.M22 - right.M22 ); } /// /// Subtracts a scalar from a matrix. /// /// A instance. /// A single-precision floating-point number. /// A new instance containing the difference. public static Matrix2 Subtract(Matrix2 matrix, float scalar) { return new Matrix2( matrix.M11 - scalar, matrix.M12 - scalar, matrix.M21 - scalar, matrix.M22 - scalar ); } /// /// Subtracts a matrix from a matrix and put the result in a third matrix. /// /// A instance to subtract from. /// A instance to subtract. /// A instance to hold the result. /// result[x][y] = left[x][y] - right[x][y] public static void Subtract(Matrix2 left, Matrix2 right, ref Matrix2 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; } /// /// Subtracts a scalar from a matrix and put the result in a third matrix. /// /// A instance. /// A single-precision floating-point number. /// A instance to hold the result. public static void Subtract(Matrix2 matrix, float scalar, ref Matrix2 result) { result.M11 = matrix.M11 - scalar; result.M12 = matrix.M12 - scalar; result.M21 = matrix.M21 - scalar; result.M22 = matrix.M22 - scalar; } /// /// Multiplies two matrices. /// /// A instance. /// A instance. /// A new instance containing the result. public static Matrix2 Multiply(Matrix2 left, Matrix2 right) { return new Matrix2( left.M11 * right.M11 + left.M12 * right.M21, left.M11 * right.M12 + left.M12 * right.M22, left.M21 * right.M11 + left.M22 * right.M21, left.M21 * right.M12 + left.M22 * right.M22 ); } /// /// Multiplies two matrices and put the result in a third matrix. /// /// A instance. /// A instance. /// A instance to hold the result. public static void Multiply(Matrix2 left, Matrix2 right, ref Matrix2 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; } /// /// Transforms a given vector by a matrix. /// /// A instance. /// A instance. /// A new instance containing the result. public static Vector2 Transform(Matrix2 matrix, Vector2 vector) { return new Vector2( (matrix.M11 * vector.X) + (matrix.M12 * vector.Y), (matrix.M21 * vector.X) + (matrix.M22 * vector.Y)); } /// /// Transforms a given vector by a matrix and put the result in a vector. /// /// A instance. /// A instance. /// A instance to hold the result. public static void Transform(Matrix2 matrix, Vector2 vector, ref Vector2 result) { result.X = (matrix.M11 * vector.X) + (matrix.M12 * vector.Y); result.Y = (matrix.M21 * vector.X) + (matrix.M22 * vector.Y); } /// /// Transposes a matrix. /// /// A instance. /// A new instance containing the transposed matrix. public static Matrix2 Transpose(Matrix2 m) { Matrix2 t = new(m); t.Transpose(); return t; } #endregion #region System.Object overrides /// /// Returns the hashcode for this instance. /// /// A 32-bit signed integer hash code. public override int GetHashCode() { return _m11.GetHashCode() ^ _m12.GetHashCode() ^ _m21.GetHashCode() ^ _m22.GetHashCode(); } /// /// Returns a value indicating whether this instance is equal to /// the specified object. /// /// An object to compare to this instance. /// if is a and has the same values as this instance; otherwise, . public override bool Equals(object obj) { if (obj is Matrix2) { Matrix2 m = (Matrix2)obj; return (_m11 == m.M11) && (_m12 == m.M12) && (_m21 == m.M21) && (_m22 == m.M22); } return false; } /// /// Returns a string representation of this object. /// /// A string representation of this object. public override string ToString() { return $"2x2[{_m11}, {_m12}, {_m21}, {_m22}]"; } #endregion #region Public Methods /// /// Calculates the determinant value of the matrix. /// /// The determinant value of the matrix. public float GetDeterminant() { return (_m11 * _m22) - (_m12 * _m21); } /// /// Transposes this matrix. /// public void Transpose() { MathFunctions.Swap(ref _m12, ref _m21); } #endregion #region Comparison Operators /// /// Tests whether two specified matrices are equal. /// /// A instance. /// A instance. /// if the two matrices are equal; otherwise, . public static bool operator ==(Matrix2 left, Matrix2 right) { return ValueType.Equals(left, right); } /// /// Tests whether two specified matrices are not equal. /// /// A instance. /// A instance. /// if the two matrices are not equal; otherwise, . public static bool operator !=(Matrix2 left, Matrix2 right) { return !ValueType.Equals(left, right); } #endregion #region Binary Operators /// /// Adds two matrices. /// /// A instance. /// A instance. /// A new instance containing the sum. public static Matrix2 operator +(Matrix2 left, Matrix2 right) { return Matrix2.Add(left, right); } /// /// Adds a matrix and a scalar. /// /// A instance. /// A single-precision floating-point number. /// A new instance containing the sum. public static Matrix2 operator +(Matrix2 matrix, float scalar) { return Matrix2.Add(matrix, scalar); } /// /// Adds a matrix and a scalar. /// /// A instance. /// A single-precision floating-point number. /// A new instance containing the sum. public static Matrix2 operator +(float scalar, Matrix2 matrix) { return Matrix2.Add(matrix, scalar); } /// /// Subtracts a matrix from a matrix. /// /// A instance. /// A instance. /// A new instance containing the difference. public static Matrix2 operator -(Matrix2 left, Matrix2 right) { return Matrix2.Subtract(left, right); } /// /// Subtracts a scalar from a matrix. /// /// A instance. /// A single-precision floating-point number. /// A new instance containing the difference. public static Matrix2 operator -(Matrix2 matrix, float scalar) { return Matrix2.Subtract(matrix, scalar); } /// /// Multiplies two matrices. /// /// A instance. /// A instance. /// A new instance containing the result. public static Matrix2 operator *(Matrix2 left, Matrix2 right) { return Matrix2.Multiply(left, right); } /// /// Transforms a given vector by a matrix. /// /// A instance. /// A instance. /// A new instance containing the result. public static Vector2 operator *(Matrix2 matrix, Vector2 vector) { return Matrix2.Transform(matrix, vector); } #endregion #region Indexing Operators /// /// Indexer allowing to access the matrix elements by an index /// where index = 2*row + column. /// public unsafe float this[int index] { get { if (index < 0 || index >= 4) throw new IndexOutOfRangeException("Invalid matrix index!"); fixed (float* f = &_m11) { return *(f + index); } } set { if (index < 0 || index >= 4) throw new IndexOutOfRangeException("Invalid matrix index!"); fixed (float* f = &_m11) { *(f + index) = value; } } } /// /// Indexer allowing to access the matrix elements by row and column. /// public float this[int row, int column] { get { return this[(row - 1) * 2 + (column - 1)]; } set { this[(row - 1) * 2 + (column - 1)] = value; } } #endregion } }