Implement Vector4 data type

This commit is contained in:
2023-12-18 14:24:43 -06:00
parent 963afc6d63
commit 21a5ce7bd8
2 changed files with 196 additions and 46 deletions

View File

@@ -11,7 +11,6 @@ inline float lerp(float a, float b, float t) {
}
// Note: Josh Linear Algebra Types are designed as Immutable Data Types
// x, y, z, w, etc. values should not and can not be set directly.
// rather, you just construct a new type and assign it.
@@ -127,6 +126,62 @@ public:
#endif
};
class Vector4 {
public:
Vector4() : x(0), y(0), z(0), w(0) {}
Vector4(float X, float Y, float Z, float W) : x(X),y(Y),z(Z),w(W) { }
Vector4(const Vector4& copy) = default;
Vector4(Vector4&& move) = default;
float getX() const;
float getY() const;
float getZ() const;
float getW() const;
#if MUTABLE
void setX(float newX);
void setY(float newY);
void setZ(float newZ);
void setW(float newW);
#endif
float operator[](int index) const;
bool IsWithinMarginOfError(const Vector4& rhs, float margin=0.0001f) const;
bool operator==(const Vector4& rhs) const;
bool operator!=(const Vector4& rhs) const;
Vector4 min(const Vector4& min) const;
Vector4 max(const Vector4& max) const;
Vector4 clamp(const Vector4& min, const Vector4& max) const;
float distance(const Vector4& to) const;
float length() const;
float lengthSquared() const;
float magnitude() const;
float dot(const Vector4& rhs) const;
Vector4 project(const Vector4& rhs) const;
// While it is feasable to compute a cross-product in four dimensions
// the cross product only has the orthogonality property in 3 and 7 dimensions
// You should consider instead looking at Gram-Schmidt Orthogonalization
// to find orthonormal vectors.
Vector4 cross(const Vector4& rhs) const;
Vector4 normalize() const;
Vector4 lerp(const Vector4& goal, float alpha) const;
Vector4 operator+(const Vector4& rhs) const;
Vector4 operator-(const Vector4& rhs) const;
Vector4 operator*(float rhs) const;
Vector4 operator/(float rhs) const;
Vector4 operator+() const;
Vector4 operator-() const;
public:
#if MUTABLE
float x = 0;
float y = 0;
float z = 0;
float w = 0;
#else
const float x = 0;
const float y = 0;
const float z = 0;
const float w = 0;
#endif
};
// Essential Reading:
// http://www.essentialmath.com/GDC2012/GDC2012_JMV_Rotations.pdf
class Angle {
@@ -186,47 +241,6 @@ class AxisAngle {
using Position = Vector3;
/*class Position : public vector3 {
public:
bool operator==(const Position& p) const {
return (x == p.x) && (y == p.y) && (z == p.z);
}
void set(Position p) {
this->x = p.x;
this->y = p.y;
this->z = p.z;
}
void set(Position* p) {
this->x = p->x;
this->y = p->y;
this->z = p->z;
}
void set(vector3 v) {
this->x = v.x;
this->y = v.y;
this->z = v.z;
}
void set(vector3* v) {
this->x = v->x;
this->y = v->y;
this->z = v->z;
}
void set(float x, float y, float z) {
this->x = x;
this->y = y;
this->z = z;
}
float distanceFrom(Position p) {
return sqrt(pow(this->x - p.x, 2) + pow(this->y - p.y, 2) + pow(this->z - p.z, 2));
}
};*/
// The CFrame is fundamentally 4 vectors (position, forward, right, up vector)
class CoordinateFrame
{
@@ -243,6 +257,8 @@ class Matrix2x2 {
public:
static const Matrix2x2 Zero;
static const Matrix2x2 Identity;
Vector2 GetRow() const;
Vector2 GetColumn() const;
protected:
float elems[2][2];
@@ -251,16 +267,39 @@ class Matrix3x3 {
public:
static const Matrix3x3 Zero;
static const Matrix3x3 Identity;
Vector3 GetRow() const;
Vector3 GetColumn() const;
float At(int x, int y) const;
// Creates a new M3x3 that rotates about the given axis by the given angle
static Matrix3x3 RotateAxisAngle(const Vector3 );
static Matrix3x3 RotateAxisAngle(const Vector3& rhs);
protected:
float elems[3][3];
};
/// A 4-by-4 matrix for affine transformations and perspective projections of 3D geometry.
/* This matrix can represent the most generic form of transformations for 3D objects,
* including perspective projections, which a 4-by-3 cannot store,
* and translations, which a 3-by-3 cannot represent.
* The elements of this matrix are
* m_00, m_01, m_02, m_03
* m_10, m_11, m_12, m_13
* m_20, m_21, m_22, m_23,
* m_30, m_31, m_32, m_33
*
* The element m_yx is the value on the row y and column x.
* You can access m_yx using the double-bracket notation m[y][x]
*/
class Matrix4x4 {
public:
static const Matrix4x4 Zero;
static const Matrix4x4 Identity;
Vector3 GetTranslationComponent() const;
Matrix3x3 GetRotationComponent() const;
Vector4 GetRow() const;
Vector4 GetColumn() const;
protected:
float elems[4][4];
};

View File

@@ -162,6 +162,7 @@ Vector3 Vector3::operator-() const
return {-x, -y, -z};
}
Vector3::Vector3(const Vector3& rhs)
{
this->x = rhs.x;
@@ -253,8 +254,8 @@ float Vector3::dot(const Vector3& rhs) const
auto a = this->normalize();
auto b = rhs.normalize();
return a.x * b.x +
a.y * b.y +
a.z * b.z;
a.y * b.y +
a.z * b.z;
}
Vector3 Vector3::project(const Vector3& rhs) const
@@ -289,4 +290,114 @@ Vector3 Vector3::lerp(const Vector3& goal, float alpha) const
return this->operator*(1.0f - alpha) + (goal * alpha);
}
#pragma endregion
#pragma endregion
#pragma region vector4
bool Vector4::operator==(const Vector4& rhs) const
{
return this->IsWithinMarginOfError(rhs);
}
bool Vector4::operator!=(const Vector4& rhs) const
{
return this->IsWithinMarginOfError(rhs) == false;
}
Vector4 Vector4::min(const Vector4& min) const
{
return {
std::min(this->x, min.x),
std::min(this->y, min.y),
std::min(this->z, min.z),
std::min(this->w, min.w)
};
}
Vector4 Vector4::max(const Vector4& max) const
{
return {
std::max(this->x, max.x),
std::max(this->y, max.y),
std::max(this->z, max.z),
std::max(this->w, max.w)
};
}
Vector4 Vector4::clamp(const Vector4& min, const Vector4& max) const
{
return {
std::clamp(this->x, min.x, max.x),
std::clamp(this->y, min.y, max.y),
std::clamp(this->z, min.z, max.z),
std::clamp(this->w, min.w, max.w)
};
}
float Vector4::distance(const Vector4& to) const
{
return ( (*this) - to ).magnitude();
}
float Vector4::length() const
{
return std::sqrt(lengthSquared());
}
float Vector4::lengthSquared() const
{
return (x*x + y*y + z*z + w*w);
}
float Vector4::magnitude() const
{
return std::sqrt(x*x + y*y + z*z + w*w);
}
float Vector4::dot(const Vector4& rhs) const
{
auto a = this->normalize();
auto b = rhs.normalize();
return a.x * b.x +
a.y * b.y +
a.z * b.z +
a.w * b.w;
}
Vector4 Vector4::project(const Vector4& rhs) const
{
float scalar = this->dot(rhs) / (rhs.magnitude()* rhs.magnitude());
return rhs * scalar;
}
Vector4 Vector4::normalize() const
{
if (length() > 0)
return {
x / length(),
y / length(),
z / length(),
w / length()
};
else
return {0,0,0,0};
}
Vector4 Vector4::lerp(const Vector4& goal, float alpha) const
{
return this->operator*(1.0f - alpha) + (goal * alpha);
}
Vector4 Vector4::operator+(const Vector4& rhs) const
{
return {x+rhs.x, y+rhs.y, z+rhs.z, w+rhs.w};
}
Vector4 Vector4::operator-(const Vector4& rhs) const
{
return {x-rhs.x, y-rhs.y, z-rhs.z, w-rhs.w};
}
#pragma endregion