/// <summary>Attempts to invert the given matrix. If the operation succeeds, the inverted matrix is stored in the result parameter.</summary> /// <param name="matrix">The source matrix.</param> /// <param name="result">The output matrix.</param> /// <returns>True if the operation succeeded, False otherwise.</returns> public static bool Invert <T>(Matrix3X2 <T> matrix, out Matrix3X2 <T> result) where T : unmanaged, IFormattable, IEquatable <T>, IComparable <T> { T det = Scalar.Subtract(Scalar.Multiply(matrix.M11, matrix.M22), Scalar.Multiply(matrix.M21, matrix.M12)); if (!Scalar.GreaterThanOrEqual(Scalar.Abs(det), Scalar <T> .Epsilon)) { result = new(Scalar <T> .NaN, Scalar <T> .NaN, Scalar <T> .NaN, Scalar <T> .NaN, Scalar <T> .NaN, Scalar <T> .NaN); return(false); } T invDet = Scalar.Reciprocal(det); result = default; result.M11 = Scalar.Multiply(matrix.M22, invDet); result.M12 = Scalar.Negate(Scalar.Multiply(matrix.M12, invDet)); result.M21 = Scalar.Negate(Scalar.Multiply(matrix.M21, invDet)); result.M22 = Scalar.Multiply(matrix.M11, invDet); result.M31 = Scalar.Multiply(Scalar.Subtract(Scalar.Multiply(matrix.M21, matrix.M32), Scalar.Multiply(matrix.M31, matrix.M22)), invDet); result.M32 = Scalar.Multiply(Scalar.Subtract(Scalar.Multiply(matrix.M31, matrix.M12), Scalar.Multiply(matrix.M11, matrix.M32)), invDet); return(true); }
/// <summary>Creates a skew matrix from the given angles in radians and a center point.</summary> /// <param name="radiansX">The X angle, in radians.</param> /// <param name="radiansY">The Y angle, in radians.</param> /// <param name="centerPoint">The center point.</param> /// <returns>A skew matrix.</returns> public static Matrix3X2 <T> CreateSkew <T>(T radiansX, T radiansY, Vector2D <T> centerPoint) where T : unmanaged, IFormattable, IEquatable <T>, IComparable <T> { Matrix3X2 <T> result = Matrix3X2 <T> .Identity; T xTan = Scalar.Tan(radiansX); T yTan = Scalar.Tan(radiansY); T tx = Scalar.Negate(Scalar.Multiply(centerPoint.Y, xTan)); T ty = Scalar.Negate(Scalar.Multiply(centerPoint.X, yTan)); result.M12 = yTan; result.M21 = xTan; result.M31 = tx; result.M32 = ty; return(result); }
/// <summary>Creates a matrix for rotating points around the Z-axis.</summary> /// <param name="radians">The amount, in radians, by which to rotate around the Z-axis.</param> /// <returns>The rotation matrix.</returns> public static Matrix3X3 <T> CreateRotationZ <T>(T radians) where T : unmanaged, IFormattable, IEquatable <T>, IComparable <T> { Matrix3X3 <T> result = Matrix3X3 <T> .Identity; T c = Scalar.Cos(radians); T s = Scalar.Sin(radians); // [ c s 0 0 ] // [ -s c 0 0 ] // [ 0 0 1 0 ] // [ 0 0 0 1 ] result.M11 = c; result.M12 = s; result.M21 = Scalar.Negate(s); result.M22 = c; return(result); }
/// <summary>Creates a matrix for rotating points around the Y-axis.</summary> /// <param name="radians">The amount, in radians, by which to rotate around the Y-axis.</param> /// <returns>The rotation matrix.</returns> public static Matrix3X3 <T> CreateRotationY <T>(T radians) where T : unmanaged, IFormattable, IEquatable <T>, IComparable <T> { Matrix3X3 <T> result = Matrix3X3 <T> .Identity; T c = Scalar.Cos(radians); T s = Scalar.Sin(radians); // [ c 0 -s 0 ] // [ 0 1 0 0 ] // [ s 0 c 0 ] // [ 0 0 0 1 ] result.M11 = c; result.M13 = Scalar.Negate(s); result.M31 = s; result.M33 = c; return(result); }
public static Plane <T> CreateFromVertices <T>(Vector3D <T> point1, Vector3D <T> point2, Vector3D <T> point3) where T : unmanaged, IFormattable, IEquatable <T>, IComparable <T> { var a = point1; var b = point2; var c = point3; var ab = b - a; var ac = c - a; var cross = Vector3D.Cross(ab, ac); Plane <T> p; p.Normal = cross; p.Distance = Scalar.Negate(Scalar.Add( Scalar.Add(Scalar.Multiply(p.Normal.X, a.X), Scalar.Multiply(p.Normal.Y, a.Y)), Scalar.Multiply(p.Normal.Z, a.Z))); return(p); /*if (Vector.IsHardwareAccelerated) * { * Vector3D<T> a = point2 - point1; * Vector3D<T> b = point3 - point1; * * // N = Cross(a, b) * Vector3D<T> n = Vector3D.Cross(a, b); * Vector3D<T> normal = Vector3D.Normalize(n); * * // D = - Dot(N, point1) * T d = Scalar.Negate(Vector3D.Dot(normal, point1)); * * return new Plane<T>(normal, d); * } * else * { * T ax = Scalar.Subtract(point2.X, point1.X); * T ay = Scalar.Subtract(point2.Y, point1.Y); * T az = Scalar.Subtract(point2.Z, point1.Z); * * T bx = Scalar.Subtract(point3.X, point1.X); * T by = Scalar.Subtract(point3.Y, point1.Y); * T bz = Scalar.Subtract(point3.Z, point1.Z); * * // N=Cross(a,b) * T nx = Scalar.Subtract(Scalar.Multiply(ay, bz), Scalar.Multiply(az, by)); * T ny = Scalar.Subtract(Scalar.Multiply(az, bx), Scalar.Multiply(ax, bz)); * T nz = Scalar.Subtract(Scalar.Multiply(ax, by), Scalar.Multiply(ay, bx)); * * // Normalize(N) * T ls = Scalar.Add(Scalar.Add(Scalar.Multiply(nx, nx), Scalar.Multiply(ny, ny)), Scalar.Multiply(nz, nz)); * T invNorm = Scalar.Inverse(Scalar.Sqrt(ls)); * * Vector3D<T> normal = new Vector3D<T>( * Scalar.Multiply(nx, invNorm), * Scalar.Multiply(ny, invNorm), * Scalar.Multiply(nz, invNorm)); * * return new(normal, * Scalar.Negate(Scalar.Add( * Scalar.Add(Scalar.Multiply(normal.X, point1.X), * Scalar.Multiply(normal.Y, point1.Y)), Scalar.Multiply(normal.Z, point1.Z)))); * }*/ }
/// <summary>Creates a rotation matrix using the given rotation in radians.</summary> /// <param name="radians">The amount of rotation, in radians.</param> /// <returns>A rotation matrix.</returns> public static Matrix3X2 <T> CreateRotation <T>(T radians) where T : unmanaged, IFormattable, IEquatable <T>, IComparable <T> { radians = Scalar.IEEERemainder(radians, Scalar <T> .Tau); T c, s; if (Scalar.GreaterThan(radians, Scalar.As <float, T>(-RotationEpsilon)) && !Scalar.GreaterThanOrEqual(radians, Scalar.As <float, T>(RotationEpsilon))) { // Exact case for zero rotation. c = Scalar <T> .One; s = Scalar <T> .Zero; } else if (Scalar.GreaterThan(radians, Scalar.As <float, T>( #if MATHF MathF.PI #else ((float)Math.PI) #endif / 2 - RotationEpsilon)) && !Scalar.GreaterThanOrEqual(radians, Scalar.As <float, T>( #if MATHF MathF.PI #else ((float)Math.PI) #endif / 2 + RotationEpsilon))) { // Exact case for 90 degree rotation. c = Scalar <T> .Zero; s = Scalar <T> .One; } else if (!Scalar.GreaterThanOrEqual(radians, Scalar.As <float, T>(- #if MATHF MathF.PI #else ((float)Math.PI) #endif + RotationEpsilon)) || Scalar.GreaterThan(radians, Scalar.As <float, T>( #if MATHF MathF.PI #else ((float)Math.PI) #endif - RotationEpsilon))) { // Exact case for 180 degree rotation. c = Scalar <T> .MinusOne; s = Scalar <T> .Zero; } else if (Scalar.GreaterThan(radians, Scalar.As <float, T>(- #if MATHF MathF.PI #else ((float)Math.PI) #endif / 2 - RotationEpsilon)) && !Scalar.GreaterThanOrEqual(radians, Scalar.As <float, T>(- #if MATHF MathF.PI #else ((float)Math.PI) #endif / 2 + RotationEpsilon))) { // Exact case for 270 degree rotation. c = Scalar <T> .Zero; s = Scalar <T> .MinusOne; } else { // Arbitrary rotation. c = Scalar.Cos(radians); s = Scalar.Sin(radians); } // [ c s ] // [ -s c ] // [ 0 0 ] Matrix3X2 <T> result = Matrix3X2 <T> .Identity; result.M11 = c; result.M12 = s; result.M21 = Scalar.Negate(s); result.M22 = c; return(result); }
/// <summary>Creates a rotation matrix using the given rotation in radians and a center point.</summary> /// <param name="radians">The amount of rotation, in radians.</param> /// <param name="centerPoint">The center point.</param> /// <returns>A rotation matrix.</returns> public static Matrix3X2 <T> CreateRotation <T>(T radians, Vector2D <T> centerPoint) where T : unmanaged, IFormattable, IEquatable <T>, IComparable <T> { radians = Scalar.IEEERemainder(radians, Scalar <T> .Tau); T c, s; if (Scalar.GreaterThan(radians, Scalar.As <float, T>(-RotationEpsilon)) && !Scalar.GreaterThanOrEqual(radians, Scalar.As <float, T>(RotationEpsilon))) { // Exact case for zero rotation. c = Scalar <T> .One; s = Scalar <T> .Zero; } else if (Scalar.GreaterThan(radians, Scalar.As <float, T>( #if MATHF MathF.PI #else ((float)Math.PI) #endif / 2 - RotationEpsilon)) && !Scalar.GreaterThanOrEqual(radians, Scalar.As <float, T>( #if MATHF MathF.PI #else ((float)Math.PI) #endif / 2 + RotationEpsilon))) { // Exact case for 90 degree rotation. c = Scalar <T> .Zero; s = Scalar <T> .One; } else if (!Scalar.GreaterThanOrEqual(radians, Scalar.As <float, T>(- #if MATHF MathF.PI #else ((float)Math.PI) #endif + RotationEpsilon)) || Scalar.GreaterThan(radians, Scalar.As <float, T>( #if MATHF MathF.PI #else ((float)Math.PI) #endif - RotationEpsilon))) { // Exact case for 180 degree rotation. c = Scalar <T> .MinusOne; s = Scalar <T> .Zero; } else if (Scalar.GreaterThan(radians, Scalar.As <float, T>(- #if MATHF MathF.PI #else ((float)Math.PI) #endif / 2 - RotationEpsilon)) && !Scalar.GreaterThanOrEqual(radians, Scalar.As <float, T>(- #if MATHF MathF.PI #else ((float)Math.PI) #endif / 2 + RotationEpsilon))) { // Exact case for 270 degree rotation. c = Scalar <T> .Zero; s = Scalar <T> .MinusOne; } else { // Arbitrary rotation. c = Scalar.Cos(radians); s = Scalar.Sin(radians); } T x = Scalar.Add(Scalar.Multiply(centerPoint.X, Scalar.Subtract(Scalar <T> .One, c)), Scalar.Multiply(centerPoint.Y, s)); T y = Scalar.Subtract(Scalar.Multiply(centerPoint.Y, Scalar.Subtract(Scalar <T> .One, c)), Scalar.Multiply(centerPoint.X, s)); // [ c s ] // [ -s c ] // [ x y ] return(new( new(c, s), new(Scalar.Negate(s), c), new(x, y))); }
/// <summary>Attempts to extract the scale, translation, and rotation components from the given scale/rotation/translation matrix. /// If successful, the out parameters will contained the extracted values.</summary> /// <param name="matrix">The source matrix.</param> /// <param name="scale">The scaling component of the transformation matrix.</param> /// <param name="rotation">The rotation component of the transformation matrix.</param> /// <returns>True if the source matrix was successfully decomposed; False otherwise.</returns> public static bool Decompose <T>(Matrix3X3 <T> matrix, out Vector3D <T> scale, out Quaternion <T> rotation) where T : unmanaged, IFormattable, IEquatable <T>, IComparable <T> { bool result = true; unsafe { fixed(Vector3D <T> *scaleBase = &scale) { T *pfScales = (T *)scaleBase; T det; VectorBasis <T> vectorBasis; Vector3D <T> ** pVectorBasis = (Vector3D <T> **) & vectorBasis; Matrix3X3 <T> matTemp = Matrix3X3 <T> .Identity; CanonicalBasis <T> canonicalBasis = default; Vector3D <T> * pCanonicalBasis = &canonicalBasis.Row0; canonicalBasis.Row0 = new Vector3D <T>(Scalar <T> .One, Scalar <T> .Zero, Scalar <T> .Zero); canonicalBasis.Row1 = new Vector3D <T>(Scalar <T> .Zero, Scalar <T> .One, Scalar <T> .Zero); canonicalBasis.Row2 = new Vector3D <T>(Scalar <T> .Zero, Scalar <T> .Zero, Scalar <T> .One); pVectorBasis[0] = &matTemp.Row1; pVectorBasis[1] = &matTemp.Row2; pVectorBasis[2] = &matTemp.Row3; *(pVectorBasis[0]) = new Vector3D <T>(matrix.M11, matrix.M12, matrix.M13); *(pVectorBasis[1]) = new Vector3D <T>(matrix.M21, matrix.M22, matrix.M23); *(pVectorBasis[2]) = new Vector3D <T>(matrix.M31, matrix.M32, matrix.M33); scale.X = pVectorBasis[0]->Length; scale.Y = pVectorBasis[1]->Length; scale.Z = pVectorBasis[2]->Length; uint a, b, c; #region Ranking T x = pfScales[0], y = pfScales[1], z = pfScales[2]; if (!Scalar.GreaterThanOrEqual(x, y)) { if (!Scalar.GreaterThanOrEqual(y, z)) { a = 2; b = 1; c = 0; } else { a = 1; if (!Scalar.GreaterThanOrEqual(x, z)) { b = 2; c = 0; } else { b = 0; c = 2; } } } else { if (!Scalar.GreaterThanOrEqual(x, z)) { a = 2; b = 0; c = 1; } else { a = 0; if (!Scalar.GreaterThanOrEqual(y, z)) { b = 2; c = 1; } else { b = 1; c = 2; } } } #endregion if (!Scalar.GreaterThanOrEqual(pfScales[a], Scalar.As <float, T>(DecomposeEpsilon))) { *(pVectorBasis[a]) = pCanonicalBasis[a]; } *pVectorBasis[a] = Vector3D.Normalize(*pVectorBasis[a]); if (!Scalar.GreaterThanOrEqual(pfScales[b], Scalar.As <float, T>(DecomposeEpsilon))) { uint cc; T fAbsX, fAbsY, fAbsZ; fAbsX = Scalar.Abs(pVectorBasis[a]->X); fAbsY = Scalar.Abs(pVectorBasis[a]->Y); fAbsZ = Scalar.Abs(pVectorBasis[a]->Z); #region Ranking if (!Scalar.GreaterThanOrEqual(fAbsX, fAbsY)) { if (!Scalar.GreaterThanOrEqual(fAbsY, fAbsZ)) { cc = 0; } else { if (!Scalar.GreaterThanOrEqual(fAbsX, fAbsZ)) { cc = 0; } else { cc = 2; } } } else { if (!Scalar.GreaterThanOrEqual(fAbsX, fAbsZ)) { cc = 1; } else { if (!Scalar.GreaterThanOrEqual(fAbsY, fAbsZ)) { cc = 1; } else { cc = 2; } } } #endregion *pVectorBasis[b] = Vector3D.Cross(*pVectorBasis[a], *(pCanonicalBasis + cc)); } *pVectorBasis[b] = Vector3D.Normalize(*pVectorBasis[b]); if (!Scalar.GreaterThanOrEqual(pfScales[c], Scalar.As <float, T>(DecomposeEpsilon))) { *pVectorBasis[c] = Vector3D.Cross(*pVectorBasis[a], *pVectorBasis[b]); } *pVectorBasis[c] = Vector3D.Normalize(*pVectorBasis[c]); det = matTemp.GetDeterminant(); // use Kramer's rule to check for handedness of coordinate system if (!Scalar.GreaterThanOrEqual(det, Scalar <T> .Zero)) { // switch coordinate system by negating the scale and inverting the basis vector on the x-axis pfScales[a] = Scalar.Negate(pfScales[a]); *pVectorBasis[a] = -(*pVectorBasis[a]); det = Scalar.Negate(det); } det = Scalar.Subtract(det, Scalar <T> .One); det = Scalar.Multiply(det, det); if (!Scalar.GreaterThanOrEqual(Scalar.As <float, T>(DecomposeEpsilon), det)) { // Non-SRT matrix encountered rotation = Quaternion <T> .Identity; result = false; } else { // generate the quaternion from the matrix rotation = Quaternion <T> .CreateFromRotationMatrix(matTemp); } } } return(result); }