Implement Polyhedron::Contains Intersects ContainsConvex ClosestPoint IsNull
This commit is contained in:
@@ -11,7 +11,7 @@ namespace J3ML::Geometry
|
||||
using namespace J3ML::LinearAlgebra;
|
||||
|
||||
// Represents a three-dimensional closed geometric solid defined by flat polygonal faces.
|
||||
class Polyhedron : public Shape
|
||||
class Polyhedron
|
||||
{
|
||||
public:
|
||||
// Stores a list of indices of a single face of a Polygon
|
||||
@@ -33,78 +33,101 @@ namespace J3ML::Geometry
|
||||
// Specifies the vertices of this polyhedron.
|
||||
std::vector<Vector3> v;
|
||||
std::vector<Face> f;
|
||||
public:
|
||||
/// The default constructor creates a null polyhedron.
|
||||
/** The null polyhedron has 0 vertices and 0 faces.
|
||||
@see IsNull(). */
|
||||
Polyhedron() = default;
|
||||
|
||||
int NumVertices() const {return (int)v.size();}
|
||||
int NumFaces() const { return (int)f.size();}
|
||||
AABB MinimalEnclosingAABB() const;
|
||||
[[nodiscard]] int NumVertices() const {return (int)v.size();}
|
||||
[[nodiscard]] int NumFaces() const { return (int)f.size();}
|
||||
[[nodiscard]] AABB MinimalEnclosingAABB() const;
|
||||
|
||||
Vector3 Vertex(int vertexIndex) const;
|
||||
[[nodiscard]] Vector3 Vertex(int vertexIndex) const;
|
||||
|
||||
[[nodiscard]] bool Contains(const Vector3&) const;
|
||||
[[nodiscard]] bool Contains(const LineSegment&) const;
|
||||
[[nodiscard]] bool Contains(const Triangle&) const;
|
||||
[[nodiscard]] bool Contains(const Polygon&) const;
|
||||
[[nodiscard]] bool Contains(const AABB&) const;
|
||||
[[nodiscard]] bool Contains(const OBB&) const;
|
||||
[[nodiscard]] bool Contains(const Frustum&) const;
|
||||
[[nodiscard]] bool Contains(const Polyhedron&) const;
|
||||
|
||||
[[nodiscard]] bool ContainsConvex(const Vector3&, float epsilon = 1e-4f) const;
|
||||
[[nodiscard]] bool ContainsConvex(const LineSegment&) const;
|
||||
[[nodiscard]] bool ContainsConvex(const Triangle&) const;
|
||||
|
||||
/// Tests whether this polyhedron and the given object intersect.
|
||||
/** Both objects are treated as "solid", meaning that if one of the objects is fully contained inside
|
||||
another, this function still returns true. (e.g. in case a line segment is contained inside this polyhedron,
|
||||
or this polyhedron is contained inside a sphere, etc.)
|
||||
@return True if an intersection occurs or one of the objects is contained inside the other, false otherwise.
|
||||
@note This function assumes that this polyhedron is closed and the edges are not self-intersecting.
|
||||
@see Contains(), ContainsConvex(), ClosestPoint(), ClosestPointConvex(), Distance(), IntersectsConvex().
|
||||
@todo Add Intersects(Circle/Disc). */
|
||||
[[nodiscard]] bool Intersects(const Line&) const;
|
||||
[[nodiscard]] bool Intersects(const LineSegment&) const;
|
||||
[[nodiscard]] bool Intersects(const Ray&) const;
|
||||
[[nodiscard]] bool Intersects(const Plane&) const;
|
||||
[[nodiscard]] bool Intersects(const Polyhedron&) const;
|
||||
[[nodiscard]] bool Intersects(const AABB& aabb) const;
|
||||
[[nodiscard]] bool Intersects(const OBB&) const;
|
||||
[[nodiscard]] bool Intersects(const Triangle&) const;
|
||||
[[nodiscard]] bool Intersects(const Polygon&) const;
|
||||
[[nodiscard]] bool Intersects(const Frustum&) const;
|
||||
[[nodiscard]] bool Intersects(const Sphere&) const;
|
||||
[[nodiscard]] bool Intersects(const Capsule& capsule) const;
|
||||
|
||||
[[nodiscard]] bool IsClosed() const;
|
||||
|
||||
[[nodiscard]] Plane FacePlane(int faceIndex) const;
|
||||
|
||||
[[nodiscard]] std::vector<Polygon> Faces() const;
|
||||
|
||||
[[nodiscard]] int NumEdges() const;
|
||||
|
||||
[[nodiscard]] LineSegment Edge(int edgeIndex) const;
|
||||
|
||||
[[nodiscard]] std::vector<std::pair<int, int>> EdgeIndices() const;
|
||||
|
||||
[[nodiscard]] std::vector<LineSegment> Edges() const;
|
||||
|
||||
[[nodiscard]] Polygon FacePolygon(int faceIndex) const;
|
||||
|
||||
[[nodiscard]] Vector3 FaceNormal(int faceIndex) const;
|
||||
|
||||
[[nodiscard]] bool IsConvex() const;
|
||||
|
||||
|
||||
/// Returns true if the Euler formula (V + F - E == 2) holds for this Polyhedron.
|
||||
/** The running time is O(E) ~ O(V).
|
||||
@see NumVertices(), NumEdges(), NumFaces(). */
|
||||
[[nodiscard]] bool EulerFormulaHolds() const;
|
||||
|
||||
bool Contains(const Vector3&) const;
|
||||
bool Contains(const LineSegment&) const;
|
||||
bool Contains(const Triangle&) const;
|
||||
bool Contains(const Polygon&) const;
|
||||
bool Contains(const AABB&) const;
|
||||
bool Contains(const OBB&) const;
|
||||
bool Contains(const Frustum&) const;
|
||||
bool Contains(const Polyhedron&) const;
|
||||
[[nodiscard]] Vector3 ApproximateConvexCentroid() const;
|
||||
|
||||
bool ContainsConvex(const Vector3&, float epsilon = 1e-4f) const;
|
||||
bool ContainsConvex(const LineSegment&) const;
|
||||
bool ContainsConvex(const Triangle&) const;
|
||||
[[nodiscard]] int ExtremeVertex(const Vector3 &direction) const;
|
||||
|
||||
bool Intersects(const Line&) const;
|
||||
bool Intersects(const LineSegment&) const;
|
||||
bool Intersects(const Ray&) const;
|
||||
bool Intersects(const Plane&) const;
|
||||
bool Intersects(const Polyhedron&) const;
|
||||
bool Intersects(const AABB&) const;
|
||||
bool Intersects(const OBB&) const;
|
||||
bool Intersects(const Triangle&) const;
|
||||
bool Intersects(const Polygon&) const;
|
||||
bool Intersects(const Frustum&) const;
|
||||
bool Intersects(const Sphere&) const;
|
||||
bool Intersects(const Capsule& capsule) const;
|
||||
|
||||
bool IsClosed() const;
|
||||
|
||||
Plane FacePlane(int faceIndex) const;
|
||||
|
||||
std::vector<Polygon> Faces() const;
|
||||
|
||||
int NumEdges() const;
|
||||
|
||||
LineSegment Edge(int edgeIndex) const;
|
||||
|
||||
std::vector<std::pair<int, int>> EdgeIndices() const;
|
||||
|
||||
std::vector<LineSegment> Edges() const;
|
||||
|
||||
Polygon FacePolygon(int faceIndex) const;
|
||||
|
||||
Vector3 FaceNormal(int faceIndex) const;
|
||||
|
||||
bool IsConvex() const;
|
||||
|
||||
Vector3 ApproximateConvexCentroid() const;
|
||||
|
||||
int ExtremeVertex(const Vector3 &direction) const;
|
||||
|
||||
Vector3 ExtremePoint(const Vector3 &direction) const;
|
||||
[[nodiscard]] Vector3 ExtremePoint(const Vector3 &direction) const;
|
||||
|
||||
/// Tests if the given face of this Polyhedron contains the given point.
|
||||
bool FaceContains(int faceIndex, const Vector3 &worldSpacePoint, float polygonThickness = 1e-3f) const;
|
||||
[[nodiscard]] bool FaceContains(int faceIndex, const Vector3 &worldSpacePoint, float polygonThickness = 1e-3f) const;
|
||||
|
||||
/// A helper for Contains() and FaceContains() tests: Returns a positive value if the given point is contained in the given face,
|
||||
/// and a negative value if the given point is outside the face. The magnitude of the return value reports a pseudo-distance
|
||||
/// from the point to the nearest edge of the face polygon. This is used as a robustness/stability criterion to estimate how
|
||||
/// numerically believable the result is.
|
||||
float FaceContainmentDistance2D(int faceIndex, const Vector3 &worldSpacePoint, float polygonThickness = 1e-5f) const;
|
||||
[[nodiscard]] float FaceContainmentDistance2D(int faceIndex, const Vector3 &worldSpacePoint, float polygonThickness = 1e-5f) const;
|
||||
void ProjectToAxis(const Vector3 &direction, float &outMin, float &outMax) const;
|
||||
|
||||
Vector3 ClosestPoint(const LineSegment& lineSegment, Vector3 *lineSegmentPt) const;
|
||||
|
||||
[[nodiscard]] Vector3 ClosestPoint(const Vector3& point) const;
|
||||
|
||||
/// Returns true if this polyhedron has 0 vertices and 0 faces.
|
||||
bool IsNull() const { return v.empty() && f.empty(); }
|
||||
|
||||
protected:
|
||||
private:
|
||||
};
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#include <J3ML/Geometry/Polyhedron.h>
|
||||
#include <J3ML/Geometry/AABB.h>
|
||||
#include <J3ML/Geometry/AABB.hpp>
|
||||
#include <J3ML/Geometry/Triangle.h>
|
||||
#include <J3ML/Geometry/LineSegment.h>
|
||||
#include "J3ML/Geometry/Ray.h"
|
||||
@@ -508,6 +508,8 @@ namespace J3ML::Geometry
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Polyhedron::EulerFormulaHolds() const { return NumVertices() + NumFaces() - NumEdges() == 2;}
|
||||
|
||||
bool Polyhedron::ContainsConvex(const Vector3 &point, float epsilon) const
|
||||
{
|
||||
assert(IsConvex());
|
||||
@@ -638,6 +640,64 @@ namespace J3ML::Geometry
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool PolyhedronIntersectsAABB_OBB(const Polyhedron& p, const T& obj) {
|
||||
if (p.Contains(obj.CenterPoint()))
|
||||
return true;
|
||||
if (obj.Contains(p.ApproximateConvexCentroid())) // @bug: This is not correct for concave polyhedrons!
|
||||
return true;
|
||||
|
||||
// Test for each edge of the AABB / OBB whether this polyhedron intersects it.
|
||||
for(int i = 0; i < obj.NumEdges(); ++i)
|
||||
if (p.Intersects(obj.Edge(i)))
|
||||
return true;
|
||||
|
||||
// Test for each edge of this polyhedron whether the AABB / OBB intersects it.
|
||||
for(size_t i = 0; i < p.f.size(); ++i)
|
||||
{
|
||||
assert(!p.f[i].v.empty()); // Cannot have degenerate faces here, and for performance reasons, don't start checking for this condition in release mode!
|
||||
int v0 = p.f[i].v.back();
|
||||
Vector3 l0 = p.v[v0];
|
||||
for(size_t j = 0; j < p.f[i].v.size(); ++j)
|
||||
{
|
||||
int v1 = p.f[i].v[j];
|
||||
Vector3 l1 = p.v[v1];
|
||||
if (v0 < v1 && obj.Intersects(LineSegment(l0, l1))) // If v0 < v1, then this line segment is the canonical one.
|
||||
return true;
|
||||
l0 = l1;
|
||||
v0 = v1;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
bool Polyhedron::Intersects(const AABB &aabb) const {
|
||||
return PolyhedronIntersectsAABB_OBB(*this, aabb);
|
||||
}
|
||||
|
||||
bool Polyhedron::Intersects(const OBB& obb) const {
|
||||
return PolyhedronIntersectsAABB_OBB(*this, obb);
|
||||
}
|
||||
|
||||
bool Polyhedron::Intersects(const Frustum& obb) const {
|
||||
return PolyhedronIntersectsAABB_OBB(*this, obb);
|
||||
}
|
||||
|
||||
bool Polyhedron::Intersects(const Triangle& obb) const {
|
||||
return PolyhedronIntersectsAABB_OBB(*this, obb);
|
||||
}
|
||||
|
||||
bool Polyhedron::Intersects(const Sphere& sphere) const {
|
||||
Vector3 closestPt = ClosestPoint(sphere.Position);
|
||||
return closestPt.DistanceSq(sphere.Position) <= sphere.Radius * sphere.Radius;
|
||||
}
|
||||
|
||||
bool Polyhedron::Intersects(const Polygon& polygon) const {
|
||||
return Intersects(polygon.ToPolyhedron());
|
||||
}
|
||||
|
||||
bool Polyhedron::Intersects(const Capsule &capsule) const {
|
||||
Vector3 pt, ptOnLineSegment;
|
||||
pt = ClosestPoint(capsule.l, &ptOnLineSegment);
|
||||
@@ -677,6 +737,22 @@ namespace J3ML::Geometry
|
||||
return closestPt;
|
||||
}
|
||||
|
||||
Vector3 Polyhedron::ClosestPoint(const Vector3 &point) const {
|
||||
if (Contains(point))
|
||||
return point;
|
||||
|
||||
Vector3 closestPoint = Vector3::NaN;
|
||||
float closestDistance = Math::Infinity;
|
||||
|
||||
for (int i = 0; i < NumFaces(); ++i) {
|
||||
Vector3 closestOnPoly = FacePolygon(i).ClosestPoint(point);
|
||||
float d = closestOnPoly.DistanceSq(point);
|
||||
if (d < closestDistance) {
|
||||
closestPoint = closestOnPoly;
|
||||
closestDistance = d;
|
||||
}
|
||||
}
|
||||
return closestPoint;
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user