Ideally fixed!!!
This commit is contained in:
@@ -1,12 +1,241 @@
|
||||
#pragma once
|
||||
|
||||
#include <J3ML/LinearAlgebra/Forward.hpp>
|
||||
#include <J3ML/LinearAlgebra/Vector2.hpp>
|
||||
#include <J3ML/Geometry/Forward.hpp>
|
||||
#include <J3ML/Algorithm/RNG.hpp>
|
||||
|
||||
namespace J3ML::Geometry
|
||||
{
|
||||
using J3ML::LinearAlgebra::Vector2;
|
||||
using J3ML::Algorithm::RNG;
|
||||
/// Specifies a triangle through three points in 2D space.
|
||||
/// This class stores three member vertices A, B, and C to specify the triangle.
|
||||
/** @note The order in which the vertices are stored in this data structure is important.
|
||||
The triangles (a,b,c) and (a,c,b) are otherwise equivalent, but their plane normals point to the opposite directions.
|
||||
@see PlaneCCW(), PlaneCW() */
|
||||
class Triangle2D {
|
||||
|
||||
public:
|
||||
Vector2 A;
|
||||
Vector2 B;
|
||||
Vector2 C;
|
||||
Vector2 A; /// The first Triangle endpoint.
|
||||
Vector2 B; /// The second Triangle endpoint.
|
||||
Vector2 C; /// The third Triangle endpoint.
|
||||
public:
|
||||
/// The default constructor does not initialize any members of this class.
|
||||
/** This means that the values of the members a, b, and c are undefined after creating a new Triangle2D using this
|
||||
default constructor. Remember to assign to them before use. */
|
||||
Triangle2D() {}
|
||||
/// Constructs a triangle from three given endpoints.
|
||||
/** The normal of the plane will be constructed to point towards the halfspace where
|
||||
the vertices a, b, and c wind in counter-clockwise order. */
|
||||
Triangle2D(const Vector2& a, const Vector2& b, const Vector2& c);
|
||||
public:
|
||||
static int NumFaces() { return 1; }
|
||||
static int NumEdges() { return 3; }
|
||||
static int NumVertices() { return 3; }
|
||||
|
||||
/// Translates this Triangle2D in world space.
|
||||
/** @param offset The amount of displacement to apply to this Triangle2D, in world space coordinates.
|
||||
@see Transform(). */
|
||||
void Translate(const Vector2& offset);
|
||||
|
||||
/// Applies a transformation to this Triangle2D, in-place.
|
||||
/** @see Translate(), classes Matrix3x3, Matrix4x4, Quaternion. */
|
||||
void Transform(const Matrix3x3& transform);
|
||||
void Transform(const Matrix4x4& transform);
|
||||
|
||||
/// Expresses the given point in barycentric (u,v,w) coordinates.
|
||||
/** @note There are two different conventions for representing barycentric coordinates. One uses a
|
||||
(u, v, w) triplet with the equation pt = u*a + v*b + w*c, and the other uses a (u,v) pair
|
||||
with the equation pt = a + u*(b-a) + v*(c-a). These two are equivalent. Use the mappings
|
||||
(u,v) -> (1-u-v, u, v) and (u,v,w)->(v,w) to convert between these two representations.
|
||||
@param point The point of the vector space to express in barycentric coordinates. This point should
|
||||
lie in the plane formed by this triangle.
|
||||
@return The factors (u,v,w) that satisfy the weighted sum equation point == u*a + v*b + w*c.
|
||||
@see BarycentricUV(), BarycentricInsideTriangle(), Point(), http://mathworld.wolfram.com/BarycentricCoordinates.html */
|
||||
Vector3 BarycentricUVW(const Vector2& point) const;
|
||||
|
||||
/// Expresses the given point in barycentric (u, v) coordinates.
|
||||
/** @note There are two different conventions for representing barycentric coordinates. One uses a
|
||||
(u, v, w) triplet with the equation pt = u*a + v*b + w*c, and the other uses a (u,v) pair
|
||||
with the equation pt = a + u*(b-a) + v*(c-a). These two are equivalent. Use the mappings
|
||||
(u,v) -> (1-u-v, u, v) and (u,v,w)->(v,w) to convert between these two representations.
|
||||
@param point The point to express in barycentric coordinates. This point should lie in the plane
|
||||
formed by this triangle.
|
||||
@return The factors (u, v) that satisfy the weighted sum equation point == a + u*(b-a) + v*(c-a)
|
||||
@see BarycentricUVW(), BarycentricInsideTriangle(), Point() */
|
||||
Vector2 BarycentricUV(const Vector2& point) const;
|
||||
|
||||
/// Tests if the given barycentric UVW coordinates lie inside a triangle.
|
||||
/** A barycentric UVW coordinate represents a point inside a triangle if
|
||||
a) 0 <= u,v,w <= 1 and
|
||||
b) u+v+w == 1.
|
||||
@param uvw The barycentric vector containing the barycentric (u,v,w) coordinates.
|
||||
@return True if the given coordinates lie inside a triangle.
|
||||
@see BarycentricUV(), BarycentricUVW(), Point(). */
|
||||
static bool BarycentricInsideTriangle(const Vector3& uvw);
|
||||
|
||||
/// Returns the point at the given barycentric coordinates.
|
||||
/** This function computes the vector space point at the given barycentric coordinates.
|
||||
@param uvw The barycentric UVW coordiante triplet. The condition u+v+w == 1 should hold for the input coordinate.
|
||||
If 0 <= u,v,w <= 1, the returned point lies inside this triangle.
|
||||
@return u*a + v*b + w*c. */
|
||||
Vector2 Point(const Vector3& uvw) const;
|
||||
Vector2 Point(float u, float v, float w) const;
|
||||
|
||||
/** These functions are an alternate form of Point(u,v,w) for the case when the barycentric coordinates are
|
||||
represented as a (u,v) pair and not as a (u,v,w) triplet. This function is provided for convenience
|
||||
and effectively just computes Point(1-u-v, u, v).
|
||||
@param uv The barycentric UV coordinates. If 0 <= u,v <= 1 and u+v <= 1, then the returned point lies inside
|
||||
this triangle.
|
||||
@return a + (b-a)*u + (c-a)*v.
|
||||
@see BarycentricUV(), BarycentricUVW(), BarycentricInsideTriangle(). */
|
||||
Vector2 Point(const Vector2& uv) const;
|
||||
Vector2 Point(float u, float v) const;
|
||||
|
||||
/// Computes the center of mass of this triangle.
|
||||
/** @return The point (a+b+c)/3. */
|
||||
Vector2 Centroid() const;
|
||||
/// Identical to Centroid(), we provide both to enable common signature with AABB2D, and OBB2D to allow them in template algorithms.
|
||||
Vector2 CenterPoint() const { return Centroid();}
|
||||
/// Computes the surface area of this triangle.
|
||||
/** @return The surface area of this triangle.
|
||||
@see Perimeter(), Area2D(), SignedArea(). */
|
||||
float Area() const;
|
||||
|
||||
/// Computes the total edge length of this triangle.
|
||||
/** @return |a-b| + |b-c| + |c-a|.
|
||||
@see Area(), Edge(). */
|
||||
float Perimeter() const;
|
||||
|
||||
/// Returns a pointer to the vertices of this triangle. The array contains three elements.
|
||||
Vector2* VertexArrayPtr() { return &A;}
|
||||
const Vector2* VertexArrayPtr() const { return &A;}
|
||||
|
||||
/// Returns a vertex of this triangle.
|
||||
/** @param i The vertex of the triangle to get: 0, 1, or 2.
|
||||
@return Vertex(0) returns the point A, Vertex(1) returns the point B, and Vertex(2) returns the point C.
|
||||
@note If an index outside [0,2] is passed, an assume() failure occurs, and a NaN vector is returned.
|
||||
@see Edge(). */
|
||||
Vector2 Vertex(int i) const;
|
||||
Vector2 CornerPoint(int i) const { return Vertex(i);} // An alias for Vertex() to be able to mesh Triangle2D into templatized algorithms.
|
||||
|
||||
|
||||
//LineSegment2D Edge(int i) const; // TODO: Implement class LineSegment2D
|
||||
|
||||
/// Quickly returns an arbitrary point inside this Triangle2D. Used in GJK intersection test.
|
||||
inline Vector2 AnyPointFast() const { return A;}
|
||||
|
||||
/// Computes an extreme point of this Triangle2D in the given direction.
|
||||
/** An extreme point is the farthest point of this Triangle2D in the given direction. Given a direction,
|
||||
this point is not necessarily unique.
|
||||
@param direction THe direction vector of the direction to find the extreme point. This vector may
|
||||
be unnormalized, but may not be null.
|
||||
@return An extreme point of this Triangle2D in the given direction. The returned point is always a
|
||||
vertex of this Triangle2D.
|
||||
@see Vertex(). */
|
||||
Vector2 ExtremePoint(const Vector2& direction) const;
|
||||
Vector2 ExtremePoint(const Vector2& direction, float& projectionDistance) const;
|
||||
|
||||
/// Returns the tight AABB2D that encloses this Triangle2D.
|
||||
AABB2D BoundingAABB() const;
|
||||
|
||||
/// Computes the surface area of the given 2D triangle.
|
||||
/** This math library does not have a separate class for for 2D triangles. To compute the area of a 2D triangle,
|
||||
use this Triangle2D class and set z=0 for each coordinate, or use this helper function.
|
||||
@see Area(), SignedArea().*/
|
||||
static float Area2D(const Vector2& p1, const Vector2& p2, const Vector2& p3);
|
||||
/// Relates the barycentric coordinate of the given point to the surface area of triangle abc.
|
||||
/** This function computes the ratio of the signed area of the triangle (point, b, c) to the signed area of
|
||||
the triangle (a,b,c). This is the same as computng the barycentric u-coordinate of the given point
|
||||
on the triangle (a,b,c).
|
||||
@see Area(), Area2D(), BarycentricUVW(). */
|
||||
static float SignedArea(const Vector2& point, const Vector2& a, const Vector2& b, const Vector2& c);
|
||||
|
||||
/// Returns true if this triangle is finite.
|
||||
/** A triangle is <b><i>finite</i></b> if its vertices a,b, and c do not contain floating-point NaNs or +/-infs
|
||||
in them.
|
||||
@return True if each coordinate of each vertex of this triangle has a finite floating-point value.
|
||||
@see A, B, C, IsDegenerate(), ::IsFinite(), IsInf(), IsNan(), IsFinite() */
|
||||
bool IsFinite() const;
|
||||
/// Returns true if this triangle is degenerate.
|
||||
/** A triangle is <b><i>degenerate</i></b> if it is not finite, or if the surface area of the triangle is
|
||||
close to zero.
|
||||
@param epsilon The threshold to test against. If two vertices of this triangle are closer than this, the
|
||||
triangle is considered degenerate.
|
||||
@see a, b, c, IsFinite() */
|
||||
bool IsDegenerate(float epsilon = 1e-3f) const;
|
||||
|
||||
/// Returns true if the triangle defined by the three given points is degenerate.
|
||||
static bool IsDegenerate(const Vector2& p1, const Vector2& p2, const Vector2& p3, float epsilon = 1e-3f);
|
||||
|
||||
/// In some templated algorithms, the input can either be a Triangle2D or a Polygon2D. Provide trivial Polygon2D-specific API
|
||||
/// for compatibility in those template functions.
|
||||
bool IsConvex() const { return true;}
|
||||
bool IsPlanar() const { return true;}
|
||||
bool IsSimple() const { return true;}
|
||||
|
||||
/// Tests if the given object is fully contained inside this triangle.
|
||||
/** @param triangleThickness An epsilon threshold value to use for this test. triangleThicknessSq is the squared version of this parameter.
|
||||
This specifies the maximum distance the given object can lie from the plane defined by this triangle.
|
||||
@see Distance(), Intersects(), ClosestPoint(). */
|
||||
bool Contains(const Vector2& point, float triangleThicknessSq = 1e-5f) const;
|
||||
/// Computes the distance between this triangle and the given object.
|
||||
/** This function finds the nearest pair of points on this and the given object, and computes their distance.
|
||||
If the two objects intersect, or one object is contained inside the other, the returned distance is zero.
|
||||
@see Contains(), Intersects(), ClosestPoint(). */
|
||||
float Distance(const Vector2& point) const;
|
||||
float DistanceSquared(const Vector2& point) const;
|
||||
float DistanceSq(const Vector2& point) const { return DistanceSquared(point); }
|
||||
|
||||
/// A helper function used in line-triangle tests.
|
||||
static float IntersectLineTri(const Vector2& linePos, const Vector2& lineDir,
|
||||
const Vector2& v0, const Vector2& v1, const Vector2& v2,
|
||||
float& u, float& v);
|
||||
|
||||
/// Projects this triangle onto the given axis.
|
||||
/** This function is used in SAT tests (separate axis theorem) to check the interval this triangle
|
||||
lies in on an 1D line.
|
||||
@param axis THe axis to project onto. This vector can be unnormalized.
|
||||
@param dMin [out] Returns the minimum extent of this triangle on the given axis.
|
||||
@param dMax [out] Returns the maximum extent of this triangle on the given axis. */
|
||||
void ProjectToAxis(const Vector2& axis, float& dMin, float& dMax) const;
|
||||
int UniqueFaceNormals(Vector2* out) const;
|
||||
int UniqueEdgeNormals(Vector2* out) const;
|
||||
|
||||
/// Computes the closest point on this triangle to the given object.
|
||||
/** If the other object intersects this triangle, the function will return an arbitrary point inside
|
||||
the region of intersection.
|
||||
@see Contains(), Distance(), Intersects(), ClosestPointToTriangleEdge(). */
|
||||
Vector2 ClosestPoint(const Vector2& point) const;
|
||||
//Vector2 ClosestPoint(const LineSegment2D& lineSegment, Vector2* otherPt = 0) const;
|
||||
|
||||
/// Generates a random point inside this Triangle2D.
|
||||
/** The points are distrubited uniformly.
|
||||
The implementation of this function is based on Graphics Gems 1, p. 25:
|
||||
"1.5 Generating random points on triangles. Method 2." The Method 1 presented in the book
|
||||
uses a Sqrt() instead of the if().
|
||||
@param rng A pre-seeded random number generator object that is to be used by this function to generate random values.
|
||||
@see class RNG, RandomPointOnEdge(), RandomVertex(), Point() */
|
||||
Vector2 RandomPointInside(RNG& rng) const;
|
||||
|
||||
/// Choose a corner vertex of this triangle2D at random.
|
||||
/** This function returns one of the vertices {a, b, c} uniformly at random.
|
||||
@param rng A pre-seeded random number generator object that is to be used by this function to generate random values.
|
||||
@see class RNG(), RandomPointInside(), RandomPointOnEdge(), Vertex().*/
|
||||
Vector2 RandomVertex(RNG& rng) const;
|
||||
/// Generates a random point on the edge of this Triangle2D.
|
||||
/** The points are distributed uniformly.
|
||||
This function requires that this triangle is not degenerate. This it is, an assume() error will be printed,
|
||||
and the return value will be undefined.
|
||||
@param rng A pre-seeded random number generator object that is to be used by this function to generate random values.
|
||||
@see class RNG, RandomPointInside, RandomVertex(), Edge(), class LineSegment2D, IsDegenerate(). */
|
||||
Vector2 RandomPointOnEdge(RNG& rng) const;
|
||||
std::string ToString() const;
|
||||
bool Equals(const Triangle2D& rhs, float epsilon = 1e-3f) const {
|
||||
return A.Equals(rhs.A, epsilon) && B.Equals(rhs.B, epsilon) && C.Equals(rhs.C, epsilon);
|
||||
}
|
||||
};
|
||||
|
||||
std::ostream& operator << (std::ostream& o, const Triangle2D& triangle);
|
||||
}
|
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <cstddef>
|
||||
#include <J3ML/Algorithm/RNG.hpp>
|
||||
#include <J3ML/LinearAlgebra/Forward.hpp>
|
||||
|
||||
namespace J3ML::LinearAlgebra {
|
||||
using namespace J3ML;
|
||||
@@ -382,7 +383,17 @@ namespace J3ML::LinearAlgebra {
|
||||
|
||||
/// Returns a random Vector2 with each entry randomized between the range [minElem, maxElem].
|
||||
static Vector2 RandomBox(Algorithm::RNG& rng, float minElem, float maxElem);
|
||||
|
||||
[[nodiscard]] std::string ToString() const;
|
||||
};
|
||||
|
||||
Vector2 operator*(float lhs, const Vector2 &rhs);
|
||||
|
||||
std::ostream& operator << (std::ostream& out, const Vector2& rhs);
|
||||
|
||||
|
||||
Vector2 Mul2D(const Matrix3x3& transform, const Vector2& v);
|
||||
Vector2 MulPos2D(const Matrix4x4& transform, const Vector2& v);
|
||||
Vector2 MulDir2D(const Matrix4x4& transform, const Vector2& v);
|
||||
|
||||
}
|
||||
|
1
src/J3ML/Geometry/PBVolume.cpp
Normal file
1
src/J3ML/Geometry/PBVolume.cpp
Normal file
@@ -0,0 +1 @@
|
||||
#include <J3ML/Geometry/PBVolume.hpp>
|
135
src/J3ML/Geometry/Triangle2D.cpp
Normal file
135
src/J3ML/Geometry/Triangle2D.cpp
Normal file
@@ -0,0 +1,135 @@
|
||||
#include <J3ML/Geometry/Triangle2D.hpp>
|
||||
#include <J3ML/LinearAlgebra/Vector2.hpp>
|
||||
#include <J3ML/LinearAlgebra/Matrix3x3.hpp>
|
||||
#include <cfloat>
|
||||
|
||||
namespace J3ML::Geometry
|
||||
{
|
||||
|
||||
Triangle2D::Triangle2D(const Vector2& a, const Vector2& b, const Vector2& c) : A(a), B(b), C(c) {}
|
||||
|
||||
void Triangle2D::Translate(const Vector2& offset)
|
||||
{
|
||||
A += offset;
|
||||
B += offset;
|
||||
C += offset;
|
||||
}
|
||||
|
||||
void Triangle2D::Transform(const Matrix3x3& transform)
|
||||
{
|
||||
A = Mul2D(transform, A);
|
||||
B = Mul2D(transform, B);
|
||||
C = Mul2D(transform, C);
|
||||
}
|
||||
|
||||
void Triangle2D::Transform(const Matrix4x4& transform)
|
||||
{
|
||||
A = MulPos2D(transform, A);
|
||||
B = MulPos2D(transform, B);
|
||||
C = MulPos2D(transform, C);
|
||||
}
|
||||
|
||||
/// Implementation from Crister Ericson's Real-Time Collision Detection, pp. 51-52.
|
||||
inline float TriArea2D(float x1, float y1, float x2, float y2, float x3, float y3)
|
||||
{
|
||||
return (x1-x2)*(y2-y3) - (x2-x3)*(y1-y2);
|
||||
}
|
||||
|
||||
Vector3 Triangle2D::BarycentricUVW(const Vector2& point) const
|
||||
{
|
||||
// Implementation from Crister Ericson's Real-Time Collision Detection, pp. 51-52, adapted for 2D.
|
||||
float nu, nv;
|
||||
|
||||
nu = TriArea2D(point.x, point.y, B.x, B.y, C.x, C.y);
|
||||
nv = TriArea2D(point.x, point.y, C.x, C.y, A.x, A.y);
|
||||
float u = nu;
|
||||
float v = nv;
|
||||
float w = 1.f - u - v;
|
||||
return Vector3(u,v,w);
|
||||
}
|
||||
|
||||
Vector2 Triangle2D::BarycentricUV(const Vector2& point) const
|
||||
{
|
||||
Vector3 uvw = BarycentricUVW(point);
|
||||
return Vector2(uvw.y, uvw.z);
|
||||
}
|
||||
|
||||
bool Triangle2D::BarycentricInsideTriangle(const Vector3& barycentric)
|
||||
{
|
||||
return barycentric.x >= 0.f && barycentric.y >= 0 && barycentric.z >= 0.f &&
|
||||
Math::EqualAbs(barycentric.x + barycentric.y + barycentric.z, 1.f);
|
||||
}
|
||||
|
||||
Vector2 Triangle2D::Point(float u, float v) const
|
||||
{
|
||||
// In case the triangle is far away from the origin but is small, the elements of 'a' will have large magnitudes,
|
||||
// and the elements of (b-a) and (c-a) will be much smaller quantities. Therefore, be extra careful with the
|
||||
// parenthesis and first sum the small floats together before adding it to the large one.
|
||||
return A + ((B-A) * u + (C-A) * v);
|
||||
}
|
||||
|
||||
Vector2 Triangle2D::Point(float u, float v, float w) const
|
||||
{
|
||||
return u * A + v * B + w * C;
|
||||
}
|
||||
|
||||
Vector2 Triangle2D::Point(const Vector3 &uvw) const
|
||||
{
|
||||
return Point(uvw.x, uvw.y, uvw.z);
|
||||
}
|
||||
|
||||
Vector2 Triangle2D::Point(const Vector2 &uv) const
|
||||
{
|
||||
return Point(uv.x, uv.y);
|
||||
}
|
||||
|
||||
Vector2 Triangle2D::Centroid() const
|
||||
{
|
||||
return (A + B + C) * (1.f/3.f);
|
||||
}
|
||||
|
||||
float Triangle2D::Perimeter() const
|
||||
{
|
||||
return A.Distance(B) + B.Distance(C) + C.Distance(A);
|
||||
}
|
||||
|
||||
Vector2 Triangle2D::Vertex(int i) const
|
||||
{
|
||||
assert(0 <= i);
|
||||
assert(i <= 2);
|
||||
if (i == 0)
|
||||
return A;
|
||||
else if (i == 1)
|
||||
return B;
|
||||
else if (i == 2)
|
||||
return C;
|
||||
else
|
||||
return Vector2::NaN;
|
||||
}
|
||||
|
||||
|
||||
Vector2 Triangle2D::ExtremePoint(const Vector2& direction) const
|
||||
{
|
||||
Vector2 mostExtreme = Vector2::NaN;
|
||||
float mostExtremeDist = -FLT_MAX;
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
Vector2 pt = Vertex(i);
|
||||
float d = Vector2::Dot(direction, pt);
|
||||
if (d > mostExtremeDist)
|
||||
{
|
||||
mostExtremeDist = d;
|
||||
mostExtreme = pt;
|
||||
}
|
||||
}
|
||||
return mostExtreme;
|
||||
}
|
||||
|
||||
|
||||
Vector2 Triangle2D::ExtremePoint(const Vector2& direction, float& projectionDistance) const
|
||||
{
|
||||
Vector2 extremePoint = ExtremePoint(direction);
|
||||
projectionDistance = extremePoint.Dot(direction);
|
||||
}
|
||||
|
||||
}
|
@@ -3,6 +3,10 @@
|
||||
#include <algorithm>
|
||||
#include <valarray>
|
||||
#include <iostream>
|
||||
#include <format>
|
||||
#include <J3ML/LinearAlgebra/Matrix3x3.hpp>
|
||||
#include <J3ML/LinearAlgebra/Matrix4x4.hpp>
|
||||
#include <J3ML/LinearAlgebra/Vector4.hpp>
|
||||
|
||||
namespace J3ML::LinearAlgebra {
|
||||
|
||||
@@ -491,7 +495,27 @@ namespace J3ML::LinearAlgebra {
|
||||
}
|
||||
}
|
||||
|
||||
std::string Vector2::ToString() const {
|
||||
return std::format("{},{}", x, y);
|
||||
}
|
||||
|
||||
Vector2 operator*(float lhs, const Vector2 &rhs) {
|
||||
return {lhs * rhs.x, lhs * rhs.y};
|
||||
}
|
||||
|
||||
Vector2 Mul2D(const Matrix3x3 &transform, const Vector2 &v) { return transform.Transform(v);}
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const Vector2 &rhs) {
|
||||
std::string str = rhs.ToString();
|
||||
out << str;
|
||||
return out;
|
||||
}
|
||||
|
||||
Vector2 MulPos2D(const Matrix4x4 &transform, const Vector2 &v) {
|
||||
return transform.Transform(Vector4(v.x, v.y, 0.f, 1.f)).XY();
|
||||
}
|
||||
|
||||
Vector2 MulDir2D(const Matrix4x4 &transform, const Vector2 &v) {
|
||||
return transform.Transform(Vector4(v.x, v.y, 0.f, 0.f)).XY();
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user