210 lines
11 KiB
C++
210 lines
11 KiB
C++
#pragma once
|
|
|
|
|
|
#include <J3ML/LinearAlgebra/Common.hpp>
|
|
#include <J3ML/Geometry/Common.hpp>
|
|
#include <J3ML/Geometry/Shape.hpp>
|
|
#include "Circle.hpp"
|
|
|
|
namespace J3ML::Geometry
|
|
{
|
|
|
|
/// A 3D cylinder with spherical ends.
|
|
class Capsule : public Shape
|
|
{
|
|
public:
|
|
/// Specifies the two inner points of this capsule
|
|
LineSegment l;
|
|
/// Specifies the radius of this capsule
|
|
float r;
|
|
public:
|
|
/// The default constructor does not initialize any members of this class.
|
|
/** This means that the values of the members l and r are both undefined after creating a new capsule using
|
|
this default constructor. Remember to assign to them before use.
|
|
@see l, r. */
|
|
Capsule();
|
|
/// Constructs a new capsule by explicitly specifying the member variables.
|
|
/** @param endPoints Specifies the line segment of the capsule.
|
|
@param radius Specifies the size of this capsule.
|
|
@see l, r. */
|
|
Capsule(const LineSegment& endPoints, float radius);
|
|
/// Constructs a new capsule by explicitly specifying the member variables.
|
|
/** This constructor is equivalent to calling Capsule(LineSegment(bottomPoint, topPoint), radius), but provided
|
|
here for conveniency.
|
|
@see l, r. */
|
|
Capsule(const Vector3& bottomPt, const Vector3& topPt, float radius);
|
|
|
|
/// Constructs a new capsule from a sphere.
|
|
/** This conversion results in a capsule which has its both endpoints at the exact same coordinates, and hence the
|
|
length of the inner line segment is set to 0. */
|
|
void SetFrom(const Sphere& s);
|
|
|
|
/// Sets this Capsule to a degenerate negative-volume state.
|
|
void SetDegenerate();
|
|
|
|
|
|
/// Quickly returns an arbitrary point inside this Capsule. Used in GJK intersection test.
|
|
[[nodiscard]] inline Vector3 AnyPointFast() const;
|
|
|
|
/// Generates a point that perhaps lies inside this capsule.
|
|
/** @param height A normalized value between [0,1]. This specifies the point position along the height line of this capsule.
|
|
@param x A normalized value between [0,1]. This specifies the x coordinate on the plane of the circle cross-section specified by l.
|
|
@param y A normalized value between [0,1]. This specifies the y coordinate on the plane of the circle cross-section specified by l.
|
|
@note This function will generate points uniformly, but they do not necessarily lie inside the capsule.
|
|
@see PointInside(). */
|
|
Vector3 UniformPointPerhapsInside(float height, float x, float y) const;
|
|
|
|
/// Returns the Sphere defining the 'bottom' section of this Capsule (corresponding to the endpoint l.a)
|
|
[[nodiscard]] Sphere SphereA() const;
|
|
|
|
/// Returns the Sphere defining the 'top' section of this Capsule (corresponding to the endpoint l.b)
|
|
[[nodiscard]] Sphere SphereB() const;
|
|
|
|
/// Computes the extreme point of this Capsule in the given direction.
|
|
/** An extreme point is a farthest point of this Capsule 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 The extreme point of this Capsule in the given direction. */
|
|
[[nodiscard]] Vector3 ExtremePoint(const Vector3 &direction) const;
|
|
Vector3 ExtremePoint(const Vector3 &direction, float &projectionDistance) const;
|
|
|
|
/// Tests if this Capsule is degenerate.
|
|
/** @return True if this Capsule does not span a strictly positive volume. */
|
|
[[nodiscard]] bool IsDegenerate() const;
|
|
|
|
/// Computes the total height of this capsule, i.e. LineLength() + Diameter().
|
|
/** <img src="CapsuleFunctions.png" />
|
|
@see LineLength(). */
|
|
[[nodiscard]] float Height() const;
|
|
|
|
/// Computes the distance of the two inner points of this capsule. @see Height.
|
|
[[nodiscard]] float LineLength() const;
|
|
/// Computes the diameter of this capsule.
|
|
[[nodiscard]] float Diameter() const;
|
|
/// Returns the bottom-most point of this Capsule.
|
|
/** <img src="CapsuleFunctions.png" />
|
|
@note The bottom-most point is only a naming convention, and does not correspond to the bottom-most point along any world axis. The returned
|
|
point is simply the point at the far end of this Capsule where the point l.a resides.
|
|
@note The bottom-most point of the capsule is different than the point l.a. The returned point is the point at the very far
|
|
edge of this capsule, and does not lie on the internal line. See the attached diagram.
|
|
@see Top(), l. */
|
|
[[nodiscard]] Vector3 Bottom() const;
|
|
/// Returns the center point of this Capsule.
|
|
/** <img src="doc/static/docs/CapsuleFunctions.png" />
|
|
@return The point (l.a + l.b) / 2. This point is the center of mass for this capsule.
|
|
@see l, Bottom(), Top(). */
|
|
|
|
[[nodiscard]] Vector3 Center() const;
|
|
[[nodiscard]] Vector3 Centroid() const; ///< [similarOverload: Center]
|
|
|
|
/// Returns the direction from the bottommost point towards the topmost point of this Capsule.
|
|
/** <img src="CapsuleFunctions.png" />
|
|
@return The normalized direction vector from l.a to l.b.
|
|
@see l. */
|
|
[[nodiscard]] Vector3 UpDirection() const;
|
|
|
|
/// Computes the volume of this Capsule.
|
|
/** @return pi * r^2 * |b-a| + 4 * pi * r^2 / 3.
|
|
@see SurfaceArea(). */
|
|
[[nodiscard]] float Volume() const;
|
|
|
|
/// Computes the surface area of this Capsule.
|
|
/** @return 2 * pi * r * |b-a| + 4 * pi * r^2.
|
|
@see Volume(). */
|
|
[[nodiscard]] float SurfaceArea() const;
|
|
|
|
/// Returns the cross-section circle at the given height of this Capsule.
|
|
/** <img src="CapsuleFunctions.png" />
|
|
@param l A normalized parameter between [0,1]. l == 0 returns a degenerate circle of radius 0 at the bottom of this Capsule, and l == 1
|
|
will return a degenerate circle of radius 0 at the top of this Capsule. */
|
|
Circle CrossSection(float l) const;
|
|
|
|
Vector3 ExtremePoint(const Vector3& direction);
|
|
|
|
/// Returns the smallest AABB that encloses this capsule.
|
|
/** @see MinimalEnclosingOBB(). */
|
|
[[nodiscard]] AABB MinimalEnclosingAABB() const;
|
|
|
|
/// Returns the smallest OBB that encloses this capsule.
|
|
/** @see MinimalEnclosingAABB(). */
|
|
OBB MinimalEnclosingOBB() const;
|
|
|
|
/// Projects this Capsule onto the given 1D axis direction vector.
|
|
/** This function collapses this Capsule onto an 1D axis for the purposes of e.g. separate axis test computations.
|
|
The function returns a 1D range [outMin, outMax] denoting the interval of the projection.
|
|
@param direction The 1D axis to project to. This vector may be unnormalized, in which case the output
|
|
of this function gets scaled by the length of this vector.
|
|
@param outMin [out] Returns the minimum extent of this object along the projection axis.
|
|
@param outMax [out] Returns the maximum extent of this object along the projection axis. */
|
|
void ProjectToAxis(const Vector3 &direction, float &outMin, float &outMax) const;
|
|
|
|
/// Returns the topmost point of this Capsule.
|
|
/** <img src="CapsuleFunctions.png" />
|
|
@note The topmost point is only a naming convention, and does not correspond to the topmost point along any world axis. The returned
|
|
point is simply the point at the far end of this Capsule where the point l.b resides.
|
|
@note The topmost point of the capsule is different than the point l.b. The returned point is the point at the very far
|
|
edge of this capsule, and does not lie on the internal line. See the attached diagram.
|
|
@see Bottom(), l. */
|
|
[[nodiscard]] Vector3 Top() const;
|
|
|
|
/// Applies a transformation to this capsule.
|
|
/** @param transform The transformation to apply to this capsule. This transformation must be
|
|
affine, and must contain an orthogonal set of column vectors (may not contain shear or projection).
|
|
The transformation can only contain uniform scale, and may not contain mirroring.
|
|
@see Translate(), Scale(), classes Matrix3x3, Matrix4x4, Quaternion. */
|
|
void Transform(const Matrix3x3 &transform);
|
|
void Transform(const Matrix4x4 &transform);
|
|
void Transform(const Quaternion &transform);
|
|
|
|
/// Computes the closest point inside this capsule to the given point.
|
|
/** If the target point lies inside this capsule, then that point is returned.
|
|
@see Distance(), Contains(), Intersects().
|
|
@todo Add ClosestPoint(Line/Ray/LineSegment/Plane/Triangle/Polygon/Circle/Disc/AABB/OBB/Sphere/Capsule/Frustum/Polyhedron). */
|
|
Vector3 ClosestPoint(const Vector3 &targetPoint) const;
|
|
|
|
|
|
/// Computes the distance between this capsule 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.
|
|
@todo Add Distance(Triangle/Polygon/Circle/Disc/Capsule).
|
|
@see Contains(), Intersects(), ClosestPoint(). */
|
|
float Distance(const Vector3 &point) const;
|
|
float Distance(const Plane &plane) const;
|
|
float Distance(const Sphere &sphere) const;
|
|
float Distance(const Ray &ray) const;
|
|
float Distance(const Line &line) const;
|
|
float Distance(const LineSegment &lineSegment) const;
|
|
float Distance(const Capsule &capsule) const;
|
|
|
|
/// Tests if the given object is fully contained inside this capsule.
|
|
/** This function returns true if the given object lies inside this capsule, and false otherwise.
|
|
@note The comparison is performed using less-or-equal, so the surface of this capsule count as being inside, but
|
|
due to float inaccuracies, this cannot generally be relied upon.
|
|
@todo Add Contains(Circle/Disc/Sphere/Capsule).
|
|
@see Distance(), Intersects(), ClosestPoint(). */
|
|
bool Contains(const Vector3 &point) const;
|
|
bool Contains(const LineSegment &lineSegment) const;
|
|
bool Contains(const Triangle &triangle) const;
|
|
bool Contains(const Polygon &polygon) const;
|
|
bool Contains(const AABB &aabb) const;
|
|
bool Contains(const OBB &obb) const;
|
|
bool Contains(const Frustum &frustum) const;
|
|
bool Contains(const Polyhedron &polyhedron) const;
|
|
|
|
bool Intersects(const Plane &plane) const;
|
|
bool Intersects(const Ray &ray) const;
|
|
bool Intersects(const Line &line) const;
|
|
bool Intersects(const LineSegment &lineSegment) const;
|
|
bool Intersects(const AABB &aabb) const;
|
|
bool Intersects(const OBB &obb) const;
|
|
bool Intersects(const Sphere &sphere) const;
|
|
bool Intersects(const Capsule &capsule) const;
|
|
bool Intersects(const Triangle &triangle) const;
|
|
bool Intersects(const Polygon &polygon) const;
|
|
bool Intersects(const Frustum &frustum) const;
|
|
bool Intersects(const Polyhedron &polyhedron) const;
|
|
|
|
Capsule Translated(const Vector3&) const;
|
|
};
|
|
} |