// // // 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& triangles, const std::vector& 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