// ----------------------------------------------------------------------- // // Copyright 2013 MIT Licence. See licence.md for more information. // // ----------------------------------------------------------------------- namespace Perspex { using System; using System.Globalization; /// /// A 2x3 matrix. /// public struct Matrix { private double m11; private double m12; private double m21; private double m22; private double m31; private double m32; /// /// Initializes a new instance of the struct. /// /// The first element of the first row. /// The second element of the first row. /// The first element of the second row. /// The second element of the second row. /// The first element of the third row. /// The second element of the third row. public Matrix( double m11, double m12, double m21, double m22, double offsetX, double offsetY) { this.m11 = m11; this.m12 = m12; this.m21 = m21; this.m22 = m22; this.m31 = offsetX; this.m32 = offsetY; } /// /// Returns the multiplicative identity matrix. /// public static Matrix Identity { get { return new Matrix(1.0, 0.0, 0.0, 1.0, 0.0, 0.0); } } /// /// Returns whether the matrix is the identity matrix. /// public bool IsIdentity { get { return this.Equals(Matrix.Identity); } } /// /// The first element of the first row /// public double M11 { get { return this.m11; } } /// /// The second element of the first row /// public double M12 { get { return this.m12; } } /// /// The first element of the second row /// public double M21 { get { return this.m21; } } /// /// The second element of the second row /// public double M22 { get { return this.m22; } } /// /// The first element of the third row /// public double M31 { get { return this.m31; } } /// /// The second element of the third row /// public double M32 { get { return this.m32; } } /// /// Multiplies two matrices together and returns the resulting matrix. /// /// The first source matrix. /// The second source matrix. /// The product matrix. public static Matrix operator *(Matrix value1, Matrix value2) { return new Matrix( (value1.M11 * value2.M11) + (value1.M12 * value2.M21), (value1.M11 * value2.M12) + (value1.M12 * value2.M22), (value1.M21 * value2.M11) + (value1.M22 * value2.M21), (value1.M21 * value2.M12) + (value1.M22 * value2.M22), (value1.m31 * value2.M11) + (value1.m32 * value2.M21) + value2.m31, (value1.m31 * value2.M12) + (value1.m32 * value2.M22) + value2.m32); } /// /// Negates the given matrix by multiplying all values by -1. /// /// The source matrix. /// The negated matrix. public static Matrix operator -(Matrix value) { return value.Invert(); } /// /// Returns a boolean indicating whether the given matrices are equal. /// /// The first source matrix. /// The second source matrix. /// True if the matrices are equal; False otherwise. public static bool operator ==(Matrix value1, Matrix value2) { return value1.Equals(value2); } /// /// Returns a boolean indicating whether the given matrices are not equal. /// /// The first source matrix. /// The second source matrix. /// True if the matrices are not equal; False if they are equal. public static bool operator !=(Matrix value1, Matrix value2) { return !value1.Equals(value2); } /// /// Creates a rotation matrix using the given rotation in radians. /// /// The amount of rotation, in radians. /// A rotation matrix. public static Matrix CreateRotation(double radians) { double cos = Math.Cos(radians); double sin = Math.Sin(radians); return new Matrix(cos, sin, -sin, cos, 0, 0); } /// /// Creates a scale matrix from the given X and Y components. /// /// Value to scale by on the X-axis. /// Value to scale by on the Y-axis. /// A scaling matrix. public static Matrix CreateScale(double xScale, double yScale) { return CreateScale(new Vector(xScale, yScale)); } /// /// Creates a scale matrix from the given vector scale. /// /// The scale to use. /// A scaling matrix. public static Matrix CreateScale(Vector scales) { return new Matrix(scales.X, 0, 0, scales.Y, 0, 0); } /// /// Creates a translation matrix from the given vector. /// /// The translation position. /// A translation matrix. public static Matrix CreateTranslation(Vector position) { return CreateTranslation(position.X, position.Y); } /// /// Creates a translation matrix from the given X and Y components. /// /// The X position. /// The Y position. /// A translation matrix. public static Matrix CreateTranslation(double xPosition, double yPosition) { return new Matrix(1.0, 0.0, 0.0, 1.0, xPosition, yPosition); } /// /// Converts an ange in degrees to radians. /// /// The angle in degrees. /// The angle in radians. public static double ToRadians(double angle) { return angle * 0.0174532925; } /// /// Calculates the determinant for this matrix. /// /// The determinant. /// /// The determinant is calculated by expanding the matrix with a third column whose /// values are (0,0,1). /// public double GetDeterminant() { return (this.m11 * this.m22) - (this.m12 * this.m21); } /// /// Returns a boolean indicating whether the matrix is equal to the other given matrix. /// /// The other matrix to test equality against. /// True if this matrix is equal to other; False otherwise. public bool Equals(Matrix other) { return this.m11 == other.M11 && this.m12 == other.M12 && this.m21 == other.M21 && this.m22 == other.M22 && this.m31 == other.M31 && this.m32 == other.M32; } /// /// Returns a boolean indicating whether the given Object is equal to this matrix instance. /// /// The Object to compare against. /// True if the Object is equal to this matrix; False otherwise. public override bool Equals(object obj) { if (!(obj is Matrix)) { return false; } return this.Equals((Matrix)obj); } /// /// Returns the hash code for this instance. /// /// The hash code. public override int GetHashCode() { return this.M11.GetHashCode() + this.M12.GetHashCode() + this.M21.GetHashCode() + this.M22.GetHashCode() + this.M31.GetHashCode() + this.M32.GetHashCode(); } /// /// Returns a String representing this matrix instance. /// /// The string representation. public override string ToString() { CultureInfo ci = CultureInfo.CurrentCulture; return string.Format( ci, "{{ {{M11:{0} M12:{1}}} {{M21:{2} M22:{3}}} {{M31:{4} M32:{5}}} }}", this.M11.ToString(ci), this.M12.ToString(ci), this.M21.ToString(ci), this.M22.ToString(ci), this.M31.ToString(ci), this.M32.ToString(ci)); } /// /// Inverts the Matrix. /// /// The inverted matrix. public Matrix Invert() { if (this.GetDeterminant() == 0) { throw new InvalidOperationException("Transform is not invertible."); } double d = this.GetDeterminant(); return new Matrix( this.m22 / d, -this.m12 / d, -this.m21 / d, this.m11 / d, ((this.m21 * this.m32) - (this.m22 * this.m31)) / d, ((this.m12 * this.m31) - (this.m11 * this.m32)) / d); } } }