242 lines
15 KiB
C++
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);
|
|
} |