Actually builds now (Sorry bout that)
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m13s
Build Docs With Doxygen / Explore-Gitea-Actions (push) Successful in 20s

This commit is contained in:
2024-08-05 18:24:51 -04:00
parent 6aa7dc9745
commit 11062e761a
11 changed files with 80 additions and 28 deletions

View File

@@ -14,7 +14,7 @@
#include <J3ML/LinearAlgebra/Common.hpp> #include <J3ML/LinearAlgebra/Common.hpp>
#include <J3ML/Geometry/Common.hpp> #include <J3ML/Geometry/Common.hpp>
#include <J3ML/Geometry/Shape.hpp> #include <J3ML/Geometry/Shape.hpp>
#include "Circle.hpp" #include <J3ML/Geometry/Circle.hpp>
namespace J3ML::Geometry namespace J3ML::Geometry
{ {

View File

@@ -12,6 +12,7 @@
#pragma once #pragma once
#include <J3ML/LinearAlgebra.hpp> #include <J3ML/LinearAlgebra.hpp>
#include <J3ML/Geometry/Common.hpp>
namespace J3ML namespace J3ML
{ {

View File

@@ -239,8 +239,8 @@ namespace J3ML::LinearAlgebra {
/// Returns a normalized copy of this vector. /// Returns a normalized copy of this vector.
/** @note If the vector is zero and cannot be normalized, the vector (1, 0) is returned, and an error message is printed. /** @note If the vector is zero and cannot be normalized, the vector (1, 0) is returned, and an error message is printed.
If you do not want to generate an error message on failure, but want to handle the failure yourself, use the If you do not want to generate an error message on failure, but want to handle the failure yourself, use the
Normalize() function instead. Normalized() function instead.
@see Normalize() */ @see Normalized() */
[[nodiscard]] Vector2 Normalized() const; [[nodiscard]] Vector2 Normalized() const;
/// Linearly interpolates between two points. /// Linearly interpolates between two points.

View File

@@ -178,6 +178,13 @@ public:
@see ScaledToLength(). */ @see ScaledToLength(). */
float ScaleToLength(float newLength); float ScaleToLength(float newLength);
/// Returns a scaled copy of this vector which has its new length as given.
/** This function assumes the length of this vector is not zero. In the case of failure, an error message is printed,
and the vector (newLength, 0, 0) is returned.
@see ScaleToLength(). */
[[nodiscard]] Vector3 ScaledToLength(float newLength) const;
[[nodiscard]] Vector3 ProjectToNorm(const Vector3& direction) const; [[nodiscard]] Vector3 ProjectToNorm(const Vector3& direction) const;
@@ -225,11 +232,15 @@ public:
@see Perpendicular(), Cross(). */ @see Perpendicular(), Cross(). */
Vector3 AnotherPerpendicular(const Vector3& hint = Vector3(0,1,0), const Vector3& hint2 = Vector3(0,0,1)) const; Vector3 AnotherPerpendicular(const Vector3& hint = Vector3(0,1,0), const Vector3& hint2 = Vector3(0,0,1)) const;
/// Returns a scaled copy of this vector which has its new length as given. /// Completes this vector to generate a perpendicular basis.
/** This function assumes the length of this vector is not zero. In the case of failure, an error message is printed, /** This function computes two new vectors b and c which are both orthogonal to this vector and to each other.
and the vector (newLength, 0, 0) is returned. That is, the set { this, b, c} is an orthogonal set. The vectors b and c that are outputted are also normalized.
@see ScaleToLength(). */ @param outB [out] Receives vector b.
Vector3 ScaledToLength(float newLength) const; @param outC [out] Receives vector c.
@note When calling this function, this vector should not be zero! */
void PerpendicularBasis(Vector3& outB, Vector3& outC) const;
[[nodiscard]] Vector3 Min(const Vector3& min) const; [[nodiscard]] Vector3 Min(const Vector3& min) const;
static Vector3 Min(const Vector3& a, const Vector3& b, const Vector3& c); static Vector3 Min(const Vector3& a, const Vector3& b, const Vector3& c);
@@ -282,8 +293,8 @@ public:
/// Returns a copy of this vector, resized to have a magnitude of 1, while preserving "direction" /// Returns a copy of this vector, resized to have a magnitude of 1, while preserving "direction"
/// @note If the vector is zero and cannot be normalized, the vector (1, 0, 0) is returned, and an error message is printed. /// @note If the vector is zero and cannot be normalized, the vector (1, 0, 0) is returned, and an error message is printed.
/// If you do not want to generate an error message on failure, but want to handle the failure yourself, use the Normalize() function instead. /// If you do not want to generate an error message on failure, but want to handle the failure yourself, use the Normalized() function instead.
/// @see Normalize() /// @see Normalized()
[[nodiscard]] Vector3 Normalized() const; [[nodiscard]] Vector3 Normalized() const;
static Vector3 Normalized(const Vector3& targ); static Vector3 Normalized(const Vector3& targ);

View File

@@ -217,7 +217,7 @@ namespace J3ML::LinearAlgebra {
[[nodiscard]] Vector4 Cross3(const Vector4& rhs) const; [[nodiscard]] Vector4 Cross3(const Vector4& rhs) const;
[[nodiscard]] Vector4 Cross(const Vector4& rhs) const; [[nodiscard]] Vector4 Cross(const Vector4& rhs) const;
[[nodiscard]] Vector4 Normalize() const; [[nodiscard]] Vector4 Normalized() const;
[[nodiscard]] Vector4 Lerp(const Vector4& goal, float alpha) const; [[nodiscard]] Vector4 Lerp(const Vector4& goal, float alpha) const;
[[nodiscard]] float AngleBetween(const Vector4& rhs) const; [[nodiscard]] float AngleBetween(const Vector4& rhs) const;
@@ -265,6 +265,8 @@ namespace J3ML::LinearAlgebra {
float y = 0; float y = 0;
float z = 0; float z = 0;
float w = 0; float w = 0;
void Normalize();
}; };
} }

View File

@@ -189,6 +189,16 @@ namespace J3ML::Geometry
return 2.f * Math::Pi * r * LineLength() + 4.f * Math::Pi * r * r; return 2.f * Math::Pi * r * LineLength() + 4.f * Math::Pi * r * r;
} }
OBB Capsule::MinimalEnclosingOBB() const {
OBB obb;
obb.axis[0] = UpDirection();
obb.axis[0].PerpendicularBasis(obb.axis[1], obb.axis[2]);
obb.pos = Center();
obb.r[0] = Height() * 0.5f;
obb.r[1] = r;
obb.r[2] = r;
return obb;
}
} }

View File

@@ -159,7 +159,7 @@ namespace J3ML::Geometry
Vector3 Dir = ((Vector3)v[f[j].v[0]] + (Vector3)v[f[j].v[1]] + (Vector3)v[f[j].v[2]]) * 0.333333333333f - point; Vector3 Dir = ((Vector3)v[f[j].v[0]] + (Vector3)v[f[j].v[1]] + (Vector3)v[f[j].v[2]]) * 0.333333333333f - point;
//if (Dir.Normalize() <= 0.f) //if (Dir.Normalized() <= 0.f)
//continue; //continue;
Ray r(Vector3(), Dir); Ray r(Vector3(), Dir);
@@ -368,7 +368,7 @@ namespace J3ML::Geometry
Vector4 b = Vector4(poly.v[face.v[1]], 1.f); Vector4 b = Vector4(poly.v[face.v[1]], 1.f);
Vector4 c = Vector4(poly.v[face.v[2]], 1.f); Vector4 c = Vector4(poly.v[face.v[2]], 1.f);
Vector4 normal = (b-a).Cross(c-a); Vector4 normal = (b-a).Cross(c-a);
normal.Normalize(); normal.Normalized();
return normal; return normal;
// return ((vec)v[face.v[1]]-(vec)v[face.v[0]]).Cross((vec)v[face.v[2]]-(vec)v[face.v[0]]).Normalized(); // return ((vec)v[face.v[1]]-(vec)v[face.v[0]]).Cross((vec)v[face.v[2]]-(vec)v[face.v[0]]).Normalized();
} }
@@ -386,7 +386,7 @@ namespace J3ML::Geometry
normal.z += (double(poly.v[v0].x) - poly.v[v1].x) * (double(poly.v[v0].y) + poly.v[v1].y); // Project on xy normal.z += (double(poly.v[v0].x) - poly.v[v1].x) * (double(poly.v[v0].y) + poly.v[v1].y); // Project on xy
v0 = v1; v0 = v1;
} }
normal.Normalize(); normal.Normalized();
return normal; return normal;
#if 0 #if 0
cv bestNormal; cv bestNormal;
@@ -397,7 +397,7 @@ namespace J3ML::Geometry
{ {
cv c = poly.v[face.v[i]]; cv c = poly.v[face.v[i]];
cv normal = (c-b).Cross(a-b); cv normal = (c-b).Cross(a-b);
float len = normal.Normalize(); float len = normal.Normalized();
if (len > bestLen) if (len > bestLen)
{ {
bestLen = len; bestLen = len;
@@ -441,7 +441,7 @@ namespace J3ML::Geometry
cv edge = cv(poly.v[i]) - cv(poly.v[bestV0]); cv edge = cv(poly.v[i]) - cv(poly.v[bestV0]);
edge.Normalize(); edge.Normalize();
cv normal = bestEdge.Cross(edge); cv normal = bestEdge.Cross(edge);
cs len = normal.Normalize(); cs len = normal.Normalized();
if (len > bestLen) if (len > bestLen)
{ {
bestLen = len; bestLen = len;

View File

@@ -105,7 +105,7 @@ namespace J3ML::LinearAlgebra {
bool Vector3::operator!=(const Vector3& rhs) const bool Vector3::operator!=(const Vector3& rhs) const
{ {
return this->IsWithinMarginOfError(rhs) == false; return !this->IsWithinMarginOfError(rhs);
} }
@@ -318,9 +318,9 @@ namespace J3ML::LinearAlgebra {
Angle2D Vector3::AngleBetween(const Vector3 &rhs) const { Angle2D Vector3::AngleBetween(const Vector3 &rhs) const {
const auto Pi_x_180 = 180.f / M_PI; const auto Pi_x_180 = 180.f / M_PI;
auto dist = this->Distance(rhs); auto dist = this->Distance(rhs);
float x = -(asinf((rhs.y - this->y) / dist)); float dx = -(asinf((rhs.y - this->y) / dist));
float y = (atan2f(rhs.x - this->x,rhs.z - this->z)); float dy = (atan2f(rhs.x - this->x,rhs.z - this->z));
return {x, y}; return {dx, dy};
} }
Angle2D Vector3::AngleBetween(const Vector3 &lhs, const Vector3 &rhs) // TODO: 3D Angle representation? Angle2D Vector3::AngleBetween(const Vector3 &lhs, const Vector3 &rhs) // TODO: 3D Angle representation?
@@ -329,9 +329,9 @@ namespace J3ML::LinearAlgebra {
} }
Vector3 Vector3::Direction(const Vector3 &rhs) { Vector3 Vector3::Direction(const Vector3 &rhs) {
float x = (cos(Math::Radians(rhs.y)) * cos(Math::Radians(rhs.x))); float x = (Math::Cos(Math::Radians(rhs.y)) * Math::Cos(Math::Radians(rhs.x)));
float y = -sin(Math::Radians(rhs.x)); float y = -Math::Sin(Math::Radians(rhs.x));
float z = (sin(Math::Radians(rhs.y)) * cos(Math::Radians(rhs.x))); float z = (Math::Sin(Math::Radians(rhs.y)) * Math::Cos(Math::Radians(rhs.x)));
return {x, y, z}; return {x, y, z};
} }
@@ -600,5 +600,22 @@ namespace J3ML::LinearAlgebra {
return *this + Vector3(s, s, s); return *this + Vector3(s, s, s);
} }
Vector3 Vector3::ScaledToLength(float newLength) const {
assert(!IsZero());
Vector3 v = *this;
v.ScaleToLength(newLength);
return v;
}
void Vector3::PerpendicularBasis(Vector3 &outB, Vector3 &outC) const {
// Pixar orthonormal basis code: https://graphics.pixar.com/library/OrthonormalB/paper.pdf
float sign = copysignf(1.0f, z);
const float a = -1.0f / (sign + z);
const float b = x * y * a;
outB = Vector3(1.0f + sign * x * x * a, sign * b, -sign * x);
outC = Vector3( b, sign + y * y * a, -y);
}
} }

View File

@@ -132,8 +132,8 @@ float Vector4::Magnitude() const
float Vector4::Dot(const Vector4& rhs) const float Vector4::Dot(const Vector4& rhs) const
{ {
auto a = this->Normalize(); auto a = this->Normalized();
auto b = rhs.Normalize(); auto b = rhs.Normalized();
return a.x * b.x + return a.x * b.x +
a.y * b.y + a.y * b.y +
@@ -155,7 +155,17 @@ Vector4 Vector4::Project(const Vector4& rhs) const
return rhs * scalar; return rhs * scalar;
} }
Vector4 Vector4::Normalize() const void Vector4::Normalize()
{
if (Length() > 0) {
x = x / Length();
y = y / Length();
z = z / Length();
w = w / Length();
}
}
Vector4 Vector4::Normalized() const
{ {
if (Length() > 0) if (Length() > 0)
return { return {
@@ -274,6 +284,7 @@ Vector4 Vector4::operator-(const Vector4& rhs) const
if (index == 2) return z; if (index == 2) return z;
if (index == 3) return w; if (index == 3) return w;
return x; // This point should never be reached.
} }
float Vector4::At(int index) const { float Vector4::At(int index) const {

View File

@@ -156,7 +156,7 @@ int Vector2Tests()
jtest::check(Base.Project(Projected) == ExpectedResult); jtest::check(Base.Project(Projected) == ExpectedResult);
}); });
TEST("Vector2::Normalize", [] TEST("Vector2::Normalized", []
{ {
Vector2 A(2, 0); Vector2 A(2, 0);
Vector2 B(1, 0); Vector2 B(1, 0);

View File

@@ -173,7 +173,7 @@ int Vector3Tests() {
Vector3 Projection; Vector3 Projection;
Vector3 ExpectedResult; Vector3 ExpectedResult;
}); });
TEST("Vector3::Normalize", [] { TEST("Vector3::Normalized", [] {
Vector3 Input (2, 0, 0); Vector3 Input (2, 0, 0);
Vector3 ExpectedResult (1, 0, 0); Vector3 ExpectedResult (1, 0, 0);