Files
j3ml/include/J3ML/Geometry/Triangle2D.hpp
Redacted 47993084ff
Some checks failed
Run ReCI Build Test / Explore-Gitea-Actions (push) Failing after 1m29s
Build Docs With Doxygen / Explore-Gitea-Actions (push) Successful in 22s
Set up shapes for dynamic cast
2024-08-20 21:37:14 -04:00

242 lines
15 KiB
C++

#pragma once
#include <J3ML/Geometry/Shape.hpp>
#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 Shape2D {
public:
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);
}