221 lines
9.0 KiB
C
221 lines
9.0 KiB
C
|
//
|
||
|
//
|
||
|
// Tyson Brochu 2011
|
||
|
//
|
||
|
|
||
|
#ifndef TUNICATE_ROOTPARITYCOLLISIONTEST_H
|
||
|
#define TUNICATE_ROOTPARITYCOLLISIONTEST_H
|
||
|
|
||
|
#include "vec.h"
|
||
|
#include "interval.h"
|
||
|
#include "expansion.h"
|
||
|
namespace CCD
|
||
|
{
|
||
|
namespace rootparity
|
||
|
{
|
||
|
|
||
|
typedef Vec<3,IntervalType> Vec3Interval;
|
||
|
typedef Vec<2,expansion> Vec2e;
|
||
|
typedef Vec<3,expansion> Vec3e;
|
||
|
typedef Vec<3,bool> Vec3b;
|
||
|
typedef Vec<4,bool> Vec4b;
|
||
|
|
||
|
/// --------------------------------------------------------
|
||
|
///
|
||
|
/// class RootParityCollisionTest: Encapsulates functions for continuous collision detection using the "root-parity" approach.
|
||
|
///
|
||
|
/// Terms used in documentation:
|
||
|
/// "Domain": The unit cube for edge-edge collision testing, and half the unit cube for point-triangle.
|
||
|
/// "Domain boundary vertices": Vertices of the unit cube or half-cube.
|
||
|
/// "Mapped domain boundary vertices": The set of points F(X), where X = the set of domain boundary vertices, F is either the
|
||
|
/// edge-edge collision function or the point-triangle collision function (i.e. F is zero where there is a collision).
|
||
|
///
|
||
|
/// --------------------------------------------------------
|
||
|
|
||
|
class RootParityCollisionTest
|
||
|
{
|
||
|
|
||
|
public:
|
||
|
|
||
|
/// Constructor, take a reference to the input vertex locations at t=0 and t=1. User also specifies whether the vertices
|
||
|
/// should be interpreted as representing an edge-edge collision test, or point-triangle.
|
||
|
///
|
||
|
inline RootParityCollisionTest(const Vec3d &x0old, const Vec3d &x1old, const Vec3d &x2old, const Vec3d &x3old,
|
||
|
const Vec3d &x0new, const Vec3d &x1new, const Vec3d &x2new, const Vec3d &x3new,
|
||
|
bool is_edge_edge );
|
||
|
|
||
|
/// Returns true if there is an odd number of ray intersections (corresponding to an odd number of roots of F in the domain).
|
||
|
///
|
||
|
inline bool run_test();
|
||
|
|
||
|
/// Run edge-edge continuous collision detection
|
||
|
///
|
||
|
bool edge_edge_collision();
|
||
|
|
||
|
/// Run point-triangle continuous collision detection
|
||
|
///
|
||
|
bool point_triangle_collision();
|
||
|
|
||
|
|
||
|
private:
|
||
|
|
||
|
/// Input vertex locations.
|
||
|
/// If point-triangle collision test, the point is vertex 0, and the triangle is vertices (1,2,3).
|
||
|
/// If edge-edge collision test, the edges are (0,1) and (2,3).
|
||
|
///
|
||
|
const Vec3d& m_x0old, m_x1old, m_x2old, m_x3old, m_x0new, m_x1new, m_x2new, m_x3new;
|
||
|
|
||
|
/// Whether this is an edge-edge collision test
|
||
|
///
|
||
|
const bool m_is_edge_edge;
|
||
|
|
||
|
/// The root-parity test uses a ray from the origin. We will actually use a finite line segment with one end point at the
|
||
|
/// origin, and the other end point equal to this variable, "ray". In the code, we will ensure that ray has magnitude
|
||
|
/// greater than the largest magnitude point in the object being tested.
|
||
|
///
|
||
|
Vec3d m_ray;
|
||
|
|
||
|
/// The mapped domain boundary vertices, computed in interval arithmetic.
|
||
|
///
|
||
|
Vec3Interval m_interval_hex_vertices[8];
|
||
|
|
||
|
/// The mapped domain boundary vertices, computed in fp-expansion arithmetic. We compute these only as needed, so for each
|
||
|
/// vertex, we track if it has been computed yet.
|
||
|
///
|
||
|
Vec3e m_expansion_hex_vertices[8];
|
||
|
|
||
|
/// Whether or not the mapping of each domain boundary vertex has been computed using floating-point expansions.
|
||
|
///
|
||
|
bool m_expansion_hex_vertices_computed[8];
|
||
|
|
||
|
//
|
||
|
// Functions
|
||
|
//
|
||
|
|
||
|
/// Determine if the given point is inside the tetrahedron given by tet_indices
|
||
|
///
|
||
|
bool point_tetrahedron_intersection( const Vec4ui& tet_indices, const Vec4b& ts, const Vec4b& us, const Vec4b& vs, const Vec3d& d_x );
|
||
|
|
||
|
/// Determine if the given segment intersects the triangle
|
||
|
///
|
||
|
bool edge_triangle_intersection(const Vec3ui& triangle,
|
||
|
const Vec3b& ts, const Vec3b& us, const Vec3b& vs,
|
||
|
const Vec3d& d_s0, const Vec3d& d_s1,
|
||
|
double* alphas );
|
||
|
|
||
|
/// Compute the sign of the implicit surface function which is zero on the bilinear patch defined by quad.
|
||
|
///
|
||
|
int implicit_surface_function_sign( const Vec4ui& quad, const Vec4b& ts, const Vec4b& us, const Vec4b& vs, const Vec3d& d_x );
|
||
|
|
||
|
/// Test the ray against the bilinear patch defined by a quad to determine whether there is an even or odd number of
|
||
|
/// intersections. Returns true if odd.
|
||
|
///
|
||
|
bool ray_quad_intersection_parity(const Vec4ui& quad,
|
||
|
const Vec4b& ts,
|
||
|
const Vec4b& us,
|
||
|
const Vec4b& vs,
|
||
|
const Vec3d& ray_origin,
|
||
|
const Vec3d& ray_direction,
|
||
|
bool& edge_hit,
|
||
|
bool& origin_on_surface );
|
||
|
|
||
|
|
||
|
/// Determine the parity of the number of intersections between a ray from the origin and the generalized prism made up
|
||
|
/// of f(G) where G = the vertices of the domain boundary.
|
||
|
///
|
||
|
bool ray_prism_parity_test();
|
||
|
|
||
|
/// Determine the parity of the number of intersections between a ray from the origin and the generalized hexahedron made
|
||
|
/// up of f(G) where G = the vertices of the domain boundary (corners of the unit cube).
|
||
|
///
|
||
|
bool ray_hex_parity_test();
|
||
|
|
||
|
/// For each triangle, form the plane it lies on, and determine if all interval_hex_vertices are on one side of the plane.
|
||
|
///
|
||
|
bool plane_culling( const std::vector<Vec3ui>& triangles, const std::vector<Vec3d>& boundary_vertices );
|
||
|
|
||
|
/// Take a set of planes defined by the mapped domain boundary, and determine if all interval_hex_vertices on one side of
|
||
|
/// any plane.
|
||
|
///
|
||
|
bool edge_edge_interval_plane_culling();
|
||
|
|
||
|
/// Take a set of planes defined by the mapped domain boundary, and determine if all interval_hex_vertices on one side of
|
||
|
/// any plane.
|
||
|
///
|
||
|
bool point_triangle_interval_plane_culling();
|
||
|
|
||
|
/// Take a fixed set of planes and determine if all interval_hex_vertices on one side of any plane.
|
||
|
///
|
||
|
bool fixed_plane_culling( unsigned int num_hex_vertices );
|
||
|
|
||
|
};
|
||
|
|
||
|
/// --------------------------------------------------------
|
||
|
///
|
||
|
/// Determine if the given AABB contains the origin.
|
||
|
///
|
||
|
/// --------------------------------------------------------
|
||
|
|
||
|
inline bool aabb_contains_origin( const Vec3d& xmin, const Vec3d& xmax )
|
||
|
{
|
||
|
return (xmin[0] <= 0 && xmin[1] <= 0 && xmin[2] <= 0) && (xmax[0] >= 0 && xmax[1] >= 0 && xmax[2] >= 0 );
|
||
|
}
|
||
|
|
||
|
/// --------------------------------------------------------
|
||
|
///
|
||
|
/// Determine if the given AABBs intersect each other.
|
||
|
///
|
||
|
/// --------------------------------------------------------
|
||
|
|
||
|
inline bool aabb_test( const Vec3d& xmin, const Vec3d& xmax, const Vec3d& oxmin, const Vec3d& oxmax )
|
||
|
{
|
||
|
return ((xmin[0] <= oxmax[0] && xmin[1] <= oxmax[1] && xmin[2] <= oxmax[2]) &&
|
||
|
(xmax[0] >= oxmin[0] && xmax[1] >= oxmin[1] && xmax[2] >= oxmin[2]) );
|
||
|
|
||
|
}
|
||
|
|
||
|
/// --------------------------------------------------------
|
||
|
///
|
||
|
/// RootParityCollisionTest constructor.
|
||
|
///
|
||
|
/// --------------------------------------------------------
|
||
|
|
||
|
inline RootParityCollisionTest::RootParityCollisionTest(const Vec3d &_x0old, const Vec3d &_x1old, const Vec3d &_x2old, const Vec3d &_x3old,
|
||
|
const Vec3d &_x0new, const Vec3d &_x1new, const Vec3d &_x2new, const Vec3d &_x3new,
|
||
|
bool _is_edge_edge ) :
|
||
|
m_x0old( _x0old ), m_x1old( _x1old ), m_x2old( _x2old ), m_x3old( _x3old ),
|
||
|
m_x0new( _x0new ), m_x1new( _x1new ), m_x2new( _x2new ), m_x3new( _x3new ),
|
||
|
m_is_edge_edge( _is_edge_edge ),
|
||
|
m_ray()
|
||
|
{
|
||
|
for ( unsigned int i = 0; i < 8; ++i )
|
||
|
{
|
||
|
m_expansion_hex_vertices_computed[i] = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// --------------------------------------------------------
|
||
|
///
|
||
|
/// Run the appropriate continuous collision detection test.
|
||
|
///
|
||
|
/// --------------------------------------------------------
|
||
|
|
||
|
inline bool RootParityCollisionTest::run_test()
|
||
|
{
|
||
|
if ( m_is_edge_edge )
|
||
|
{
|
||
|
return edge_edge_collision();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return point_triangle_collision();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
} // namespace rootparity
|
||
|
}
|
||
|
#endif
|