using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Ximmerse.XR.Internal.Mathmatics
{
///
/// A 3x3 matrix struct.
/// Performative to represent quaternion.
///
[System.Serializable]
internal struct Matrix3x3
{
///
/// Gets a identity matrix.
///
public static Matrix3x3 identity
{
get
{
return new Matrix3x3(1, 0, 0, 0, 1, 0, 0, 0, 1);
}
}
///
/// Row 0
///
[SerializeField]
float m_m00, m_m01, m_m02;
///
/// Row 1
///
[SerializeField]
float m_m10, m_m11, m_m12;
///
/// Row 2
///
[SerializeField]
float m_m20, m_m21, m_m22;
///
/// Row 0, Col 0
///
public float m00
{
get => m_m00;
}
///
/// Row 0, Col 1
///
public float m01
{
get => m_m01;
}
///
/// Row 0, Col 2
///
public float m02
{
get => m_m02;
}
///
/// Row 1, Col 0
///
public float m10
{
get => m_m10;
}
///
/// Row 1, Col 1
///
public float m11
{
get => m_m11;
}
///
/// Row 1, Col 2
///
public float m12
{
get => m_m12;
}
///
/// Row 2, Col 0
///
public float m20
{
get => m_m20;
}
///
/// Row 2, Col 1
///
public float m21
{
get => m_m21;
}
///
/// Row 2, Col 2
///
public float m22
{
get => m_m22;
}
///
/// Gets element by row/col
///
///
///
///
public float this[int row, int col]
{
get
{
if (row == 0 && col == 0)
{
return m_m00;
}
if (row == 0 && col == 1)
{
return m_m01;
}
if (row == 0 && col == 2)
{
return m_m02;
}
if (row == 1 && col == 0)
{
return m_m10;
}
if (row == 1 && col == 1)
{
return m_m11;
}
if (row == 1 && col == 2)
{
return m_m12;
}
if (row == 2 && col == 0)
{
return m_m20;
}
if (row == 2 && col == 1)
{
return m_m21;
}
if (row == 2 && col == 2)
{
return m_m22;
}
throw new UnityException(string.Format("Invalid format : {0},{1}", row, col));
}
}
///
/// Ctor of matrix 3x3
///
///
///
///
///
///
///
///
///
///
public Matrix3x3(float m00, float m01, float m02, float m10, float m11, float m12, float m20, float m21, float m22)
{
m_m00 = m00;
m_m01 = m01;
m_m02 = m02;
m_m10 = m10;
m_m11 = m11;
m_m12 = m12;
m_m20 = m20;
m_m21 = m21;
m_m22 = m22;
}
///
/// Ctor a matrix3x3 by 2 vector3 of row and col.
///
/// A vector3 of represents column.
/// A vector3 of represents row.
public Matrix3x3(Vector3 col, Vector3 row)
{
m_m00 = col.x * row.x;
m_m01 = col.x * row.y;
m_m02 = col.x * row.z;
m_m10 = col.y * row.x;
m_m11 = col.y * row.y;
m_m12 = col.y * row.z;
m_m20 = col.z * row.x;
m_m21 = col.z * row.y;
m_m22 = col.z * row.z;
}
///
/// Ctor of matrix 3x3 by quaternion.
///
///
public Matrix3x3(Quaternion q)
{
m_m00 = 1.0f - 2.0f * (q.y * q.y + q.z * q.z);
m_m10 = (q.x * q.y + q.z * q.w) * 2.0f;
m_m20 = (q.x * q.z - q.y * q.w) * 2.0f;
m_m01 = (q.x * q.y - q.z * q.w) * 2.0f;
m_m11 = 1.0f - 2.0f * (q.x * q.x + q.z * q.z);
m_m21 = (q.y * q.z + q.x * q.w) * 2.0f;
m_m02 = (q.x * q.z + q.y * q.w) * 2.0f;
m_m12 = (q.y * q.z - q.x * q.w) * 2.0f;
m_m22 = 1.0f - 2.0f * (q.x * q.x + q.y * q.y);
}
///
/// Sets this matrix3x3 by the quaternion.
///
///
public void SetRotation(Quaternion q)
{
m_m00 = 1.0f - 2.0f * (q.y * q.y + q.z * q.z);
m_m10 = (q.x * q.y + q.z * q.w) * 2.0f;
m_m20 = (q.x * q.z - q.y * q.w) * 2.0f;
m_m01 = (q.x * q.y - q.z * q.w) * 2.0f;
m_m11 = 1.0f - 2.0f * (q.x * q.x + q.z * q.z);
m_m21 = (q.y * q.z + q.x * q.w) * 2.0f;
m_m02 = (q.x * q.z + q.y * q.w) * 2.0f;
m_m12 = (q.y * q.z - q.x * q.w) * 2.0f;
m_m22 = 1.0f - 2.0f * (q.x * q.x + q.y * q.y);
}
///
/// Transpose this 3x3 matrix.
///
///
public Matrix3x3 transpose
{
get => new Matrix3x3(m00, m10, m20, m01, m11, m21, m02, m12, m22);
}
///
/// Composite a rotation 3x3 matrix and a position to a matrix4x4 translation matrix.
///
///
///
///
public static Matrix4x4 ToTRS(Matrix3x3 RotationMatrix, Vector3 position)
{
Matrix4x4 trs = Matrix4x4.identity;
trs.SetRow(0, new Vector4(RotationMatrix.m00, RotationMatrix.m01, RotationMatrix.m02, position.x));
trs.SetRow(1, new Vector4(RotationMatrix.m10, RotationMatrix.m11, RotationMatrix.m12, position.y));
trs.SetRow(2, new Vector4(RotationMatrix.m20, RotationMatrix.m21, RotationMatrix.m22, position.z));
return trs;
}
///
/// Assumes the matrix3x3 represents a quaternion rotation.
/// Thread safe function.
///
///
///
public Quaternion GetRotation()
{
float fourXSquaredMinus1 = m_m00 - m_m11 - m_m22;
float fourYSquaredMinus1 = m_m11 - m_m00 - m_m22;
float fourZSquaredMinus1 = m_m22 - m_m00 - m_m11;
float fourWSquaredMinus1 = m_m00 + m_m11 + m_m22;
int biggestIndex = 0;
float fourBiggestSquaredMinus1 = fourWSquaredMinus1;
if (fourXSquaredMinus1 > fourBiggestSquaredMinus1)
{
fourBiggestSquaredMinus1 = fourXSquaredMinus1;
biggestIndex = 1;
}
if (fourYSquaredMinus1 > fourBiggestSquaredMinus1)
{
fourBiggestSquaredMinus1 = fourYSquaredMinus1;
biggestIndex = 2;
}
if (fourZSquaredMinus1 > fourBiggestSquaredMinus1)
{
fourBiggestSquaredMinus1 = fourZSquaredMinus1;
biggestIndex = 3;
}
float biggestVal = Mathf.Sqrt(fourBiggestSquaredMinus1 + 1) * 0.5f;
float mult = 0.25f / biggestVal;
Quaternion q = Quaternion.identity;
switch (biggestIndex)
{
case 0:
q.w = biggestVal;
q.x = (m_m12 - m_m21) * mult;
q.y = (m_m20 - m_m02) * mult;
q.z = (m_m01 - m_m10) * mult;
break;
case 1:
q.w = (m_m12 - m_m21) * mult;
q.x = biggestVal;
q.y = (m_m01 + m_m10) * mult;
q.z = (m_m20 + m_m02) * mult;
break;
case 2:
q.w = (m_m20 - m_m02) * mult;
q.x = (m_m01 + m_m10) * mult;
q.y = biggestVal;
q.z = (m_m12 + m_m21) * mult;
break;
case 3:
q.w = (m_m01 - m_m10) * mult;
q.x = (m_m20 + m_m02) * mult;
q.y = (m_m12 + m_m21) * mult;
q.z = biggestVal;
break;
default: // Silence a -Wswitch-default warning in GCC. Should never actually get here. Assert is just for sanity.
break;
}
float e = 1 / (q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w);
return new Quaternion(-q.x * e, -q.y * e, -q.z * e, q.w * e);
}
///
/// Gets row at the index of the matrix3x3
///
///
///
public Vector3 GetRow(int RowIndex)
{
switch (RowIndex)
{
case 0:
return new Vector3(m00, m01, m02);
case 1:
return new Vector3(m10, m11, m12);
case 2:
return new Vector3(m20, m21, m22);
default:
throw new UnityException(string.Format("Invalid index: {0}", RowIndex));
}
}
///
/// Gets column at the index of the matrix3x3
///
///
///
public Vector3 GetColumn(int ColumnIndex)
{
switch (ColumnIndex)
{
case 0:
return new Vector3(m00, m10, m20);
case 1:
return new Vector3(m01, m11, m21);
case 2:
return new Vector3(m02, m12, m22);
default:
throw new UnityException(string.Format("Invalid index: {0}", ColumnIndex));
}
}
public static Matrix3x3 operator *(float lhs, Matrix3x3 rhs)
{
return new Matrix3x3(lhs * rhs.m00, lhs * rhs.m01, lhs * rhs.m02,
lhs * rhs.m10, lhs * rhs.m11, lhs * rhs.m12,
lhs * rhs.m20, lhs * rhs.m21, lhs * rhs.m22);
}
public static Matrix3x3 operator *(Matrix3x3 lhs, float rhs)
{
return new Matrix3x3(rhs * lhs.m00, rhs * lhs.m01, rhs * lhs.m02,
rhs * lhs.m10, rhs * lhs.m11, rhs * lhs.m12,
rhs * lhs.m20, rhs * lhs.m21, rhs * lhs.m22);
}
///
/// Multiple two matrix3x3
///
///
///
///
public static Matrix3x3 operator *(Matrix3x3 lhs, Matrix3x3 rhs)
{
Vector3 lRow0 = lhs.GetRow(0);
Vector3 lRow1 = lhs.GetRow(1);
Vector3 lRow2 = lhs.GetRow(2);
Vector3 rRow0 = rhs.GetRow(0);
Vector3 rRow1 = rhs.GetRow(1);
Vector3 rRow2 = rhs.GetRow(2);
Matrix3x3 result = new Matrix3x3(
m00: lRow0.x * rRow0.x + lRow0.y * rRow1.x + lRow0.z * rRow2.x,
m01: lRow0.x * rRow0.y + lRow0.y * rRow1.y + lRow0.z * rRow2.y,
m02: lRow0.x * rRow0.z + lRow0.y * rRow1.z + lRow0.z * rRow2.z,
m10: lRow1.x * rRow0.x + lRow1.y * rRow1.x + lRow1.z * rRow2.x,
m11: lRow1.x * rRow0.y + lRow1.y * rRow1.y + lRow1.z * rRow2.y,
m12: lRow1.x * rRow0.z + lRow1.y * rRow1.z + lRow1.z * rRow2.z,
m20: lRow2.x * rRow0.x + lRow2.y * rRow1.x + lRow2.z * rRow2.x,
m21: lRow2.x * rRow0.y + lRow2.y * rRow1.y + lRow2.z * rRow2.y,
m22: lRow2.x * rRow0.z + lRow2.y * rRow1.z + lRow2.z * rRow2.z
);
return result;
}
///
/// Plus lhs to rhs
///
///
///
///
public static Matrix3x3 operator +(Matrix3x3 lhs, Matrix3x3 rhs)
{
return new Matrix3x3(lhs.m00 + rhs.m00, lhs.m01 + rhs.m01, lhs.m02 + rhs.m02,
lhs.m10 + rhs.m10, lhs.m11 + rhs.m11, lhs.m12 + rhs.m12,
lhs.m20 + rhs.m20, lhs.m21 + rhs.m21, lhs.m22 + rhs.m22);
}
///
/// Minus lhs to rhs
///
///
///
///
public static Matrix3x3 operator -(Matrix3x3 lhs, Matrix3x3 rhs)
{
return new Matrix3x3(lhs.m00 - rhs.m00, lhs.m01 - rhs.m01, lhs.m02 - rhs.m02,
lhs.m10 - rhs.m10, lhs.m11 - rhs.m11, lhs.m12 - rhs.m12,
lhs.m20 - rhs.m20, lhs.m21 - rhs.m21, lhs.m22 - rhs.m22);
}
///
/// Multiple lhs by rhs Vector3
///
///
///
///
public static Vector3 operator *(Matrix3x3 lhs, Vector3 rhs)
{
Vector3 lCol0 = lhs.GetColumn(0);
Vector3 lCol1 = lhs.GetColumn(1);
Vector3 lCol2 = lhs.GetColumn(2);
return lCol0 * rhs.x + lCol1 * rhs.y + lCol2 * rhs.z;
}
public override string ToString()
{
return string.Format("[{0}, {1}, {2}]\r\n[{3}, {4}, {5}]\r\n[{6}, {7}, {8}]", m00, m01, m02,
m10, m11, m12,
m20, m21, m22);
}
public string ToString(string format)
{
return string.Format("[{0}, {1}, {2}]\r\n[{3}, {4}, {5}]\r\n[{6}, {7}, {8}]", m00.ToString(format), m01.ToString(format), m02.ToString(format),
m10.ToString(format), m11.ToString(format), m12.ToString(format),
m20.ToString(format), m21.ToString(format), m22.ToString(format));
}
}
}