613 lines
15 KiB
C++
613 lines
15 KiB
C++
#include <types/vector.h>
|
|
|
|
namespace LinearAlgebra {
|
|
|
|
|
|
|
|
#pragma region vector2
|
|
|
|
Vector2::Vector2(): x(0), y(0)
|
|
{}
|
|
|
|
Vector2::Vector2(float X, float Y): x(X), y(Y)
|
|
{}
|
|
|
|
Vector2::Vector2(const Vector2& rhs): x(rhs.x), y(rhs.y)
|
|
{}
|
|
|
|
float Vector2::operator[](std::size_t index)
|
|
{
|
|
assert(index < 2);
|
|
if (index == 0) return x;
|
|
if (index == 1) return y;
|
|
return 0;
|
|
}
|
|
|
|
bool Vector2::IsWithinMarginOfError(const Vector2& rhs, float margin) const
|
|
{
|
|
return this->Distance(rhs) <= margin;
|
|
}
|
|
|
|
bool Vector2::operator==(const Vector2& rhs) const
|
|
{
|
|
return this->IsWithinMarginOfError(rhs);
|
|
}
|
|
|
|
bool Vector2::operator!=(const Vector2& rhs) const
|
|
{
|
|
return this->IsWithinMarginOfError(rhs) == false;
|
|
}
|
|
|
|
Vector2 Vector2::Min(const Vector2& min) const
|
|
{
|
|
return {
|
|
std::min(this->x, min.x),
|
|
std::min(this->y, min.y)
|
|
};
|
|
}
|
|
|
|
Vector2 Vector2::Max(const Vector2& max) const
|
|
{
|
|
return {
|
|
std::max(this->x, max.x),
|
|
std::max(this->y, max.y)
|
|
};
|
|
}
|
|
|
|
Vector2 Vector2::Clamp(const Vector2& min, const Vector2& max) const
|
|
{
|
|
return {
|
|
std::clamp(this->x, min.x, max.x),
|
|
std::clamp(this->y, min.y, max.y)
|
|
};
|
|
}
|
|
|
|
float Vector2::Distance(const Vector2& to) const
|
|
{
|
|
return ((*this)-to).Magnitude();
|
|
}
|
|
|
|
float Vector2::Length() const
|
|
{
|
|
return std::sqrt(LengthSquared());
|
|
}
|
|
|
|
float Vector2::LengthSquared() const
|
|
{
|
|
return (x*x + y*y);
|
|
}
|
|
|
|
float Vector2::Magnitude() const
|
|
{
|
|
return std::sqrt(LengthSquared());
|
|
}
|
|
|
|
float Vector2::Dot(const Vector2& rhs) const
|
|
{
|
|
auto a = this->Normalize();
|
|
auto b = rhs.Normalize();
|
|
|
|
return a.x * b.x + a.y * b.y;
|
|
}
|
|
|
|
Vector2 Vector2::Project(const Vector2& rhs) const
|
|
{
|
|
float scalar = this->Dot(rhs) / (rhs.Magnitude()*rhs.Magnitude());
|
|
return rhs * scalar;
|
|
}
|
|
|
|
Vector2 Vector2::Normalize() const
|
|
{
|
|
if (Length() > 0)
|
|
return {
|
|
x / Length(),
|
|
y / Length()
|
|
};
|
|
else
|
|
return {0,0};
|
|
}
|
|
|
|
Vector2 Vector2::Lerp(const Vector2& rhs, float alpha) const
|
|
{
|
|
return this->operator*(1.0f - alpha) + (rhs * alpha);
|
|
}
|
|
|
|
float Vector2::AngleBetween(const Vector2& rhs) const
|
|
{
|
|
auto numer = this->Dot(rhs);
|
|
auto denom = this->Magnitude() * rhs.Magnitude();
|
|
return std::acos(numer / denom);
|
|
}
|
|
|
|
float Vector2::AngleBetween(const Vector2& lhs, const Vector2& rhs)
|
|
{ return lhs.AngleBetween(rhs); }
|
|
|
|
Vector2 Vector2::operator+(const Vector2& rhs) const
|
|
{
|
|
return {this->x + rhs.x, this->y + rhs.y};
|
|
}
|
|
|
|
Vector2 Vector2::operator-(const Vector2& rhs) const
|
|
{
|
|
return {this->x - rhs.x, this->y - rhs.y};
|
|
}
|
|
|
|
Vector2 Vector2::operator*(float rhs) const
|
|
{
|
|
return {
|
|
this->x * rhs,
|
|
this->y * rhs
|
|
};
|
|
}
|
|
|
|
Vector2 Vector2::operator/(float rhs) const
|
|
{
|
|
return {
|
|
this->x / rhs,
|
|
this->y / rhs
|
|
};
|
|
}
|
|
|
|
Vector2 Vector2::operator-() const
|
|
{
|
|
return {-x, -y};
|
|
}
|
|
|
|
const Vector2 Vector2::Zero = {0, 0};
|
|
const Vector2 Vector2::Up = {0, -1};
|
|
const Vector2 Vector2::Down = {0, 1};
|
|
const Vector2 Vector2::Left = {-1, 0};
|
|
const Vector2 Vector2::Right = {1, 0};
|
|
#pragma endregion
|
|
|
|
#pragma region vector3
|
|
|
|
const Vector3 Vector3::Zero = {0,0,0};
|
|
const Vector3 Vector3::Up = {0, -1, 0};
|
|
const Vector3 Vector3::Down = {0, 1, 0};
|
|
const Vector3 Vector3::Left = {-1, 0, 0};
|
|
const Vector3 Vector3::Right = {1, 0, 0};
|
|
const Vector3 Vector3::Forward = {0, 0, -1};
|
|
const Vector3 Vector3::Backward = {0, 0, 1};
|
|
|
|
Vector3 Vector3::operator+(const Vector3& rhs) const
|
|
{
|
|
return {this->x + rhs.x, this->y + rhs.y, this->z + rhs.z};
|
|
}
|
|
|
|
Vector3 Vector3::operator-(const Vector3& rhs) const
|
|
{
|
|
return {
|
|
this->x- rhs.x,
|
|
this->y-rhs.y,
|
|
this->z-rhs.z
|
|
};
|
|
}
|
|
|
|
Vector3 Vector3::operator*(float rhs) const
|
|
{
|
|
return {
|
|
this->x * rhs,
|
|
this->y * rhs,
|
|
this->z * rhs
|
|
};
|
|
}
|
|
|
|
|
|
Vector3 Vector3::operator/(float rhs) const
|
|
{
|
|
return {
|
|
this->x / rhs,
|
|
this->y / rhs,
|
|
this->z / rhs
|
|
};
|
|
}
|
|
|
|
Vector3 Vector3::operator-() const
|
|
{
|
|
return {-x, -y, -z};
|
|
}
|
|
|
|
Vector4::Vector4(): x(0), y(0), z(0), w(0)
|
|
{}
|
|
|
|
Vector4::Vector4(float X, float Y, float Z, float W): x(X),y(Y),z(Z),w(W)
|
|
{ }
|
|
|
|
|
|
Vector3::Vector3(): x(0), y(0), z(0)
|
|
{}
|
|
|
|
Vector3::Vector3(float X, float Y, float Z): x(X), y(Y), z(Z)
|
|
{}
|
|
|
|
Vector3::Vector3(const Vector3& rhs)
|
|
{
|
|
this->x = rhs.x;
|
|
this->y = rhs.y;
|
|
this->z = rhs.z;
|
|
}
|
|
|
|
Vector3& Vector3::operator=(const Vector3& rhs)
|
|
{
|
|
this->x = rhs.x;
|
|
this->y = rhs.y;
|
|
this->z = rhs.z;
|
|
return *this;
|
|
}
|
|
|
|
float Vector3::operator[](std::size_t index) const
|
|
{
|
|
assert(index < 3);
|
|
if (index==0) return x;
|
|
if (index==1) return y;
|
|
if (index==2) return z;
|
|
return 0;
|
|
}
|
|
|
|
bool Vector3::IsWithinMarginOfError(const Vector3& rhs, float margin) const
|
|
{
|
|
return this->Distance(rhs) <= margin;
|
|
}
|
|
|
|
bool Vector3::operator==(const Vector3& rhs) const
|
|
{
|
|
return this->IsWithinMarginOfError(rhs);
|
|
}
|
|
|
|
bool Vector3::operator!=(const Vector3& rhs) const
|
|
{
|
|
return this->IsWithinMarginOfError(rhs) == false;
|
|
}
|
|
|
|
Vector3 Vector3::Min(const Vector3& min) const
|
|
{
|
|
return {
|
|
std::min(this->x, min.x),
|
|
std::min(this->y, min.y),
|
|
std::min(this->z, min.z)
|
|
};
|
|
}
|
|
|
|
Vector3 Vector3::Max(const Vector3& max) const
|
|
{
|
|
return {
|
|
std::max(this->x, max.x),
|
|
std::max(this->y, max.y),
|
|
std::max(this->z, max.z)
|
|
};
|
|
}
|
|
|
|
Vector3 Vector3::Clamp(const Vector3& min, const Vector3& 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)
|
|
};
|
|
}
|
|
|
|
float Vector3::Distance(const Vector3& to) const
|
|
{
|
|
return ((*this)-to).Magnitude();
|
|
}
|
|
|
|
float Vector3::Length() const
|
|
{
|
|
return std::sqrt(LengthSquared());
|
|
}
|
|
|
|
float Vector3::LengthSquared() const
|
|
{
|
|
return (x*x + y*y + z*z);
|
|
}
|
|
|
|
float Vector3::Magnitude() const
|
|
{
|
|
return std::sqrt(x*x + y*y + z*z);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
Vector3 Vector3::Project(const Vector3& rhs) const
|
|
{
|
|
float scalar = this->Dot(rhs) / (rhs.Magnitude()*rhs.Magnitude());
|
|
return rhs * scalar;
|
|
}
|
|
|
|
Vector3 Vector3::Cross(const Vector3& rhs) const
|
|
{
|
|
return {
|
|
this->y * rhs.z - this->z * rhs.y,
|
|
this->z * rhs.x - this->x * rhs.z,
|
|
this->x * rhs.y - this->y * rhs.x
|
|
};
|
|
}
|
|
|
|
Vector3 Vector3::Normalize() const
|
|
{
|
|
if (Length() > 0)
|
|
return {
|
|
x / Length(),
|
|
y / Length(),
|
|
z / Length()
|
|
};
|
|
else
|
|
return {0,0,0};
|
|
}
|
|
|
|
Vector3 Vector3::Lerp(const Vector3& goal, float alpha) const
|
|
{
|
|
return this->operator*(1.0f - alpha) + (goal * alpha);
|
|
}
|
|
|
|
#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
|
|
|
|
|
|
|
|
#pragma region EulerAngle
|
|
|
|
EulerAngle::EulerAngle(float pitch, float yaw, float roll): pitch(pitch), yaw(yaw), roll(roll)
|
|
{}
|
|
|
|
float EulerAngle::GetPitch(float pitch_limit) const
|
|
{ return std::clamp( std::remainderf(pitch,360.f), -pitch_limit, pitch_limit); }
|
|
|
|
float EulerAngle::GetYaw(float yaw_limit) const
|
|
{ return std::clamp(std::remainderf(yaw, 360.f), -yaw_limit, yaw_limit); }
|
|
|
|
float EulerAngle::GetRoll(float pitch_limit) const
|
|
{ return std::clamp( std::remainderf(pitch,360.f), -pitch_limit, pitch_limit); }
|
|
|
|
bool EulerAngle::operator==(const EulerAngle& a) const
|
|
{
|
|
return (pitch == a.pitch) && (yaw == a.yaw) && (roll == a.roll);
|
|
}
|
|
|
|
void EulerAngle::clamp()
|
|
{
|
|
if (this->pitch > 89.0f)
|
|
this->pitch = 89.0f;
|
|
if (this->pitch <= -89.0f)
|
|
this->pitch = -89.0f;
|
|
//TODO: Make this entirely seamless by getting the amount they rotated passed -180 and +180 by.
|
|
if (this->yaw <= -180.0f)
|
|
this->yaw = 180.0f;
|
|
if (this->yaw >= 180.01f)
|
|
this->yaw = -179.9f;
|
|
if (this->roll >= 360.0f)
|
|
this->roll = 0.0;
|
|
if (this->roll <= -360.0f)
|
|
this->roll = 0.0;
|
|
}
|
|
|
|
EulerAngle EulerAngle::movementAngle() const
|
|
{
|
|
EulerAngle a;
|
|
a.pitch = (cos(glm::radians(yaw)) * cos(glm::radians(pitch)));
|
|
a.yaw = -sin(glm::radians(pitch));
|
|
a.roll = (sin(glm::radians(yaw)) * cos(glm::radians(pitch)));
|
|
return a;
|
|
}
|
|
|
|
|
|
const Matrix3x3 Matrix3x3::Zero = Matrix3x3(0,0,0, 0,0,0, 0,0,0);
|
|
const Matrix3x3 Matrix3x3::Identity = Matrix3x3(1,0,0, 0,1,0, 0,0,1);
|
|
const Matrix3x3 Matrix3x3::NaN = Matrix3x3(NAN);
|
|
|
|
Matrix3x3::Matrix3x3(float m00, float m01, float m02, float m10, float m11, float m12, float m20, float m21,
|
|
float m22)
|
|
{
|
|
this->elems[0][0] = m00;
|
|
this->elems[0][1] = m01;
|
|
this->elems[0][2] = m02;
|
|
|
|
this->elems[1][0] = m10;
|
|
this->elems[1][1] = m11;
|
|
this->elems[1][2] = m12;
|
|
|
|
this->elems[2][0] = m20;
|
|
this->elems[2][1] = m21;
|
|
this->elems[2][2] = m22;
|
|
}
|
|
|
|
Vector3 Matrix3x3::GetRow(int index) const
|
|
{
|
|
float x = this->elems[index][0];
|
|
float y = this->elems[index][1];
|
|
float z = this->elems[index][2];
|
|
return {x,y,z};
|
|
}
|
|
|
|
Vector3 Matrix3x3::GetColumn(int index) const
|
|
{
|
|
float x = this->elems[0][index];
|
|
float y = this->elems[1][index];
|
|
float z = this->elems[2][index];
|
|
|
|
return {x,y,z};
|
|
}
|
|
|
|
float Matrix3x3::At(int x, int y) const
|
|
{
|
|
return this->elems[x][y];
|
|
|
|
}
|
|
|
|
Vector3 Matrix3x3::operator*(const Vector3& rhs) const
|
|
{
|
|
return {
|
|
At(0,0) * rhs.x + At(0, 1) * rhs.y + At(0, 2) * rhs.z,
|
|
At(1, 0) * rhs.x + At(1, 1) * rhs.y + At(1, 2) * rhs.z,
|
|
At(2, 0) * rhs.x + At(2, 1) * rhs.y + At(2,2) * rhs.z
|
|
};
|
|
}
|
|
|
|
Matrix3x3 Matrix3x3::operator*(const Matrix3x3& rhs) const
|
|
{
|
|
//Matrix3x3 r;
|
|
auto m00 = At(0, 0) * rhs.At(0, 0) + At(0, 1) * rhs.At(1, 0) + At(0, 2) * rhs.At(2, 0);
|
|
auto m01 = At(0, 0) * rhs.At(0, 1) + At(0, 1) * rhs.At(1, 1) + At(0, 2) * rhs.At(2, 1);
|
|
auto m02 = At(0, 0) * rhs.At(0, 2) + At(0, 1) * rhs.At(1, 2) + At(0, 2) * rhs.At(2, 2);
|
|
|
|
auto m10 = At(1, 0) * rhs.At(0, 0) + At(1, 1) * rhs.At(1, 0) + At(1, 2) * rhs.At(2, 0);
|
|
auto m11 = At(1, 0) * rhs.At(0, 1) + At(1, 1) * rhs.At(1, 1) + At(1, 2) * rhs.At(2, 1);
|
|
auto m12 = At(1, 0) * rhs.At(0, 2) + At(1, 1) * rhs.At(1, 2) + At(1, 2) * rhs.At(2,2);
|
|
|
|
auto m20 = At(2, 0) * rhs.At(0, 0) + At(2, 1) * rhs.At(1, 0) + At(2,2) * rhs.At(2, 0);
|
|
auto m21 = At(2, 0) * rhs.At(0, 1) + At(2, 1) * rhs.At(1, 1) + At(2,2) * rhs.At(2, 1);
|
|
auto m22 = At(2, 0) * rhs.At(0, 2) + At(2, 1) * rhs.At(1, 2) + At(2,2) * rhs.At(2,2);
|
|
|
|
return Matrix3x3({m00, m01, m02}, {m10, m11, m12}, {m20, m21, m22});
|
|
}
|
|
|
|
Quaternion Quaternion::operator-() const
|
|
{
|
|
return {-x, -y, -z, -w};
|
|
}
|
|
|
|
|
|
#pragma endregion
|
|
|
|
|
|
|
|
#pragma region Matrix2x2
|
|
|
|
#pragma endregion
|
|
|
|
|
|
|
|
#pragma region Matrix3x3
|
|
|
|
#pragma endregion
|
|
|
|
|
|
#pragma region Matrix4x4
|
|
|
|
|
|
#pragma endregion
|
|
|
|
|
|
#pragma region Quaternion
|
|
|
|
#pragma endregion
|
|
} |