Fill out Matrix3x3 Documentation, implement several missing functions.
Some checks failed
Build Docs With Doxygen / Explore-Gitea-Actions (push) Has been cancelled
Some checks failed
Build Docs With Doxygen / Explore-Gitea-Actions (push) Has been cancelled
This commit is contained in:
@@ -8,6 +8,79 @@
|
||||
namespace J3ML::LinearAlgebra {
|
||||
|
||||
|
||||
|
||||
/** Sets the top-left 3x3 area of the matrix to the rotation matrix about the X-axis. Elements
|
||||
outside the top-left 3x3 area are ignored. This matrix rotates counterclockwise if multiplied
|
||||
in the order M*v, and clockwise if rotated in the order v*M.
|
||||
@param m The matrix to store the result.
|
||||
@param angle the rotation angle in radians. */
|
||||
template <typename Matrix>
|
||||
void Set3x3PartRotateX(Matrix &m, float angle)
|
||||
{
|
||||
float sinz, cosz;
|
||||
sinz = std::sin(angle);
|
||||
cosz = std::cos(angle);
|
||||
|
||||
m[0][0] = 1.f; m[0][1] = 0.f; m[0][2] = 0.f;
|
||||
m[1][0] = 0.f; m[1][1] = cosz; m[1][2] = -sinz;
|
||||
m[2][0] = 0.f; m[2][1] = sinz; m[2][2] = cosz;
|
||||
}
|
||||
|
||||
/** Sets the top-left 3x3 area of the matrix to the rotation matrix about the Y-axis. Elements
|
||||
outside the top-left 3x3 area are ignored. This matrix rotates counterclockwise if multiplied
|
||||
in the order M*v, and clockwise if rotated in the order v*M.
|
||||
@param m The matrix to store the result
|
||||
@param angle The rotation angle in radians. */
|
||||
template <typename Matrix>
|
||||
void Set3x3PartRotateY(Matrix &m, float angle)
|
||||
{
|
||||
float sinz, cosz;
|
||||
sinz = std::sin(angle);
|
||||
cosz = std::cos(angle);
|
||||
|
||||
m[0][0] = cosz; m[0][1] = 0.f; m[0][2] = sinz;
|
||||
m[1][0] = 0.f; m[1][1] = 1.f; m[1][2] = 0.f;
|
||||
m[2][0] = -sinz; m[2][1] = 0.f; m[2][2] = cosz;
|
||||
}
|
||||
|
||||
/** Sets the top-left 3x3 area of the matrix to the rotation matrix about the Z-axis. Elements
|
||||
outside the top-left 3x3 area are ignored. This matrix rotates counterclockwise if multiplied
|
||||
in the order of M*v, and clockwise if rotated in the order v*M.
|
||||
@param m The matrix to store the result.
|
||||
@param angle The rotation angle in radians. */
|
||||
template <typename Matrix>
|
||||
void Set3x3RotatePartZ(Matrix &m, float angle)
|
||||
{
|
||||
float sinz, cosz;
|
||||
sinz = std::sin(angle);
|
||||
cosz = std::cos(angle);
|
||||
|
||||
m[0][0] = cosz; m[0][1] = -sinz; m[0][2] = 0.f;
|
||||
m[1][0] = sinz; m[1][1] = cosz; m[1][2] = 0.f;
|
||||
m[2][0] = 0.f; m[2][1] = 0.f; m[2][2] = 1.f;
|
||||
}
|
||||
|
||||
|
||||
/** Computes the matrix M = R_x * R_y * R_z, where R_d is the cardinal rotation matrix
|
||||
about the axis +d, rotating counterclockwise.
|
||||
This function was adapted from https://www.geometrictools.com/Documentation/EulerAngles.pdf .
|
||||
Parameters x y and z are the angles of rotation, in radians. */
|
||||
template <typename Matrix>
|
||||
void Set3x3PartRotateEulerXYZ(Matrix &m, float x, float y, float z)
|
||||
{
|
||||
// TODO: vectorize to compute 4 sines + cosines at one time;
|
||||
float cx = std::cos(x);
|
||||
float sx = std::sin(x);
|
||||
float cy = std::cos(y);
|
||||
float sy = std::sin(y);
|
||||
float cz = std::cos(z);
|
||||
float sz = std::sin(z);
|
||||
|
||||
m[0][0] = cy * cz; m[0][1] = -cy * sz; m[0][2] = sy;
|
||||
m[1][0] = cz*sx*sy + cx*sz; m[1][1] = cx*cz - sx*sy*sz; m[1][2] = -cy*sx;
|
||||
m[2][0] = -cx*cz*sy + sx*sz; m[2][1] = cz*sx + cx*sy*sz; m[2][2] = cx*cy;
|
||||
}
|
||||
|
||||
class Quaternion;
|
||||
|
||||
/// A 3-by-3 matrix for linear transformations of 3D geometry.
|
||||
@@ -28,56 +101,87 @@ namespace J3ML::LinearAlgebra {
|
||||
*/
|
||||
|
||||
class Matrix3x3 {
|
||||
public:
|
||||
public: /// Constant Values
|
||||
enum { Rows = 3 };
|
||||
enum { Cols = 3 };
|
||||
|
||||
public: /// Constant Members
|
||||
static const Matrix3x3 Zero;
|
||||
static const Matrix3x3 Identity;
|
||||
static const Matrix3x3 NaN;
|
||||
|
||||
public: /// Constructors
|
||||
/// Creates a new Matrix3x3 with uninitalized member values.
|
||||
Matrix3x3() {}
|
||||
|
||||
Matrix3x3(const Matrix3x3& rhs) { Set(rhs); }
|
||||
Matrix3x3(float val);
|
||||
Matrix3x3(float m00, float m01, float m02, float m10, float m11, float m12, float m20, float m21, float m22);
|
||||
Matrix3x3(const Vector3& r1, const Vector3& r2, const Vector3& r3);
|
||||
/// Creates a new Matrix3x3 by explicitly specifying all the matrix elements.
|
||||
/// The elements are specified in row-major format, i.e. the first row first followed by the second and third row.
|
||||
/// E.g. The element m10 denotes the scalar at second (idx 1) row, first (idx 0) column.
|
||||
Matrix3x3(float m00, float m01, float m02,
|
||||
float m10, float m11, float m12,
|
||||
float m20, float m21, float m22);
|
||||
/// Constructs the matrix by explicitly specifying the three column vectors.
|
||||
/** @param col0 The first column. If this matrix represents a change-of-basis transformation, this parameter is the world-space
|
||||
direction of the local X axis.
|
||||
@param col1 The second column. If this matrix represents a change-of-basis transformation, this parameter is the world-space
|
||||
direction of the local Y axis.
|
||||
@param col2 The third column. If this matrix represents a change-of-basis transformation, this parameter is the world-space
|
||||
direction of the local Z axis. */
|
||||
Matrix3x3(const Vector3& col0, const Vector3& col1, const Vector3& col2);
|
||||
/// Constructs this matrix3x3 from the given quaternion.
|
||||
explicit Matrix3x3(const Quaternion& orientation);
|
||||
/// Constructs this Matrix3x3 from a pointer to an array of floats.
|
||||
explicit Matrix3x3(const float *data);
|
||||
|
||||
|
||||
/// Creates a new Matrix3x3 that rotates about one of the principal axes by the given angle.
|
||||
/// Calling RotateX, RotateY, or RotateZ is slightly faster than calling the more generic RotateAxisAngle function.
|
||||
static Matrix3x3 RotateX(float radians);
|
||||
/// [similarOverload: RotateX] [hideIndex]
|
||||
static Matrix3x3 RotateY(float radians);
|
||||
/// [similarOverload: RotateX] [hideIndex]
|
||||
static Matrix3x3 RotateZ(float radians);
|
||||
|
||||
Vector3 GetRow(int index) const;
|
||||
Vector3 GetColumn(int index) const;
|
||||
|
||||
Vector3 GetRow3(int index) const;
|
||||
|
||||
Vector3 GetColumn3(int index) const;
|
||||
|
||||
float &At(int row, int col);
|
||||
float At(int x, int y) const;
|
||||
|
||||
void SetRotatePart(const Vector3& a, float angle);
|
||||
|
||||
/// Creates a new M3x3 that rotates about the given axis by the given angle
|
||||
static Matrix3x3 RotateAxisAngle(const Vector3& axis, float angleRadians);
|
||||
|
||||
// TODO: Implement
|
||||
/// Creates a matrix that rotates the sourceDirection vector to coincide with the targetDirection vector.]
|
||||
/** Both input direction vectors must be normalized.
|
||||
@note There are infinite such rotations - this function returns the rotation that has the shortest angle
|
||||
(when decomposed to axis-angle notation)
|
||||
@return An orthonormal matrix M with a determinant of +1. For the matrix M it holds that
|
||||
M * sourceDirection = targetDirection */
|
||||
static Matrix3x3 RotateFromTo(const Vector3& source, const Vector3& direction);
|
||||
|
||||
void SetRow(int i, const Vector3 &vector3);
|
||||
void SetColumn(int i, const Vector3& vector);
|
||||
void SetAt(int x, int y, float value);
|
||||
|
||||
void Orthonormalize(int c0, int c1, int c2);
|
||||
|
||||
/// Creates a LookAt matrix.
|
||||
/** A LookAt matrix is a rotation matrix that orients an object to face towards a specified target direction.
|
||||
* @param forward Specifies the forward direction in the local space of the object. This is the direction
|
||||
the model is facing at in its own local/object space, often +X (1,0,0), +Y (0,1,0), or +Z (0,0,1). The
|
||||
vector to pass in here depends on the conventions you or your modeling software is using, and it is best
|
||||
pick one convention for all your objects, and be consistent.
|
||||
* @param target Specifies the desired world space direction the object should look at. This function
|
||||
will compute a rotation matrix which will rotate the localForward vector to orient towards this targetDirection
|
||||
vector. This input parameter must be a normalized vector.
|
||||
* @param localUp Specifies the up direction in the local space of the object. This is the up direction the model
|
||||
was authored in, often +Y (0,1,0) or +Z (0,0,1). The vector to pass in here depends on the conventions you
|
||||
or your modeling software is using, and it is best to pick one convention for all your objects, and be
|
||||
consistent. This input parameter must be a normalized vector. This vector must be perpendicular to the
|
||||
vector localForward, i.e. localForward.Dot(localUp) == 0.
|
||||
* @param worldUp Specifies the global up direction of the scene in world space. Simply rotating one vector to
|
||||
coincide with another (localForward->targetDirection) would cause the up direction of the resulting
|
||||
orientation to drift (e.g. the model could be looking at its target its head slanted sideways). To keep
|
||||
the up direction straight, this function orients the localUp direction of the model to point towards the
|
||||
specified worldUp direction (as closely as possible). The worldUp and targetDirection vectors cannot be
|
||||
collinear, but they do not need to be perpendicular either.
|
||||
* @return A matrix that maps the given local space forward direction vector to point towards the given target
|
||||
direction, and the given local up direction towards the given target world up direction. This matrix can be
|
||||
used as the 'world transform' of an object. THe returned matrix M is orthogonal with a determinant of +1.
|
||||
For the matrix M it holds that M * localForward = targetDirection, and M * localUp lies in the plane spanned by
|
||||
the vectors targetDirection and worldUp.
|
||||
* @see RotateFromTo()
|
||||
* @note Be aware that the convention of a 'LookAt' matrix in J3ML differs from e.g. GLM. In J3ML, the returned
|
||||
matrix is a mapping from local space to world space, meaning that the returned matrix can be used as the 'world transform'
|
||||
for any 3D object (camera or not). The view space is the local space of the camera, so this function returns the mapping
|
||||
view->world. In GLM, the LookAt function is tied to cameras only, and it returns the inverse mapping world->view.
|
||||
*/
|
||||
static Matrix3x3 LookAt(const Vector3& forward, const Vector3& target, const Vector3& localUp, const Vector3& worldUp);
|
||||
|
||||
/// Creates a new Matrix3x3 that performs the rotation expressed by the given quaternion.
|
||||
static Matrix3x3 FromQuat(const Quaternion& orientation);
|
||||
|
||||
Quaternion ToQuat() const;
|
||||
|
||||
/// Creates a new Matrix3x3 as a combination of rotation and scale.
|
||||
// This function creates a new matrix M in the form M = R * S
|
||||
// where R is a rotation matrix and S is a scale matrix.
|
||||
@@ -86,12 +190,80 @@ namespace J3ML::LinearAlgebra {
|
||||
// is applied to the vector first, followed by rotation, and finally translation
|
||||
static Matrix3x3 FromRS(const Quaternion& rotate, const Vector3& scale);
|
||||
static Matrix3x3 FromRS(const Matrix3x3 &rotate, const Vector3& scale);
|
||||
|
||||
|
||||
/// Creates a new transformation matrix that scales by the given factors.
|
||||
// This matrix scales with respect to origin.
|
||||
static Matrix3x3 FromScale(float sx, float sy, float sz);
|
||||
static Matrix3x3 FromScale(const Vector3& scale);
|
||||
public: /// Member Methods
|
||||
/// Sets this matrix to perform rotation about the positive X axis which passes through the origin
|
||||
/// [similarOverload: SetRotatePart] [hideIndex]
|
||||
void SetRotatePartX(float angle);
|
||||
/// Sets this matrix to perform rotation about the positive Y axis.
|
||||
void SetRotatePartY(float angle);
|
||||
/// Sets this matrix to perform rotation about the positive Z axis.
|
||||
void SetRotatePartZ(float angle);
|
||||
|
||||
/// Sets this matrix to perform a rotation about the given axis and angle.
|
||||
void SetRotatePart(const Vector3& a, float angle);
|
||||
void SetRotatePart(const AxisAngle& axisAngle);
|
||||
/// Sets this matrix to perform the rotation expressed by the given quaternion.
|
||||
void SetRotatePart(const Quaternion& quat);
|
||||
|
||||
/// Returns the given row.
|
||||
/** @param row The zero-based index [0, 2] of the row to get. */
|
||||
Vector3 GetRow(int index) const;
|
||||
Vector3 Row(int index) const { return GetRow(index);}
|
||||
/// This method also allows assignment to the retrieved row.
|
||||
Vector3& Row(int row);
|
||||
|
||||
/// Returns only the first-three elements of the given row.
|
||||
Vector3 GetRow3(int index) const;
|
||||
Vector3 Row3(int index) const;
|
||||
/// This method also allows assignment to the retrieved row.
|
||||
Vector3& Row3(int index);
|
||||
|
||||
/// Returns the given column.
|
||||
/** @param col The zero-based index [0, 2] of the column to get. */
|
||||
Vector3 GetColumn(int index) const;
|
||||
Vector3 Column(int index) const;
|
||||
Vector3 Col(int index) const;
|
||||
/// This method also allows assignment to the retrieved column.
|
||||
Vector3& Col(int index);
|
||||
|
||||
/// Returns only the first three elements of the given column.
|
||||
Vector3 GetColumn3(int index) const;
|
||||
Vector3 Column3(int index) const;
|
||||
Vector3 Col3(int index) const;
|
||||
/// This method also allows assignment to the retrieved column.
|
||||
Vector3& Col3(int index);
|
||||
|
||||
|
||||
|
||||
void SetRow(int i, const Vector3 &vector3);
|
||||
void SetColumn(int i, const Vector3& vector);
|
||||
void SetAt(int x, int y, float value);
|
||||
|
||||
float &At(int row, int col);
|
||||
float At(int x, int y) const;
|
||||
|
||||
void Set(const Matrix3x3 &x3);
|
||||
|
||||
|
||||
void Orthonormalize(int c0, int c1, int c2);
|
||||
|
||||
|
||||
|
||||
/// Convers this rotation matrix to a quaternion.
|
||||
/// This function assumes that the matrix is orthonormal (no shear or scaling) and does not perform any mirroring (determinant > 0)
|
||||
Quaternion ToQuat() const;
|
||||
/// Attempts to convert this matrix to a quaternion. Returns false if the conversion cannot succeed (this matrix was not a rotation
|
||||
/// matrix, and there is scaling ,shearing, or mirroring in this matrix)
|
||||
bool TryConvertToQuat(Quaternion& q) const;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// Returns the main diagonal.
|
||||
Vector3 Diagonal() const;
|
||||
@@ -147,14 +319,11 @@ namespace J3ML::LinearAlgebra {
|
||||
bool IsRowOrthogonal(float epsilon = 1e-3f) const;
|
||||
|
||||
|
||||
|
||||
bool HasUniformScale(float epsilon = 1e-3f) const;
|
||||
|
||||
Vector3 ExtractScale() const {
|
||||
return {GetColumn(0).Length(), GetColumn(1).Length(), GetColumn(2).Length()};
|
||||
}
|
||||
Vector3 ExtractScale() const;
|
||||
|
||||
protected:
|
||||
protected: /// Member values
|
||||
float elems[3][3];
|
||||
};
|
||||
}
|
@@ -87,18 +87,22 @@ namespace J3ML::LinearAlgebra {
|
||||
|
||||
}
|
||||
|
||||
Matrix3x3::Matrix3x3(const Vector3 &r1, const Vector3 &r2, const Vector3 &r3) {
|
||||
this->elems[0][0] = r1.x;
|
||||
this->elems[0][1] = r1.y;
|
||||
this->elems[0][2] = r1.z;
|
||||
Matrix3x3::Matrix3x3(const Vector3 &col0, const Vector3 &col1, const Vector3 &col2) {
|
||||
SetColumn(0, col0);
|
||||
SetColumn(1, col1);
|
||||
SetColumn(2, col2);
|
||||
|
||||
this->elems[1][0] = r2.x;
|
||||
this->elems[1][1] = r2.y;
|
||||
this->elems[1][2] = r2.z;
|
||||
//this->elems[0][0] = r1.x;
|
||||
//this->elems[0][1] = r1.y;
|
||||
//this->elems[0][2] = r1.z;
|
||||
|
||||
this->elems[2][0] = r3.x;
|
||||
this->elems[2][1] = r3.y;
|
||||
this->elems[2][2] = r3.z;
|
||||
//this->elems[1][0] = r2.x;
|
||||
//this->elems[1][1] = r2.y;
|
||||
//this->elems[1][2] = r2.z;
|
||||
|
||||
//this->elems[2][0] = r3.x;
|
||||
//this->elems[2][1] = r3.y;
|
||||
//this->elems[2][2] = r3.z;
|
||||
}
|
||||
|
||||
Matrix3x3::Matrix3x3(const Quaternion &orientation) {
|
||||
@@ -456,5 +460,74 @@ namespace J3ML::LinearAlgebra {
|
||||
return Transform(rhs);
|
||||
}
|
||||
|
||||
Matrix3x3 Matrix3x3::RotateX(float radians) {
|
||||
Matrix3x3 r;
|
||||
r.SetRotatePartX(radians);
|
||||
return r;
|
||||
}
|
||||
|
||||
Matrix3x3 Matrix3x3::RotateY(float radians) {
|
||||
Matrix3x3 r;
|
||||
r.SetRotatePartY(radians);
|
||||
return r;
|
||||
}
|
||||
|
||||
Matrix3x3 Matrix3x3::RotateZ(float radians) {
|
||||
Matrix3x3 r;
|
||||
r.SetRotatePartZ(radians);
|
||||
return r;
|
||||
}
|
||||
|
||||
void Matrix3x3::SetRotatePartX(float angle) {
|
||||
Set3x3PartRotateX(*this, angle);
|
||||
}
|
||||
|
||||
void Matrix3x3::SetRotatePartY(float angle) {
|
||||
Set3x3PartRotateY(*this, angle);
|
||||
}
|
||||
|
||||
void Matrix3x3::SetRotatePartZ(float angle) {
|
||||
Set3x3RotatePartZ(*this, angle);
|
||||
}
|
||||
|
||||
Vector3 Matrix3x3::ExtractScale() const {
|
||||
return {GetColumn(0).Length(), GetColumn(1).Length(), GetColumn(2).Length()};
|
||||
}
|
||||
|
||||
// TODO: Finish implementation
|
||||
Matrix3x3 Matrix3x3::RotateFromTo(const Vector3 &source, const Vector3 &direction) {
|
||||
assert(source.IsNormalized());
|
||||
assert(source.IsNormalized());
|
||||
|
||||
// http://cs.brown.edu/research/pubs/pdfs/1999/Moller-1999-EBA.pdf
|
||||
Matrix3x3 r;
|
||||
float dot = source.Dot(direction);
|
||||
if (std::abs(dot) > 0.999f)
|
||||
{
|
||||
Vector3 s = source.Abs();
|
||||
Vector3 unit = s.x < s.y && s.x < s.z ? Vector3::UnitX : (s.y < s.z ? Vector3::UnitY : Vector3::UnitZ);
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 &Matrix3x3::Row(int row) {
|
||||
assert(row >= 0);
|
||||
assert(row < Rows);
|
||||
return reinterpret_cast<Vector3 &> (elems[row]);
|
||||
}
|
||||
|
||||
Vector3 Matrix3x3::Column(int index) const { return GetColumn(index);}
|
||||
|
||||
Vector3 Matrix3x3::Col(int index) const { return Column(index);}
|
||||
|
||||
Vector3 &Matrix3x3::Row3(int index) {
|
||||
return reinterpret_cast<Vector3 &>(elems[index]);
|
||||
}
|
||||
|
||||
Vector3 Matrix3x3::Row3(int index) const { return GetRow3(index);}
|
||||
|
||||
void Matrix3x3::Set(const Matrix3x3 &x3) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user