Implement Matrix4x4::Determinant4 IsIdentity

This commit is contained in:
2024-07-10 14:19:46 -04:00
parent 68c6f6c9f8
commit e8b907d86a
2 changed files with 61 additions and 24 deletions

View File

@@ -2,7 +2,7 @@
#include <J3ML/LinearAlgebra/Common.h>
#include <J3ML/Algorithm/RNG.h>
#include <J3ML/Algorithm/RNG.hpp>
#include <algorithm>
@@ -232,6 +232,10 @@ namespace J3ML::LinearAlgebra {
static Matrix4x4 FromTRS(const Vector3& translate, const Matrix3x3& rotate, const Vector3& scale);
static Matrix4x4 FromTRS(const Vector3& translate, const Matrix4x4& rotate, const Vector3& scale);
void SetCol3(int col, const Vector3 &xyz);
bool HasNegativeScale() const;
public:
/// Returns the translation part.
/** The translation part is stored in the fourth column of this matrix.
@@ -239,9 +243,9 @@ namespace J3ML::LinearAlgebra {
after applying rotation and scale. If this matrix represents a local->world space transformation for an object,
then this gives the world space position of the object.
@note This function assumes that this matrix does not contain projection (the fourth row of this matrix is [0 0 0 1]). */
Vector3 GetTranslatePart() const;
[[nodiscard]] Vector3 GetTranslatePart() const;
/// Returns the top-left 3x3 part of this matrix. This stores the rotation part of this matrix (if this matrix represents a rotation).
Matrix3x3 GetRotatePart() const;
[[nodiscard]] Matrix3x3 GetRotatePart() const;
/// Sets the translation part of this matrix.
/** This function sets the translation part of this matrix. These are the first three elements of the fourth column. All other entries are left untouched. */
@@ -287,36 +291,36 @@ namespace J3ML::LinearAlgebra {
/// Returns the given row.
/** @param The zero-based index [0, 3] of the row to get */
Vector4 GetRow(int row) const;
Vector4 Row(int row) const;
[[nodiscard]] Vector4 GetRow(int row) const;
[[nodiscard]] Vector4 Row(int row) const;
Vector4& Row(int row);
/// Returns only the first-three elements of the given row.
Vector3 GetRow3(int index) const;
Vector3 Row3(int i) const;
[[nodiscard]] Vector3 GetRow3(int index) const;
[[nodiscard]] Vector3 Row3(int i) const;
/// This method also allows assignment to the retrieved row.
Vector3& Row3(int row);
/// Returns the given column.
/** @param col The zero-based index [0, 3] of the column to get. */
Vector4 GetColumn(int index) const;
Vector4 Column(int index) const;
Vector4 Col(int i) const;
[[nodiscard]] Vector4 GetColumn(int index) const;
[[nodiscard]] Vector4 Column(int index) const;
[[nodiscard]] Vector4 Col(int i) const;
/// Returns only the first three elements of the given column.
Vector3 GetColumn3(int index) const;
Vector3 Column3(int index) const;
[[nodiscard]] Vector3 GetColumn3(int index) const;
[[nodiscard]] Vector3 Column3(int index) const;
Vector3 Col3(int i) const;
[[nodiscard]] Vector3 Col3(int i) const;
/// Returns the scaling performed by this matrix. This function assumes taht the last row is [0 0 0 1].
/// GetScale().x specifies the amount of scaling applied to the local x direction vector when it is transformed by this matrix.
/// i.e. GetScale()[i] equals Col[i].Length();
Vector3 GetScale() const;
[[nodiscard]] Vector3 GetScale() const;
float &At(int row, int col);
float At(int x, int y) const;
[[nodiscard]] float At(int x, int y) const;
void SwapColumns(int col1, int col2);
@@ -337,35 +341,48 @@ namespace J3ML::LinearAlgebra {
/** @return Returns true if the entries of this float4x4 are all finite, and do not contain NaN or infs. */
bool IsFinite() const;
/// Tests if this matrix is the identity matrix.
bool IsIdentity(float epsilon = 1e-3f) const;
/// Tests if this matrix has an inverse.
/** @return Returns true if this matrix can be inverted, up to the given epsilon. */
bool IsInvertible(float epsilon = 1e-3f) const;
Vector4 Diagonal() const;
Vector3 Diagonal3() const;
[[nodiscard]] Vector4 Diagonal() const;
[[nodiscard]] Vector3 Diagonal3() const;
/// Returns the local +X axis in world space.
/// This is the same as transforming the vector (1,0,0) by this matrix.
Vector3 WorldX() const;
[[nodiscard]] Vector3 WorldX() const;
/// Returns the local +Y axis in world space.
/// This is the same as transforming the vector (0,1,0) by this matrix.
Vector3 WorldY() const;
[[nodiscard]] Vector3 WorldY() const;
/// Returns the local +Z axis in world space.
/// This is the same as transforming the vector (0,0,1) by this matrix.
Vector3 WorldZ() const;
[[nodiscard]] Vector3 WorldZ() const;
/// Accesses this structure as a float array.
/// @return A pointer to the upper-left element. The data is contiguous in memory.
/// ptr[0] gives the element [0][0], ptr[1] is [0][1], ptr[2] is [0][2].
/// ptr[4] == [1][0], ptr[5] == [1][1], ..., and finally, ptr[15] == [3][3].
float *ptr() { return &elems[0][0]; }
const float *ptr() const { return &elems[0][0]; }
[[nodiscard]] const float *ptr() const { return &elems[0][0]; }
float Determinant3x3() const;
/// Computes the determinant of the upper-left 3x3 submatrix of this matrix.
[[nodiscard]] float Determinant3x3() const;
/// Computes the determinant of this matrix.
// If the determinant is nonzero, this matrix is invertible.
float Determinant() const;
[[nodiscard]] float Determinant() const;
#define SKIPNUM(val, skip) (val >= skip ? (val+1) : val)
/// Computes the determinant of this matrix.
/** If the determinant is nonzero, this matrix is invertible.
If the determinant is negative, this matrix performs reflection about some axis.
From http://msdn.microsoft.com/en-us/library/bb204853(VS.85).aspx :
"If the determinant is positive, the basis is said to be "positively" oriented (or right-handed).
If the determinant is negative, the basis is said to be "negatively" oriented (or left-handed)." */
float Determinant4() const;
#define SKIPNUM(val, skip) (val >= skip ? (val+1) : val)
float Minor(int i, int j) const;

View File

@@ -345,6 +345,11 @@ namespace J3ML::LinearAlgebra {
return At(0, 0) * Minor(0,0) - At(0, 1) * Minor(0,1) + At(0, 2) * Minor(0,2) - At(0, 3) * Minor(0,3);
}
float Matrix4x4::Determinant4() const {
assert(IsFinite());
return At(0,0) * Minor(0, 0) - At(0, 1) * Minor(0,1) + At(0,2) * Minor(0,2) - At(0, 3) * Minor(0, 3);
}
float Matrix4x4::Determinant3x3() const {
const float a = elems[0][0];
@@ -405,6 +410,14 @@ namespace J3ML::LinearAlgebra {
return true;
}
bool Matrix4x4::IsIdentity(float epsilon) const {
for (int iy = 0; iy < Rows; ++iy)
for (int ix = 0; ix < Cols; ++ix)
if (!Math::EqualAbs(elems[iy][ix], (ix == iy) ? 1.f : 0.f, epsilon))
return false;
return true;
}
Vector3 Matrix4x4::GetColumn3(int index) const {
return Vector3{At(0, index), At(1, index), At(2, index)};
}
@@ -931,6 +944,13 @@ namespace J3ML::LinearAlgebra {
return Matrix4x4::Translate(translate) * Matrix4x4(rotate) * Matrix4x4::Scale(scale);
}
void Matrix4x4::SetCol3(int col, const Vector3& xyz) {
SetCol3(col, xyz.x, xyz.y, xyz.z);
}
bool Matrix4x4::HasNegativeScale() const { return Determinant() < 0.f; }
void Matrix4x4::SetCol3(int col, float x, float y, float z) {
// TODO: implement assertations
At(0, col) = x;