#include "rootparitycollisiontest.h" #include namespace CCD { namespace rootparity { namespace // unnamed namespace for local functions { /// /// Local helper functions /// template inline void make_vector( const Vec& in, Vec& out ); template void point_triangle_collision_function(const Vec3d &d_x0, const Vec3d &d_x1, const Vec3d &d_x2, const Vec3d &d_x3, const Vec3d &d_x0new, const Vec3d &d_x1new, const Vec3d &d_x2new, const Vec3d &d_x3new, bool d_t, bool d_u, bool d_v, Vec<3,T>& out ); template void edge_edge_collision_function(const Vec3d &d_x0, const Vec3d &d_x1, const Vec3d &d_x2, const Vec3d &d_x3, const Vec3d &d_x0new, const Vec3d &d_x1new, const Vec3d &d_x2new, const Vec3d &d_x3new, bool d_t, bool d_u, bool d_v, Vec<3,T>& out ); template void get_quad_vertices(const Vec3d &d_x0old, const Vec3d &d_x1old, const Vec3d &d_x2old, const Vec3d &d_x3old, const Vec3d &d_x0new, const Vec3d &d_x1new, const Vec3d &d_x2new, const Vec3d &d_x3new, bool is_edge_edge, const Vec4b& ts, const Vec4b& us, const Vec4b& vs, Vec<3,T>& q0, Vec<3,T>& q1, Vec<3,T>& q2, Vec<3,T>& q3 ); template void get_triangle_vertices(const Vec3d &d_x0old, const Vec3d &d_x1old, const Vec3d &d_x2old, const Vec3d &d_x3old, const Vec3d &d_x0new, const Vec3d &d_x1new, const Vec3d &d_x2new, const Vec3d &d_x3new, bool is_edge_edge, const Vec3b& ts, const Vec3b& us, const Vec3b& vs, Vec<3,T>& q0, Vec<3,T>& q1, Vec<3,T>& q2 ); template static T orientation2d(const Vec<2,T>& x0, const Vec<2,T>& x1, const Vec<2,T>& x2); template T orientation3d(const Vec<3,T>& x0, const Vec<3,T>& x1, const Vec<3,T>& x2, const Vec<3,T>& x3); int expansion_simplex_intersection1d(int k, const expansion& x0, const expansion& x1, const expansion& x2, double* out_alpha0, double* out_alpha1, double* out_alpha2); int expansion_simplex_intersection2d(int k, const Vec2e& x0, const Vec2e& x1, const Vec2e& x2, double* out_alpha0, double* out_alpha1, double* out_alpha2 ); int expansion_simplex_intersection2d(int k, const Vec2e& x0, const Vec2e& x1, const Vec2e& x2, const Vec2e& x3, double* out_alpha0, double* out_alpha1, double* out_alpha2, double* out_alpha3); bool expansion_simplex_intersection3d(int k, const Vec3e& x0, const Vec3e& x1, const Vec3e& x2, const Vec3e& x3, double* alpha0, double* alpha1, double* alpha2, double* alpha3); int degenerate_point_tetrahedron_intersection(const Vec3e& x0, const Vec3e& x1, const Vec3e& x2, const Vec3e& x3, const Vec3e& x4, double* alpha0, double* alpha1, double* alpha2, double* alpha3, double* alpha4); int degenerate_point_tetrahedron_intersection(const Vec3Interval& x0, const Vec3Interval& x1, const Vec3Interval& x2, const Vec3Interval& x3, const Vec3Interval& x4, double* out_alpha0, double* out_alpha1, double* out_alpha2, double* out_alpha3, double* out_alpha4); template int point_tetrahedron_intersection(const Vec<3,T>& x0, const Vec<3,T>& x1, const Vec<3,T>& x2, const Vec<3,T>& x3, const Vec<3,T>& x4, double* out_alpha0, double* out_alpha1, double* out_alpha2, double* out_alpha3, double* out_alpha4 ); int degenerate_edge_triangle_intersection(const Vec3e& x0, const Vec3e& x1, const Vec3e& x2, const Vec3e& x3, const Vec3e& x4, double* alpha0, double* alpha1, double* alpha2, double* alpha3, double* alpha4); int degenerate_edge_triangle_intersection(const Vec3Interval& x0, const Vec3Interval& x1, const Vec3Interval& x2, const Vec3Interval& x3, const Vec3Interval& x4, double* out_alpha0, double* out_alpha1, double* out_alpha2, double* out_alpha3, double* out_alpha4); template int edge_triangle_intersection(const Vec<3,T>& x0, const Vec<3,T>& x1, const Vec<3,T>& x2, const Vec<3,T>& x3, const Vec<3,T>& x4, double* out_alpha0, double* out_alpha1, double* out_alpha2, double* out_alpha3, double* out_alpha4 ); bool edge_triangle_intersection(const Vec3d &d_x0old, const Vec3d &d_x1old, const Vec3d &d_x2old, const Vec3d &d_x3old, const Vec3d &d_x0new, const Vec3d &d_x1new, const Vec3d &d_x2new, const Vec3d &d_x3new, bool is_edge_edge, const Vec3b& ts, const Vec3b& us, const Vec3b& vs, const Vec3d& d_s0, const Vec3d& d_s1, double* alphas ); template T plane_dist( const Vec<3,T>& x, const Vec<3,T>& q, const Vec<3,T>& r, const Vec<3,T>& p ); template void implicit_surface_function( const Vec<3,T>& x, const Vec<3,T>& q0, const Vec<3,T>& q1, const Vec<3,T>& q2, const Vec<3,T>& q3, T& out ); bool test_with_triangles(const Vec3d &d_x0old, const Vec3d &d_x1old, const Vec3d &d_x2old, const Vec3d &d_x3old, const Vec3d &d_x0new, const Vec3d &d_x1new, const Vec3d &d_x2new, const Vec3d &d_x3new, bool is_edge_edge, const Vec4b& ts, const Vec4b& us, const Vec4b& vs, const Vec3d& s0, const Vec3d& s1, bool use_positive_triangles, bool& edge_hit ); // // Local function definitions // // -------------------------------------------------------- template inline void make_vector( const Vec& in, Vec& out ) { for ( unsigned int i = 0; i < N; ++i ) { create_from_double( in[i], out[i] ); } } // -------------------------------------------------------- template inline void edge_edge_collision_function(const Vec3d &d_x0, const Vec3d &d_x1, const Vec3d &d_x2, const Vec3d &d_x3, const Vec3d &d_x0new, const Vec3d &d_x1new, const Vec3d &d_x2new, const Vec3d &d_x3new, bool b_t, bool b_u, bool b_v, Vec<3,T>& out ) { Vec<3,T> x0, x1, x2, x3; make_vector( d_x0, x0 ); make_vector( d_x1, x1 ); make_vector( d_x2, x2 ); make_vector( d_x3, x3 ); out = x0; out -= x2; if ( b_t ) { Vec<3,T> x0new, x1new, x2new, x3new; make_vector( d_x0new, x0new ); make_vector( d_x1new, x1new ); make_vector( d_x2new, x2new ); make_vector( d_x3new, x3new ); out += x0new; out -= x0; out -= x2new; out += x2; if ( b_u ) { out += x0; out -= x0new; out += x1new; out -= x1; } if ( b_v ) { out += x2new; out -= x2; out -= x3new; out += x3; } } if ( b_u ) { out += x1; out -= x0; } if ( b_v ) { out += x2; out -= x3; } } /// -------------------------------------------------------- inline void add( Vec3d& a, const Vec3d& b ) { a[0] += b[0]; a[1] += b[1]; a[2] += b[2]; } /// -------------------------------------------------------- inline void sub( Vec3d& a, const Vec3d& b ) { a[0] -= b[0]; a[1] -= b[1]; a[2] -= b[2]; } // -------------------------------------------------------- inline void edge_edge_collision_function(const Vec3d &d_x0, const Vec3d &d_x1, const Vec3d &d_x2, const Vec3d &d_x3, const Vec3d &d_x0new, const Vec3d &d_x1new, const Vec3d &d_x2new, const Vec3d &d_x3new, bool b_t, bool b_u, bool b_v, Vec<3,IntervalType>& out ) { Vec3d out_lower( -d_x0[0], -d_x0[1], -d_x0[2] ); add( out_lower, d_x2 ); Vec3d out_upper( d_x0[0], d_x0[1], d_x0[2] ); sub( out_upper, d_x2 ); if ( b_t ) { sub( out_lower, d_x0new ); add( out_lower, d_x0 ); add( out_lower, d_x2new ); sub( out_lower, d_x2 ); add( out_upper, d_x0new ); sub( out_upper, d_x0 ); sub( out_upper, d_x2new ); add( out_upper, d_x2 ); if ( b_u ) { sub( out_lower, d_x0 ); add( out_lower, d_x0new ); sub( out_lower, d_x1new ); add( out_lower, d_x1 ); add( out_upper, d_x0 ); sub( out_upper, d_x0new ); add( out_upper, d_x1new ); sub( out_upper, d_x1 ); } if ( b_v ) { sub( out_lower, d_x2new ); add( out_lower, d_x2 ); add( out_lower, d_x3new ); sub( out_lower, d_x3 ); add( out_upper, d_x2new ); sub( out_upper, d_x2 ); sub( out_upper, d_x3new ); add( out_upper, d_x3 ); } } if ( b_u ) { sub( out_lower, d_x1 ); add( out_lower, d_x0 ); add( out_upper, d_x1 ); sub( out_upper, d_x0 ); } if ( b_v ) { sub( out_lower, d_x2 ); add( out_lower, d_x3 ); add( out_upper, d_x2 ); sub( out_upper, d_x3 ); } out[0].v[0] = out_lower[0]; out[1].v[0] = out_lower[1]; out[2].v[0] = out_lower[2]; out[0].v[1] = out_upper[0]; out[1].v[1] = out_upper[1]; out[2].v[1] = out_upper[2]; } /// -------------------------------------------------------- template void point_triangle_collision_function(const Vec3d &d_x0, const Vec3d &d_x1, const Vec3d &d_x2, const Vec3d &d_x3, const Vec3d &d_x0new, const Vec3d &d_x1new, const Vec3d &d_x2new, const Vec3d &d_x3new, bool b_t, bool b_u, bool b_v, Vec<3,T>& out ) { Vec<3,T> x0, x1, x2, x3; make_vector( d_x0, x0 ); make_vector( d_x1, x1 ); make_vector( d_x2, x2 ); make_vector( d_x3, x3 ); out = x0; out -= x1; if ( b_t ) { Vec<3,T> x0new, x1new, x2new, x3new; make_vector( d_x0new, x0new ); make_vector( d_x1new, x1new ); make_vector( d_x2new, x2new ); make_vector( d_x3new, x3new ); out += x0new; out -= x0; out -= x1new; out += x1; if ( b_u ) { out += x1new; out -= x1; out -= x2new; out += x2; } if ( b_v ) { out += x1new; out -= x1; out -= x3new; out += x3; } } if ( b_u ) { out += x1; out -= x2; } if ( b_v ) { out += x1; out -= x3; } } /// -------------------------------------------------------- void point_triangle_collision_function(const Vec3d &d_x0, const Vec3d &d_x1, const Vec3d &d_x2, const Vec3d &d_x3, const Vec3d &d_x0new, const Vec3d &d_x1new, const Vec3d &d_x2new, const Vec3d &d_x3new, bool b_t, bool b_u, bool b_v, Vec<3,IntervalType>& out ) { Vec3d out_lower( -d_x0[0], -d_x0[1], -d_x0[2] ); Vec3d out_upper( d_x0[0], d_x0[1], d_x0[2] ); add( out_lower, d_x1 ); sub( out_upper, d_x1 ); if ( b_t ) { sub( out_lower, d_x0new ); add( out_lower, d_x0 ); add( out_lower, d_x1new ); sub( out_lower, d_x1 ); add( out_upper, d_x0new ); sub( out_upper, d_x0 ); sub( out_upper, d_x1new ); add( out_upper, d_x1 ); if ( b_u ) { sub( out_lower, d_x1new ); add( out_lower, d_x1 ); add( out_lower, d_x2new ); sub( out_lower, d_x2 ); add( out_upper, d_x1new ); sub( out_upper, d_x1 ); sub( out_upper, d_x2new ); add( out_upper, d_x2 ); } if ( b_v ) { sub( out_lower, d_x1new ); add( out_lower, d_x1 ); add( out_lower, d_x3new ); sub( out_lower, d_x3 ); add( out_upper, d_x1new ); sub( out_upper, d_x1 ); sub( out_upper, d_x3new ); add( out_upper, d_x3 ); } } if ( b_u ) { sub( out_lower, d_x1 ); add( out_lower, d_x2 ); add( out_upper, d_x1 ); sub( out_upper, d_x2 ); } if ( b_v ) { sub( out_lower, d_x1 ); add( out_lower, d_x3 ); add( out_upper, d_x1 ); sub( out_upper, d_x3 ); } out[0].v[0] = out_lower[0]; out[1].v[0] = out_lower[1]; out[2].v[0] = out_lower[2]; out[0].v[1] = out_upper[0]; out[1].v[1] = out_upper[1]; out[2].v[1] = out_upper[2]; } // -------------------------------------------------------- template void get_quad_vertices(const Vec3d &d_x0old, const Vec3d &d_x1old, const Vec3d &d_x2old, const Vec3d &d_x3old, const Vec3d &d_x0new, const Vec3d &d_x1new, const Vec3d &d_x2new, const Vec3d &d_x3new, bool is_edge_edge, const Vec4b& ts, const Vec4b& us, const Vec4b& vs, Vec<3,T>& q0, Vec<3,T>& q1, Vec<3,T>& q2, Vec<3,T>& q3 ) { T::begin_special_arithmetic(); if ( is_edge_edge ) { edge_edge_collision_function( d_x0old, d_x1old, d_x2old, d_x3old, d_x0new, d_x1new, d_x2new, d_x3new, ts[0], us[0], vs[0], q0 ); edge_edge_collision_function( d_x0old, d_x1old, d_x2old, d_x3old, d_x0new, d_x1new, d_x2new, d_x3new, ts[1], us[1], vs[1], q1 ); edge_edge_collision_function( d_x0old, d_x1old, d_x2old, d_x3old, d_x0new, d_x1new, d_x2new, d_x3new, ts[2], us[2], vs[2], q2 ); edge_edge_collision_function( d_x0old, d_x1old, d_x2old, d_x3old, d_x0new, d_x1new, d_x2new, d_x3new, ts[3], us[3], vs[3], q3 ); } else { point_triangle_collision_function( d_x0old, d_x1old, d_x2old, d_x3old, d_x0new, d_x1new, d_x2new, d_x3new, ts[0], us[0], vs[0], q0 ); point_triangle_collision_function( d_x0old, d_x1old, d_x2old, d_x3old, d_x0new, d_x1new, d_x2new, d_x3new, ts[1], us[1], vs[1], q1 ); point_triangle_collision_function( d_x0old, d_x1old, d_x2old, d_x3old, d_x0new, d_x1new, d_x2new, d_x3new, ts[2], us[2], vs[2], q2 ); point_triangle_collision_function( d_x0old, d_x1old, d_x2old, d_x3old, d_x0new, d_x1new, d_x2new, d_x3new, ts[3], us[3], vs[3], q3 ); } T::end_special_arithmetic(); } // -------------------------------------------------------- template void get_triangle_vertices(const Vec3d &d_x0old, const Vec3d &d_x1old, const Vec3d &d_x2old, const Vec3d &d_x3old, const Vec3d &d_x0new, const Vec3d &d_x1new, const Vec3d &d_x2new, const Vec3d &d_x3new, bool is_edge_edge, const Vec3b& ts, const Vec3b& us, const Vec3b& vs, Vec<3,T>& q0, Vec<3,T>& q1, Vec<3,T>& q2 ) { T::begin_special_arithmetic(); if ( is_edge_edge ) { edge_edge_collision_function( d_x0old, d_x1old, d_x2old, d_x3old, d_x0new, d_x1new, d_x2new, d_x3new, ts[0], us[0], vs[0], q0 ); edge_edge_collision_function( d_x0old, d_x1old, d_x2old, d_x3old, d_x0new, d_x1new, d_x2new, d_x3new, ts[1], us[1], vs[1], q1 ); edge_edge_collision_function( d_x0old, d_x1old, d_x2old, d_x3old, d_x0new, d_x1new, d_x2new, d_x3new, ts[2], us[2], vs[2], q2 ); } else { point_triangle_collision_function( d_x0old, d_x1old, d_x2old, d_x3old, d_x0new, d_x1new, d_x2new, d_x3new, ts[0], us[0], vs[0], q0 ); point_triangle_collision_function( d_x0old, d_x1old, d_x2old, d_x3old, d_x0new, d_x1new, d_x2new, d_x3new, ts[1], us[1], vs[1], q1 ); point_triangle_collision_function( d_x0old, d_x1old, d_x2old, d_x3old, d_x0new, d_x1new, d_x2new, d_x3new, ts[2], us[2], vs[2], q2 ); } T::end_special_arithmetic(); } // ---------------------------------------- template static T orientation2d(const Vec<2,T>& x0, const Vec<2,T>& x1, const Vec<2,T>& x2) { return x0[0]*x1[1] + -(x0[0])*x2[1] + x1[0]*x2[1] + -(x1[0])*x0[1] + x2[0]*x0[1] + -(x2[0])*x1[1]; } // ---------------------------------------- inline expansion orientation2d(const Vec<2,expansion>& x0, const Vec<2,expansion>& x1, const Vec<2,expansion>& x2) { expansion prod; expansion result; multiply( x0[0], x1[1], prod ); add( result, prod, result ); multiply( x0[0], x2[1], prod ); subtract( result, prod, result ); multiply( x1[0], x2[1], prod ); add( result, prod, result ); multiply( x1[0], x0[1], prod ); subtract( result, prod, result ); multiply( x2[0], x0[1], prod ); add( result, prod, result ); multiply( x2[0], x1[1], prod ); subtract( result, prod, result ); return result; } // -------------------------------------------------------- template void orientation3d(const Vec<3,T>& x0, const Vec<3,T>& x1, const Vec<3,T>& x2, const Vec<3,T>& x3, T& result ) { // avoid recomputing common factors T x00x11 = x0[0] * x1[1]; T x00x21 = x0[0] * x2[1]; T x00x31 = x0[0] * x3[1]; T x10x01 = x1[0] * x0[1]; T x10x21 = x1[0] * x2[1]; T x10x31 = x1[0] * x3[1]; T x20x01 = x2[0] * x0[1]; T x20x11 = x2[0] * x1[1]; T x20x31 = x2[0] * x3[1]; T x30x01 = x3[0] * x0[1]; T x30x11 = x3[0] * x1[1]; T x30x21 = x3[0] * x2[1]; result = ( x00x11 * ( x2[2] - x3[2] ) ) + ( x00x21 * ( x3[2] - x1[2] ) ) + ( x00x31 * ( x1[2] - x2[2] ) ) + ( x10x01 * ( x3[2] - x2[2] ) ) + ( x10x21 * ( x0[2] - x3[2] ) ) + ( x10x31 * ( x2[2] - x0[2] ) ) + ( x20x01 * ( x1[2]- x3[2] ) ) + ( x20x11 * ( x3[2] - x0[2] ) ) + ( x20x31 * ( x0[2] - x1[2] ) ) + ( x30x01 * ( x2[2] - x1[2] ) ) + ( x30x11 * ( x0[2] - x2[2] ) ) + ( x30x21 * ( x1[2] - x0[2] ) ); } // -------------------------------------------------------- inline void orientation3d(const Vec<3,expansion>& x0, const Vec<3,expansion>& x1, const Vec<3,expansion>& x2, const Vec<3,expansion>& x3, expansion& result ) { // avoid recomputing common factors expansion x00x11; multiply( x0[0], x1[1], x00x11 ); expansion x00x21; multiply( x0[0], x2[1], x00x21 ); expansion x00x31; multiply( x0[0], x3[1], x00x31 ); expansion x10x01; multiply( x1[0], x0[1], x10x01 ); expansion x10x21; multiply( x1[0], x2[1], x10x21 ); expansion x10x31; multiply( x1[0], x3[1], x10x31 ); expansion x20x01; multiply( x2[0], x0[1], x20x01 ); expansion x20x11; multiply( x2[0], x1[1], x20x11 ); expansion x20x31; multiply( x2[0], x3[1], x20x31 ); expansion x30x01; multiply( x3[0], x0[1], x30x01 ); expansion x30x11; multiply( x3[0], x1[1], x30x11 ); expansion x30x21; multiply( x3[0], x2[1], x30x21 ); expansion diff; subtract( x2[2], x3[2], diff ); multiply( x00x11, diff, result ); expansion prod; subtract( x3[2], x1[2], diff ); multiply( x00x21, diff, prod ); add( result, prod, result ); subtract( x1[2], x2[2], diff ); multiply( x00x31, diff, prod ); add( result, prod, result ); subtract( x3[2], x2[2], diff ); multiply( x10x01, diff, prod ); add( result, prod, result ); subtract( x0[2], x3[2], diff ); multiply( x10x21, diff, prod ); add( result, prod, result ); subtract( x2[2], x0[2], diff ); multiply( x10x31, diff, prod ); add( result, prod, result ); subtract( x1[2], x3[2], diff ); multiply( x20x01, diff, prod ); add( result, prod, result ); subtract( x3[2], x0[2], diff ); multiply( x20x11, diff, prod ); add( result, prod, result ); subtract( x0[2], x1[2], diff ); multiply( x20x31, diff, prod ); add( result, prod, result ); subtract( x2[2], x1[2], diff ); multiply( x30x01, diff, prod ); add( result, prod, result ); subtract( x0[2], x2[2], diff ); multiply( x30x11, diff, prod ); add( result, prod, result ); subtract( x1[2], x0[2], diff ); multiply( x30x21, diff, prod ); add( result, prod, result ); } // ---------------------------------------- int expansion_simplex_intersection1d(int k, const expansion& x0, const expansion& x1, const expansion& x2, double* out_alpha0, double* out_alpha1, double* out_alpha2) { assert( k == 1 ); assert(out_alpha0 && out_alpha1 && out_alpha2); assert(fegetround()== FE_TONEAREST); if( sign(x1-x2) < 0 ) { if( sign(x0-x1) < 0) return 0; else if ( sign(x0-x2) > 0 ) return 0; *out_alpha0=1; *out_alpha1=(x2.estimate()-x0.estimate())/(x2.estimate()-x1.estimate()); *out_alpha2=(x0.estimate()-x1.estimate())/(x2.estimate()-x1.estimate()); return 1; } else if( sign(x1-x2) > 0 ) { if( sign(x0-x2) < 0 ) return 0; else if( sign(x0-x1) > 0) return 0; *out_alpha0=1; *out_alpha1=(x2.estimate()-x0.estimate())/(x2.estimate()-x1.estimate()); *out_alpha2=(x0.estimate()-x1.estimate())/(x2.estimate()-x1.estimate()); return 1; } else { // x1 == x2 if( sign(x0-x1) != 0 ) return 0; *out_alpha0=1; *out_alpha1=0.5; *out_alpha2=0.5; return 1; } } // ---------------------------------------- int expansion_simplex_intersection2d(int k, const Vec2e& x0, const Vec2e& x1, const Vec2e& x2, double* out_alpha0, double* out_alpha1, double* out_alpha2 ) { assert(k==1); assert(fegetround()== FE_TONEAREST); // try projecting each coordinate out in turn double ax0, ax1, ax2; if(!expansion_simplex_intersection1d(1, x0[1], x1[1], x2[1], &ax0, &ax1, &ax2)) return 0; double ay0, ay1, ay2; if(!expansion_simplex_intersection1d(1, x0[0], x1[0], x2[0], &ay0, &ay1, &ay2)) return 0; // decide which solution is more accurate for barycentric coordinates double checkx=std::fabs(-ax0*x0[0].estimate()+ax1*x1[0].estimate()+ax2*x2[0].estimate()) +std::fabs(-ax0*x0[1].estimate()+ax1*x1[1].estimate()+ax2*x2[1].estimate()); double checky=std::fabs(-ay0*x0[0].estimate()+ay1*x1[0].estimate()+ay2*x2[0].estimate()) +std::fabs(-ay0*x0[1].estimate()+ay1*x1[1].estimate()+ay2*x2[1].estimate()); if(checkx<=checky) { *out_alpha0=ax0; *out_alpha1=ax1; *out_alpha2=ax2; } else { *out_alpha0=ay0; *out_alpha1=ay1; *out_alpha2=ay2; } return 1; } // ---------------------------------------- int expansion_simplex_intersection2d(int k, const Vec2e& x0, const Vec2e& x1, const Vec2e& x2, const Vec2e& x3, double* out_alpha0, double* out_alpha1, double* out_alpha2, double* out_alpha3) { assert(1<=k && k<=3); assert(fegetround()== FE_TONEAREST); switch(k) { case 1: // point vs. triangle { expansion alpha1 = -orientation2d(x0, x2, x3); expansion alpha2 = orientation2d(x0, x1, x3); if(certainly_opposite_sign(alpha1, alpha2)) return 0; expansion alpha3 = -orientation2d(x0, x1, x2); if(certainly_opposite_sign(alpha1, alpha3)) return 0; if(certainly_opposite_sign(alpha2, alpha3)) return 0; double sum2 = alpha1.estimate() + alpha2.estimate() + alpha3.estimate(); if(sum2) { *out_alpha0=1; *out_alpha1 = alpha1.estimate() / sum2; *out_alpha2 = alpha2.estimate() / sum2; *out_alpha3 = alpha3.estimate() / sum2; return 1; } else { // triangle is degenerate and point lies on same line if(expansion_simplex_intersection2d(1, x0, x1, x2, out_alpha0, out_alpha1, out_alpha2)) { *out_alpha3=0; return 1; } if(expansion_simplex_intersection2d(1, x0, x1, x3, out_alpha0, out_alpha1, out_alpha3)) { *out_alpha2=0; return 1; } if(expansion_simplex_intersection2d(1, x0, x2, x3, out_alpha0, out_alpha2, out_alpha3)) { *out_alpha1=0; return 1; } return 0; } } case 2: // segment vs. segment { expansion alpha0 = orientation2d(x1, x2, x3); expansion alpha1 = -orientation2d(x0, x2, x3); if( certainly_opposite_sign(alpha0, alpha1) ) return 0; expansion alpha2 = orientation2d(x0, x1, x3); expansion alpha3 = -orientation2d(x0, x1, x2); if( certainly_opposite_sign(alpha2, alpha3) ) return 0; double sum1, sum2; sum1= alpha0.estimate() + alpha1.estimate(); sum2= alpha2.estimate() + alpha3.estimate(); if(sum1 && sum2){ *out_alpha0 = alpha0.estimate() / sum1; *out_alpha1 = alpha1.estimate() / sum1; *out_alpha2 = alpha2.estimate() / sum2; *out_alpha3 = alpha3.estimate() / sum2; return 1; } else { // degenerate: segments lie on the same line if(expansion_simplex_intersection2d(1, x0, x2, x3, out_alpha0, out_alpha2, out_alpha3)){ *out_alpha1=0; return 1; } if(expansion_simplex_intersection2d(1, x1, x2, x3, out_alpha1, out_alpha2, out_alpha3)){ *out_alpha0=0; return 1; } if(expansion_simplex_intersection2d(1, x2, x0, x1, out_alpha2, out_alpha0, out_alpha1)){ *out_alpha3=0; return 1; } if(expansion_simplex_intersection2d(1, x3, x0, x1, out_alpha3, out_alpha0, out_alpha1)){ *out_alpha2=0; return 1; } return 0; } } break; default: assert(0); return -1; // should never get here } } // -------------------------------------------------------- // degenerate test in 3d - assumes four points lie on the same plane bool expansion_simplex_intersection3d(int k, const Vec3e& x0, const Vec3e& x1, const Vec3e& x2, const Vec3e& x3, double* alpha0, double* alpha1, double* alpha2, double* ) { assert(k<=2); assert(fegetround()== FE_TONEAREST); // try projecting each coordinate out in turn double ax0, ax1, ax2, ax3; if( !expansion_simplex_intersection2d(k, Vec2e(x0[1],x0[2]), Vec2e(x1[1],x1[2]), Vec2e(x2[1],x2[2]), Vec2e(x3[1],x3[2]), &ax0, &ax1, &ax2,&ax3) ) { return 0; } double ay0, ay1, ay2, ay3; Vec2e p0( x0[0], x0[2] ); Vec2e p1( x1[0], x1[2] ); Vec2e p2( x2[0], x2[2] ); Vec2e p3( x3[0], x3[2] ); if ( !expansion_simplex_intersection2d(k, p0, p1, p2, p3, &ay0, &ay1, &ay2, &ay3) ) { return 0; } double az0, az1, az2, az3; if( !expansion_simplex_intersection2d(k, Vec2e(x0[0],x0[1]), Vec2e(x1[0],x1[1]), Vec2e(x2[0],x2[1]), Vec2e(x3[0],x3[1]), &az0, &az1, &az2, &az3) ) { return 0; } // decide which solution is more accurate for barycentric coordinates double checkx, checky, checkz; Vec3d estx0( x0[0].estimate(), x0[1].estimate(), x0[2].estimate() ); Vec3d estx1( x1[0].estimate(), x1[1].estimate(), x1[2].estimate() ); Vec3d estx2( x2[0].estimate(), x2[1].estimate(), x2[2].estimate() ); Vec3d estx3( x3[0].estimate(), x3[1].estimate(), x3[2].estimate() ); if(k==1) { checkx=std::fabs(-ax0*estx0[0]+ax1*estx1[0]+ax2*estx2[0]+ax3*estx3[0]) +std::fabs(-ax0*estx0[1]+ax1*estx1[1]+ax2*estx2[1]+ax3*estx3[1]) +std::fabs(-ax0*estx0[2]+ax1*estx1[2]+ax2*estx2[2]+ax3*estx3[2]); checky=std::fabs(-ay0*estx0[0]+ay1*estx1[0]+ay2*estx2[0]+ay3*estx3[0]) +std::fabs(-ay0*estx0[1]+ay1*estx1[1]+ay2*estx2[1]+ay3*estx3[1]) +std::fabs(-ay0*estx0[2]+ay1*estx1[2]+ay2*estx2[2]+ay3*estx3[2]); checkz=std::fabs(-az0*estx0[0]+az1*estx1[0]+az2*estx2[0]+az3*estx3[0]) +std::fabs(-az0*estx0[1]+az1*estx1[1]+az2*estx2[1]+az3*estx3[1]) +std::fabs(-az0*estx0[2]+az1*estx1[2]+az2*estx2[2]+az3*estx3[2]); } else { checkx=std::fabs(-ax0*estx0[0]-ax1*estx1[0]+ax2*estx2[0]+ax3*estx3[0]) +std::fabs(-ax0*estx0[1]-ax1*estx1[1]+ax2*estx2[1]+ax3*estx3[1]) +std::fabs(-ax0*estx0[2]-ax1*estx1[2]+ax2*estx2[2]+ax3*estx3[2]); checky=std::fabs(-ay0*estx0[0]-ay1*estx1[0]+ay2*estx2[0]+ay3*estx3[0]) +std::fabs(-ay0*estx0[1]-ay1*estx1[1]+ay2*estx2[1]+ay3*estx3[1]) +std::fabs(-ay0*estx0[2]-ay1*estx1[2]+ay2*estx2[2]+ay3*estx3[2]); checkz=std::fabs(-az0*estx0[0]-az1*estx1[0]+az2*estx2[0]+az3*estx3[0]) +std::fabs(-az0*estx0[1]-az1*estx1[1]+az2*estx2[1]+az3*estx3[1]) +std::fabs(-az0*estx0[2]-az1*estx1[2]+az2*estx2[2]+az3*estx3[2]); } if(checkx<=checky && checkx<=checkz) { *alpha0=ax0; *alpha1=ax1; *alpha2=ax2; *alpha2=ax3; } else if(checky<=checkz) { *alpha0=ay0; *alpha1=ay1; *alpha2=ay2; *alpha2=ay3; } else { *alpha0=az0; *alpha1=az1; *alpha2=az2; *alpha2=az3; } return 1; } // -------------------------------------------------------- int degenerate_point_tetrahedron_intersection(const Vec3e& x0, const Vec3e& x1, const Vec3e& x2, const Vec3e& x3, const Vec3e& x4, double* alpha0, double* alpha1, double* alpha2, double* alpha3, double* alpha4) { assert(fegetround()== FE_TONEAREST); // degenerate: point and tetrahedron in same plane if (expansion_simplex_intersection3d(1, x0, x2, x3, x4, alpha0, alpha2, alpha3, alpha4)) { *alpha1=0; return 1; } if(expansion_simplex_intersection3d(1, x0, x1, x3, x4, alpha0, alpha1, alpha3, alpha4)) { *alpha2=0; return 1; } if(expansion_simplex_intersection3d(1, x0, x1, x2, x4, alpha0, alpha1, alpha2, alpha4)) { *alpha3=0; return 1; } if(expansion_simplex_intersection3d(1, x0, x1, x2, x3, alpha0, alpha1, alpha2, alpha3)) { *alpha4=0; return 1; } return 0; } // -------------------------------------------------------- int degenerate_point_tetrahedron_intersection(const Vec3Interval& , const Vec3Interval& , const Vec3Interval& , const Vec3Interval& , const Vec3Interval& , double* , double* , double* , double* , double* ) { return -1; } // -------------------------------------------------------- template int point_tetrahedron_intersection(const Vec<3,T>& x0, const Vec<3,T>& x1, const Vec<3,T>& x2, const Vec<3,T>& x3, const Vec<3,T>& x4, double* out_alpha0, double* out_alpha1, double* out_alpha2, double* out_alpha3, double* out_alpha4 ) { T::begin_special_arithmetic(); T alpha1; orientation3d(x0, x2, x3, x4, alpha1); alpha1 = -alpha1; T alpha2; orientation3d(x0, x1, x3, x4, alpha2); if( certainly_opposite_sign(alpha1, alpha2) ) { T::end_special_arithmetic(); return 0; } T alpha3; orientation3d(x0, x1, x2, x4, alpha3); alpha3 = -alpha3; if( certainly_opposite_sign(alpha1, alpha3) ) { T::end_special_arithmetic(); return 0; } if( certainly_opposite_sign(alpha2, alpha3) ) { T::end_special_arithmetic(); return 0; } T alpha4; orientation3d(x0, x1, x2, x3, alpha4); T::end_special_arithmetic(); if( certainly_opposite_sign(alpha1, alpha4) ) return 0; if( certainly_opposite_sign(alpha2, alpha4) ) return 0; if( certainly_opposite_sign(alpha3, alpha4) ) return 0; if ( alpha1.indefinite_sign() || alpha2.indefinite_sign() || alpha3.indefinite_sign() || alpha4.indefinite_sign() ) { // degenerate return -1; } double sum2 = alpha1.estimate() + alpha2.estimate() + alpha3.estimate() + alpha4.estimate(); if(sum2) { *out_alpha0 = 1; *out_alpha1 = alpha1.estimate() / sum2; *out_alpha2 = alpha2.estimate() / sum2; *out_alpha3 = alpha3.estimate() / sum2; *out_alpha4 = alpha4.estimate() / sum2; return 1; } else { // If T is IntervalType, returns -1 // If T is expansion, computes exact intersection by projecting to lower dimensions. return degenerate_point_tetrahedron_intersection( x0, x1, x2, x3, x4, out_alpha0, out_alpha1, out_alpha2, out_alpha3, out_alpha4 ); } } // -------------------------------------------------------- int degenerate_edge_triangle_intersection(const Vec3e& x0, const Vec3e& x1, const Vec3e& x2, const Vec3e& x3, const Vec3e& x4, double* alpha0, double* alpha1, double* alpha2, double* alpha3, double* alpha4) { // degenerate: segment and triangle in same plane if(expansion_simplex_intersection3d(1, x1, x2, x3, x4, alpha1, alpha2, alpha3, alpha4)){ *alpha0=0; return 1; } if(expansion_simplex_intersection3d(1, x0, x2, x3, x4, alpha0, alpha2, alpha3, alpha4)){ *alpha1=0; return 1; } if(expansion_simplex_intersection3d(2, x0, x1, x3, x4, alpha0, alpha1, alpha3, alpha4)){ *alpha2=0; return 1; } if(expansion_simplex_intersection3d(2, x0, x1, x2, x4, alpha0, alpha1, alpha2, alpha4)){ *alpha3=0; return 1; } if(expansion_simplex_intersection3d(2, x0, x1, x2, x3, alpha0, alpha1, alpha2, alpha3)){ *alpha4=0; return 1; } return 0; } // -------------------------------------------------------- int degenerate_edge_triangle_intersection(const Vec3Interval& , const Vec3Interval& , const Vec3Interval& , const Vec3Interval& , const Vec3Interval& , double* , double* , double* , double* , double* ) { return -1; } // -------------------------------------------------------- template int edge_triangle_intersection(const Vec<3,T>& x0, const Vec<3,T>& x1, const Vec<3,T>& x2, const Vec<3,T>& x3, const Vec<3,T>& x4, double* out_alpha0, double* out_alpha1, double* out_alpha2, double* out_alpha3, double* out_alpha4 ) { T::begin_special_arithmetic(); T alpha0; orientation3d(x1, x2, x3, x4,alpha0); T alpha1; orientation3d(x0, x2, x3, x4,alpha1); alpha1 = -alpha1; if( certainly_opposite_sign(alpha0, alpha1) ) { T::end_special_arithmetic(); return 0; } T alpha2; orientation3d(x0, x1, x3, x4, alpha2); T alpha3; orientation3d(x0, x1, x2, x4, alpha3); alpha3 = -alpha3; if( certainly_opposite_sign(alpha2, alpha3) ) { T::end_special_arithmetic(); return 0; } T alpha4; orientation3d(x0, x1, x2, x3, alpha4); if( certainly_opposite_sign(alpha2, alpha4) ) { T::end_special_arithmetic(); return 0; } if( certainly_opposite_sign(alpha3, alpha4) ) { T::end_special_arithmetic(); return 0; } T::end_special_arithmetic(); if ( alpha0.indefinite_sign() || alpha1.indefinite_sign() || alpha2.indefinite_sign() || alpha3.indefinite_sign() || alpha4.indefinite_sign() ) { // degenerate return -1; } double sum1 = alpha0.estimate() + alpha1.estimate(); double sum2 = alpha2.estimate() + alpha3.estimate() + alpha4.estimate(); if(sum1 && sum2) { *out_alpha0 = alpha0.estimate() / sum1; *out_alpha1 = alpha1.estimate() / sum1; *out_alpha2 = alpha2.estimate() / sum2; *out_alpha3 = alpha3.estimate() / sum2; *out_alpha4 = alpha4.estimate() / sum2; return 1; } else { // If T is IntervalType, returns -1 // If T is expansion, computes exact intersection by projecting to lower dimensions. return degenerate_edge_triangle_intersection( x0, x1, x2, x3, x4, out_alpha0, out_alpha1, out_alpha2, out_alpha3, out_alpha4 ); } } // ---------------------------------------- bool edge_triangle_intersection(const Vec3d &d_x0old, const Vec3d &d_x1old, const Vec3d &d_x2old, const Vec3d &d_x3old, const Vec3d &d_x0new, const Vec3d &d_x1new, const Vec3d &d_x2new, const Vec3d &d_x3new, bool is_edge_edge, const Vec3b& ts, const Vec3b& us, const Vec3b& vs, const Vec3d& d_s0, const Vec3d& d_s1, double* alphas ) { // TODO: These should be cached already Vec3Interval t0, t1, t2; get_triangle_vertices( d_x0old, d_x1old, d_x2old, d_x3old, d_x0new, d_x1new, d_x2new, d_x3new, is_edge_edge, ts, us, vs, t0, t1, t2 ); Vec3Interval s0, s1; make_vector( d_s0, s0 ); make_vector( d_s1, s1 ); int result = edge_triangle_intersection( s0, s1, t0, t1, t2, &alphas[0], &alphas[1], &alphas[2], &alphas[3], &alphas[4] ); // If degenerate, repeat test using expansion arithmetric if ( result < 0 ) { // TODO: These might be cached already Vec3e exp_t0, exp_t1, exp_t2; get_triangle_vertices( d_x0old, d_x1old, d_x2old, d_x3old, d_x0new, d_x1new, d_x2new, d_x3new, is_edge_edge, ts, us, vs, exp_t0, exp_t1, exp_t2 ); Vec3e exp_s0, exp_s1; make_vector( d_s0, exp_s0 ); make_vector( d_s1, exp_s1 ); result = edge_triangle_intersection( exp_s0, exp_s1, exp_t0, exp_t1, exp_t2, &alphas[0], &alphas[1], &alphas[2], &alphas[3], &alphas[4] ); } if ( result == 0 ) { return false; } return true; } // ---------------------------------------- template T plane_dist( const Vec<3,T>& x, const Vec<3,T>& q, const Vec<3,T>& r, const Vec<3,T>& p ) { return dot( x-p, cross( q-p, r-p ) ); } // ---------------------------------------- template void implicit_surface_function( const Vec<3,T>& x, const Vec<3,T>& q0, const Vec<3,T>& q1, const Vec<3,T>& q2, const Vec<3,T>& q3, T& out ) { T::begin_special_arithmetic(); T g012 = plane_dist( x, q0, q1, q2 ); T g132 = plane_dist( x, q1, q3, q2 ); T h12 = g012 * g132; T g013 = plane_dist( x, q0, q1, q3 ); T g032 = plane_dist( x, q0, q3, q2 ); T h03 = g013 * g032; out = h12 - h03; T::end_special_arithmetic(); } // ---------------------------------------- bool test_with_triangles(const Vec3d &d_x0old, const Vec3d &d_x1old, const Vec3d &d_x2old, const Vec3d &d_x3old, const Vec3d &d_x0new, const Vec3d &d_x1new, const Vec3d &d_x2new, const Vec3d &d_x3new, bool is_edge_edge, const Vec4b& ts, const Vec4b& us, const Vec4b& vs, const Vec3d& s0, const Vec3d& s1, bool use_positive_triangles, bool& edge_hit ) { // determine which two triangles are on the positive side of f // first try evaluating sign using interval arithmetic int sign_h12 = -2; { Vec3Interval q0, q1, q2, q3; // TODO: These should be cached already get_quad_vertices( d_x0old, d_x1old, d_x2old, d_x3old, d_x0new, d_x1new, d_x2new, d_x3new, is_edge_edge, ts, us, vs, q0, q1, q2, q3 ); IntervalType::begin_special_arithmetic(); Vec3Interval x = IntervalType(0.5) * ( q0 + q3 ); IntervalType g012 = plane_dist( x, q0, q1, q2 ); IntervalType g132 = plane_dist( x, q1, q3, q2 ); IntervalType h12 = g012 * g132; IntervalType::end_special_arithmetic(); if ( h12.is_certainly_negative() ) { sign_h12 = -1; } if ( h12.is_certainly_zero() ) { sign_h12 = 0; } if ( h12.is_certainly_positive() ) { sign_h12 = 1; } } if ( sign_h12 == -2 ) { // not sure about sign - compute using expansion Vec3e eq0, eq1, eq2, eq3; // TODO: These might be cached already get_quad_vertices( d_x0old, d_x1old, d_x2old, d_x3old, d_x0new, d_x1new, d_x2new, d_x3new, is_edge_edge, ts, us, vs, eq0, eq1, eq2, eq3 ); Vec3e x = expansion( 0.5 ) * ( eq0 + eq3 ); expansion g012 = plane_dist( x, eq0, eq1, eq2 ); expansion g132 = plane_dist( x, eq1, eq3, eq2 ); expansion h12 = g012 * g132; sign_h12 = sign( h12 ); } if ( sign_h12 == 0 ) { // use either pair of triangles sign_h12 = 1; } if ( sign_h12 > 0 ) { // positive side: 013, 032 // negative side: 012, 132 if ( use_positive_triangles ) { double b[5] = { 0.5, 0.5, 0.5, 0.5, 0.5 }; Vec3b t013( ts[0], ts[1], ts[3] ); Vec3b u013( us[0], us[1], us[3] ); Vec3b v013( vs[0], vs[1], vs[3] ); bool hit_a = edge_triangle_intersection( d_x0old, d_x1old, d_x2old, d_x3old, d_x0new, d_x1new, d_x2new, d_x3new, is_edge_edge, t013, u013, v013, s0, s1, b ); if ( b[2] == 0.0 || b[3] == 0.0 || b[4] == 0.0 ) { edge_hit = true; } if ( b[2] == 1.0 || b[3] == 1.0 || b[4] == 1.0 ) { edge_hit = true; } Vec3b t032( ts[0], ts[3], ts[2] ); Vec3b u032( us[0], us[3], us[2] ); Vec3b v032( vs[0], vs[3], vs[2] ); bool hit_b = edge_triangle_intersection( d_x0old, d_x1old, d_x2old, d_x3old, d_x0new, d_x1new, d_x2new, d_x3new, is_edge_edge, t032, u032, v032, s0, s1, b ); if ( b[2] == 0.0 || b[3] == 0.0 || b[4] == 0.0 ) { edge_hit = true; } if ( b[2] == 1.0 || b[3] == 1.0 || b[4] == 1.0 ) { edge_hit = true; } return hit_a || hit_b; } else { double b[5] = { 0.5, 0.5, 0.5, 0.5, 0.5 }; Vec3b t012( ts[0], ts[1], ts[2] ); Vec3b u012( us[0], us[1], us[2] ); Vec3b v012( vs[0], vs[1], vs[2] ); bool hit_a = edge_triangle_intersection( d_x0old, d_x1old, d_x2old, d_x3old, d_x0new, d_x1new, d_x2new, d_x3new, is_edge_edge, t012, u012, v012, s0, s1, b ); if ( b[2] == 0.0 || b[3] == 0.0 || b[4] == 0.0 ) { edge_hit = true; } if ( b[2] == 1.0 || b[3] == 1.0 || b[4] == 1.0 ) { edge_hit = true; } Vec3b t132( ts[1], ts[3], ts[2] ); Vec3b u132( us[1], us[3], us[2] ); Vec3b v132( vs[1], vs[3], vs[2] ); bool hit_b = edge_triangle_intersection( d_x0old, d_x1old, d_x2old, d_x3old, d_x0new, d_x1new, d_x2new, d_x3new, is_edge_edge, t132, u132, v132, s0, s1, b ); if ( b[2] == 0.0 || b[3] == 0.0 || b[4] == 0.0 ) { edge_hit = true; } if ( b[2] == 1.0 || b[3] == 1.0 || b[4] == 1.0 ) { edge_hit = true; } return hit_a || hit_b; } } else { // positive side: 012, 132 // negative side: 013, 032 if ( use_positive_triangles ) { double b[5] = { 0.5, 0.5, 0.5, 0.5, 0.5 }; Vec3b t012( ts[0], ts[1], ts[2] ); Vec3b u012( us[0], us[1], us[2] ); Vec3b v012( vs[0], vs[1], vs[2] ); bool hit_a = edge_triangle_intersection( d_x0old, d_x1old, d_x2old, d_x3old, d_x0new, d_x1new, d_x2new, d_x3new, is_edge_edge, t012, u012, v012, s0, s1, b ); if ( b[2] == 0.0 || b[3] == 0.0 || b[4] == 0.0 ) { edge_hit = true; } if ( b[2] == 1.0 || b[3] == 1.0 || b[4] == 1.0 ) { edge_hit = true; } Vec3b t132( ts[1], ts[3], ts[2] ); Vec3b u132( us[1], us[3], us[2] ); Vec3b v132( vs[1], vs[3], vs[2] ); bool hit_b = edge_triangle_intersection( d_x0old, d_x1old, d_x2old, d_x3old, d_x0new, d_x1new, d_x2new, d_x3new, is_edge_edge, t132, u132, v132, s0, s1, b ); if ( b[2] == 0.0 || b[3] == 0.0 || b[4] == 0.0 ) { edge_hit = true; } if ( b[2] == 1.0 || b[3] == 1.0 || b[4] == 1.0 ) { edge_hit = true; } return hit_a || hit_b; } else { double b[5] = { 0.5, 0.5, 0.5, 0.5, 0.5 }; Vec3b t013( ts[0], ts[1], ts[3] ); Vec3b u013( us[0], us[1], us[3] ); Vec3b v013( vs[0], vs[1], vs[3] ); bool hit_a = edge_triangle_intersection( d_x0old, d_x1old, d_x2old, d_x3old, d_x0new, d_x1new, d_x2new, d_x3new, is_edge_edge, t013, u013, v013, s0, s1, b ); if ( b[2] == 0.0 || b[3] == 0.0 || b[4] == 0.0 ) { edge_hit = true; } if ( b[2] == 1.0 || b[3] == 1.0 || b[4] == 1.0 ) { edge_hit = true; } Vec3b t032( ts[0], ts[3], ts[2] ); Vec3b u032( us[0], us[3], us[2] ); Vec3b v032( vs[0], vs[3], vs[2] ); bool hit_b = edge_triangle_intersection( d_x0old, d_x1old, d_x2old, d_x3old, d_x0new, d_x1new, d_x2new, d_x3new, is_edge_edge, t032, u032, v032, s0, s1, b ); if ( b[2] == 0.0 || b[3] == 0.0 || b[4] == 0.0 ) { edge_hit = true; } if ( b[2] == 1.0 || b[3] == 1.0 || b[4] == 1.0 ) { edge_hit = true; } return hit_a || hit_b; } } } /// -------------------------------------------------------- inline int plane_sign( const Vec3d& n, const Vec3Interval& x ) { IntervalType dist = IntervalType(n[0])*x[0] + IntervalType(n[1])*x[1] + IntervalType(n[2])*x[2]; if ( dist.is_certainly_negative() ) { return -1; } else if ( dist.is_certainly_positive() ) { return 1; } return 0; } /// -------------------------------------------------------- inline int quick_1_plane_sign( const Vec3i& normal, const Vec3Interval& x ) { IntervalType dist( 0, 0 ); if ( normal[0] < 0 ) { dist -= x[0]; } else if ( normal[0] > 0 ) { dist += x[0]; } if ( normal[1] < 0 ) { dist -= x[1]; } else if ( normal[1] > 0 ) { dist += x[1]; } if ( normal[2] < 0 ) { dist -= x[2]; } else if ( normal[2] > 0 ) { dist += x[2]; } if ( dist.is_certainly_negative() ) { return -1; } else if ( dist.is_certainly_positive() ) { return 1; } return 0; } } // end unnamed namespace for local helper functions // // Member function definitions // // ---------------------------------------- /// /// Determine if the given point is inside the tetrahedron given by tet_indices /// // ---------------------------------------- bool RootParityCollisionTest::point_tetrahedron_intersection( const Vec4ui& quad, const Vec4b& ts, const Vec4b& us, const Vec4b& vs, const Vec3d& d_x ) { Vec3Interval x; make_vector( d_x, x ); double s[5]; int result = rootparity::point_tetrahedron_intersection(x, m_interval_hex_vertices[quad[0]], m_interval_hex_vertices[quad[1]], m_interval_hex_vertices[quad[2]], m_interval_hex_vertices[quad[3]], &s[0], &s[1], &s[2], &s[3], &s[4] ); // If degenerate, repeat test using expansion arithmetric if ( result < 0 ) { // Check if the expansion vertices have been computed already for ( unsigned int i = 0; i < 4; ++i ) { if ( !m_expansion_hex_vertices_computed[ quad[i] ] ) { if ( m_is_edge_edge ) { edge_edge_collision_function( m_x0old, m_x1old, m_x2old, m_x3old, m_x0new, m_x1new, m_x2new, m_x3new, ts[i], us[i], vs[i], m_expansion_hex_vertices[ quad[i] ] ); } else { point_triangle_collision_function( m_x0old, m_x1old, m_x2old, m_x3old, m_x0new, m_x1new, m_x2new, m_x3new, ts[i], us[i], vs[i], m_expansion_hex_vertices[ quad[i] ] ); } m_expansion_hex_vertices_computed[ quad[i] ] = true; } } // now run the test in expansion arithmetic Vec3e exp_x; make_vector( d_x, exp_x ); result = rootparity::point_tetrahedron_intersection(exp_x, m_expansion_hex_vertices[ quad[0] ], m_expansion_hex_vertices[ quad[1] ], m_expansion_hex_vertices[ quad[2] ], m_expansion_hex_vertices[ quad[3] ], &s[0], &s[1], &s[2], &s[3], &s[4] ); } if ( result == 0 ) { return false; } return true; } // ---------------------------------------- /// /// Determine if the given segment intersects the triangle /// // ---------------------------------------- bool RootParityCollisionTest::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 ) { const Vec3Interval& t0 = m_interval_hex_vertices[triangle[0]]; const Vec3Interval& t1 = m_interval_hex_vertices[triangle[1]]; const Vec3Interval& t2 = m_interval_hex_vertices[triangle[2]]; Vec3Interval s0, s1; make_vector( d_s0, s0 ); make_vector( d_s1, s1 ); int result = rootparity::edge_triangle_intersection( s0, s1, t0, t1, t2, &alphas[0], &alphas[1], &alphas[2], &alphas[3], &alphas[4] ); // If degenerate, repeat test using expansion arithmetric if ( result < 0 ) { Vec3e exp_t0, exp_t1, exp_t2; get_triangle_vertices( m_x0old, m_x1old, m_x2old, m_x3old, m_x0new, m_x1new, m_x2new, m_x3new, m_is_edge_edge, ts, us, vs, exp_t0, exp_t1, exp_t2 ); Vec3e exp_s0, exp_s1; make_vector( d_s0, exp_s0 ); make_vector( d_s1, exp_s1 ); result = rootparity::edge_triangle_intersection( exp_s0, exp_s1, exp_t0, exp_t1, exp_t2, &alphas[0], &alphas[1], &alphas[2], &alphas[3], &alphas[4] ); } if ( result == 0 ) { return false; } return true; } // ---------------------------------------- /// /// Compute the sign of the implicit surface function which is zero on the bilinear patch defined by quad. /// // ---------------------------------------- int RootParityCollisionTest::implicit_surface_function_sign( const Vec4ui& quad, const Vec4b& ts, const Vec4b& us, const Vec4b& vs, const Vec3d& d_x ) { // first try evaluating sign using interval arithmetic { const Vec3Interval& q0 = m_interval_hex_vertices[quad[0]]; const Vec3Interval& q1 = m_interval_hex_vertices[quad[1]]; const Vec3Interval& q2 = m_interval_hex_vertices[quad[2]]; const Vec3Interval& q3 = m_interval_hex_vertices[quad[3]]; Vec3Interval x; make_vector( d_x, x ); IntervalType f; implicit_surface_function( x, q0, q1, q2, q3, f ); if ( f.is_certainly_negative() ) { return -1; } if ( f.is_certainly_zero() ) { return 0; } if ( f.is_certainly_positive() ) { return 1; } } // not sure about sign - compute using expansion for ( unsigned int i = 0; i < 4; ++i ) { if ( !m_expansion_hex_vertices_computed[ quad[i] ] ) { if ( m_is_edge_edge ) { edge_edge_collision_function( m_x0old, m_x1old, m_x2old, m_x3old, m_x0new, m_x1new, m_x2new, m_x3new, ts[i], us[i], vs[i], m_expansion_hex_vertices[ quad[i] ] ); } else { point_triangle_collision_function( m_x0old, m_x1old, m_x2old, m_x3old, m_x0new, m_x1new, m_x2new, m_x3new, ts[i], us[i], vs[i], m_expansion_hex_vertices[ quad[i] ] ); } m_expansion_hex_vertices_computed[ quad[i] ] = true; } } Vec3e x; make_vector( d_x, x ); expansion ef; implicit_surface_function( x, m_expansion_hex_vertices[ quad[0] ], m_expansion_hex_vertices[ quad[1] ], m_expansion_hex_vertices[ quad[2] ], m_expansion_hex_vertices[ quad[3] ], ef ); return sign( ef ); } // ---------------------------------------- /// /// Test the segment s0-s1 against the bilinear patch defined by quad to determine whether there is an even or odd number of /// intersections. Returns true if odd. /// // ---------------------------------------- bool RootParityCollisionTest::ray_quad_intersection_parity( const Vec4ui& quad, const Vec4b& ts, const Vec4b& us, const Vec4b& vs, const Vec3d& ray_origin, const Vec3d& ray_head, bool& edge_hit, bool& origin_on_surface ) { bool point_in_tet0 = point_tetrahedron_intersection( quad, ts, us, vs, ray_origin ); if ( point_in_tet0 ) { int sign0 = implicit_surface_function_sign( quad, ts, us, vs, ray_origin ); if ( sign0 == 0 ) { origin_on_surface = true; return false; } // s0 is inside the tet, s1 is outside if ( sign0 > 0 ) { // use the triangles on the negative side of f() return test_with_triangles( m_x0old, m_x1old, m_x2old, m_x3old, m_x0new, m_x1new, m_x2new, m_x3new, m_is_edge_edge, ts, us, vs, ray_origin, ray_head, false, edge_hit ); } else { // use the triangles on the positive side of f() return test_with_triangles( m_x0old, m_x1old, m_x2old, m_x3old, m_x0new, m_x1new, m_x2new, m_x3new, m_is_edge_edge, ts, us, vs, ray_origin, ray_head, true, edge_hit ); } } else { // s0 is outside the tet // both outside // use either set of triangles bool hit_a, hit_b; { double b[5] = { 0.5, 0.5, 0.5, 0.5, 0.5 }; Vec3ui triangle013( quad[0], quad[1], quad[3] ); Vec3b t013( ts[0], ts[1], ts[3] ); Vec3b u013( us[0], us[1], us[3] ); Vec3b v013( vs[0], vs[1], vs[3] ); hit_a = edge_triangle_intersection( triangle013, t013, u013, v013, ray_origin, ray_head, b ); if ( b[2] == 0.0 || b[3] == 0.0 || b[4] == 0.0 ) { edge_hit = true; } if ( b[2] == 1.0 || b[3] == 1.0 || b[4] == 1.0 ) { edge_hit = true; } } { double b[5] = { 0.5, 0.5, 0.5, 0.5, 0.5 }; Vec3ui triangle032( quad[0], quad[3], quad[2] ); Vec3b t032( ts[0], ts[3], ts[2] ); Vec3b u032( us[0], us[3], us[2] ); Vec3b v032( vs[0], vs[3], vs[2] ); hit_b = edge_triangle_intersection( triangle032, t032, u032, v032, ray_origin, ray_head, b ); if ( b[2] == 0.0 || b[3] == 0.0 || b[4] == 0.0 ) { edge_hit = true; } if ( b[2] == 1.0 || b[3] == 1.0 || b[4] == 1.0 ) { edge_hit = true; } } return hit_a ^ hit_b; } assert( !"Should not get here" ); return true; } // -------------------------------------------------------- /// /// 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 RootParityCollisionTest::ray_prism_parity_test() { Vec3d test_ray( m_ray ); double ray_len = mag( test_ray ); std::vector tris(2); tris[0] = Vec3ui( 0, 1, 2 ); tris[1] = Vec3ui( 3, 4, 5 ); std::vector quads(3); quads[0] = Vec4ui( 0, 1, 3, 4 ); quads[1] = Vec4ui( 1, 2, 4, 5 ); quads[2] = Vec4ui( 0, 2, 3, 5 ); const bool vertex_ts[6] = { 0, 0, 0, 1, 1, 1 }; const bool vertex_us[6] = { 0, 1, 0, 0, 1, 0 }; const bool vertex_vs[6] = { 0, 0, 1, 0, 0, 1 }; // for debugging purposes, store the result of each hit test std::vector tri_hits( 2, false ); std::vector quad_hits( 3, false ); bool good_hit = false; unsigned int num_tries = 0; while (!good_hit && num_tries++ < 10 ) { good_hit = true; // ray-cast against each tri and each quad for ( unsigned int i = 0; i < tris.size(); ++i ) { const Vec3ui& t = tris[i]; double bary[5] = { 0.5, 0.5, 0.5, 0.5, 0.5 }; Vec3b ts( vertex_ts[t[0]], vertex_ts[t[1]], vertex_ts[t[2]] ); Vec3b us( vertex_us[t[0]], vertex_us[t[1]], vertex_us[t[2]] ); Vec3b vs( vertex_vs[t[0]], vertex_vs[t[1]], vertex_vs[t[2]] ); tri_hits[i] = rootparity::edge_triangle_intersection( m_x0old, m_x1old, m_x2old, m_x3old, m_x0new, m_x1new, m_x2new, m_x3new, m_is_edge_edge, ts, us, vs, Vec3d(0,0,0), test_ray, bary ); if ( tri_hits[i] ) { if ( bary[2] == 0.0 || bary[3] == 0.0 || bary[4] == 0.0 ) { good_hit = false; } if ( bary[2] == 1.0 || bary[3] == 1.0 || bary[4] == 1.0 ) { good_hit = false; } if ( bary[0] == 1.0 ) { // origin is on surface return true; } } } for ( unsigned int i = 0; i < quads.size(); ++i ) { const Vec4ui& q = quads[i]; bool edge_hit = false; bool origin_on_surface = false; Vec4b ts( vertex_ts[q[0]], vertex_ts[q[1]], vertex_ts[q[2]], vertex_ts[q[3]] ); Vec4b us( vertex_us[q[0]], vertex_us[q[1]], vertex_us[q[2]], vertex_us[q[3]] ); Vec4b vs( vertex_vs[q[0]], vertex_vs[q[1]], vertex_vs[q[2]], vertex_vs[q[3]] ); quad_hits[i] = ray_quad_intersection_parity( q, ts, us, vs, Vec3d(0,0,0), test_ray, edge_hit, origin_on_surface ); if ( edge_hit ) { good_hit = false; break; } if ( origin_on_surface ) { return true; } } // check if any hit was not good if ( !good_hit ) { double r = rand() / (double)RAND_MAX * 2.0 * M_PI; test_ray[0] = cos(r) * ray_len; test_ray[1] = -sin(r) * ray_len; } } if ( !good_hit ) { return true; } unsigned int num_hits = 0; for ( unsigned int i = 0; i < tri_hits.size(); ++i ) { if ( tri_hits[i] ) { ++num_hits; } } for ( unsigned int i = 0; i < quad_hits.size(); ++i ) { if ( quad_hits[i] ) { ++num_hits; } } return ( num_hits % 2 == 1 ); } // -------------------------------------------------------- /// /// 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 RootParityCollisionTest::ray_hex_parity_test( ) { const bool vertex_ts[8] = { 0, 1, 1, 0, 0, 1, 1, 0 }; const bool vertex_us[8] = { 0, 0, 1, 1, 0, 0, 1, 1 }; const bool vertex_vs[8] = { 0, 0, 0, 0, 1, 1, 1, 1 }; Vec3d test_ray( m_ray ); double ray_len = mag( test_ray ); bool good_hit = false; unsigned int num_tries = 0; // bilinear patch faces of the mapped hex std::vector quads(6); quads[0] = Vec4ui( 0, 1, 3, 2 ); quads[1] = Vec4ui( 0, 1, 4, 5 ); quads[2] = Vec4ui( 1, 2, 5, 6 ); quads[3] = Vec4ui( 2, 3, 6, 7 ); quads[4] = Vec4ui( 3, 0, 7, 4 ); quads[5] = Vec4ui( 4, 5, 7, 6 ); // for debugging purposes, store the result of each hit test std::vector hits( 6, false ); // (t,u,v) coordinates of each vertex on the hexahedron while (!good_hit && num_tries++ < 10 ) { good_hit = true; bool any_origin_on_surface = false; // ray-cast against each quad for ( int i = 0; i < 6; ++i ) { const Vec4ui& quad = quads[i]; Vec4b ts( vertex_ts[quad[0]], vertex_ts[quad[1]], vertex_ts[quad[2]], vertex_ts[quad[3]] ); Vec4b us( vertex_us[quad[0]], vertex_us[quad[1]], vertex_us[quad[2]], vertex_us[quad[3]] ); Vec4b vs( vertex_vs[quad[0]], vertex_vs[quad[1]], vertex_vs[quad[2]], vertex_vs[quad[3]] ); bool edge_hit = false; bool origin_on_surface = false; hits[i] = ray_quad_intersection_parity( quad, ts, us, vs, Vec3d(0,0,0), test_ray, edge_hit, origin_on_surface ); if ( edge_hit ) { good_hit = false; } if ( origin_on_surface ) { any_origin_on_surface = true; } } if ( any_origin_on_surface ) { return true; } // check if any hit was not okay if ( !good_hit ) { double r = rand() / (double)RAND_MAX * 2.0 * M_PI; test_ray[0] = cos(r) * ray_len; test_ray[1] = -sin(r) * ray_len; } } if ( !good_hit ) { return true; } unsigned int num_hits = 0; for ( unsigned int i = 0; i < hits.size(); ++i ) { if ( hits[i] ) { ++num_hits; } } return ( num_hits % 2 == 1 ); } /// -------------------------------------------------------- /// /// For each triangle, form the plane it lies on, and determine if all m_interval_hex_vertices are on one side of the plane. /// /// -------------------------------------------------------- bool RootParityCollisionTest::plane_culling( const std::vector& triangles, const std::vector& boundary_vertices ) { std::size_t num_triangles = triangles.size(); std::size_t num_boundary_vertices = boundary_vertices.size(); for ( unsigned int i = 0; i < num_triangles; ++i ) { const Vec3ui& t = triangles[i]; Vec3d normal = cross( boundary_vertices[t[1]] - boundary_vertices[t[0]], boundary_vertices[t[2]] - boundary_vertices[t[0]] ); if ( mag(normal) == 0.0 ) { continue; } normal = normalized(normal); IntervalType::begin_special_arithmetic(); const int sgn = plane_sign( normal, m_interval_hex_vertices[0] ); IntervalType::end_special_arithmetic(); if ( sgn == 0 ) { continue; } bool all_same_side = true; for ( unsigned int v = 1; v < num_boundary_vertices; ++v ) { IntervalType::begin_special_arithmetic(); const int this_plane_sign = plane_sign( normal, m_interval_hex_vertices[v] ); IntervalType::end_special_arithmetic(); if ( this_plane_sign == 0 || this_plane_sign != sgn ) { all_same_side = false; break; } } if ( all_same_side ) { return true; } } IntervalType::end_special_arithmetic(); return false; } /// -------------------------------------------------------- /// /// Take a set of planes defined by the mapped domain boundary, and determine if all m_interval_hex_vertices on one side of /// any plane. /// /// -------------------------------------------------------- bool RootParityCollisionTest::edge_edge_interval_plane_culling() { std::vector hex_vertices(8); for ( unsigned int i = 0; i < 8; ++i ) { hex_vertices[i][0] = m_interval_hex_vertices[i][0].estimate(); hex_vertices[i][1] = m_interval_hex_vertices[i][1].estimate(); hex_vertices[i][2] = m_interval_hex_vertices[i][2].estimate(); } std::vector triangles(12); triangles[0] = Vec3ui(0,1,3); triangles[1] = Vec3ui(0,3,2); triangles[2] = Vec3ui(0,1,4); triangles[3] = Vec3ui(0,4,5); triangles[4] = Vec3ui(1,2,5); triangles[5] = Vec3ui(1,5,6); triangles[6] = Vec3ui(2,3,6); triangles[7] = Vec3ui(2,6,7); triangles[8] = Vec3ui(3,0,7); triangles[9] = Vec3ui(3,7,4); triangles[10] = Vec3ui(4,5,7); triangles[11] = Vec3ui(4,7,6); return plane_culling( triangles, hex_vertices ); } /// -------------------------------------------------------- /// /// Take a set of planes defined by the mapped domain boundary, and determine if all m_interval_hex_vertices lie on one side of /// any plane. /// /// -------------------------------------------------------- bool RootParityCollisionTest::point_triangle_interval_plane_culling() { std::vector hex_vertices(6); for ( unsigned int i = 0; i < 6; ++i ) { hex_vertices[i][0] = m_interval_hex_vertices[i][0].estimate(); hex_vertices[i][1] = m_interval_hex_vertices[i][1].estimate(); hex_vertices[i][2] = m_interval_hex_vertices[i][2].estimate(); } std::vector triangles(8); triangles[0] = Vec3ui(0,1,2); triangles[1] = Vec3ui(3,4,5); triangles[2] = Vec3ui(0,1,3); triangles[3] = Vec3ui(0,3,4); triangles[4] = Vec3ui(1,2,4); triangles[5] = Vec3ui(1,4,5); triangles[6] = Vec3ui(0,2,3); triangles[7] = Vec3ui(0,2,5); return plane_culling( triangles, hex_vertices ); } /// -------------------------------------------------------- /// /// Take a fixed set of planes and determine if all m_interval_hex_vertices lie on one side of any plane. /// /// -------------------------------------------------------- bool RootParityCollisionTest::fixed_plane_culling( unsigned int num_hex_vertices ) { for ( int i = -1; i < 1; ++i ) { for ( int j = -1; j < 1; ++j ) { for ( int k = -1; k < 1; ++k ) { Vec3i normal( i, k, j ); const int plane_sign = quick_1_plane_sign( normal, m_interval_hex_vertices[0] ); if ( plane_sign == 0 ) { continue; } bool all_same_side = true; for ( unsigned int v = 1; v < num_hex_vertices; ++v ) { const int this_plane_sign = quick_1_plane_sign( normal, m_interval_hex_vertices[v] ); if ( this_plane_sign == 0 || this_plane_sign != plane_sign ) { all_same_side = false; break; } } if ( all_same_side ) { return true; } } } } return false; } /// -------------------------------------------------------- /// /// Run edge-edge continuous collision detection /// /// -------------------------------------------------------- bool RootParityCollisionTest::edge_edge_collision( ) { static const bool vertex_ts[8] = { 0, 1, 1, 0, 0, 1, 1, 0 }; static const bool vertex_us[8] = { 0, 0, 1, 1, 0, 0, 1, 1 }; static const bool vertex_vs[8] = { 0, 0, 0, 0, 1, 1, 1, 1 }; // Get the transformed corners of the domain boundary in interval representation IntervalType::begin_special_arithmetic(); edge_edge_collision_function( m_x0old, m_x1old, m_x2old, m_x3old, m_x0new, m_x1new, m_x2new, m_x3new, vertex_ts[0], vertex_us[0], vertex_vs[0], m_interval_hex_vertices[0] ); edge_edge_collision_function( m_x0old, m_x1old, m_x2old, m_x3old, m_x0new, m_x1new, m_x2new, m_x3new, vertex_ts[1], vertex_us[1], vertex_vs[1], m_interval_hex_vertices[1] ); edge_edge_collision_function( m_x0old, m_x1old, m_x2old, m_x3old, m_x0new, m_x1new, m_x2new, m_x3new, vertex_ts[2], vertex_us[2], vertex_vs[2], m_interval_hex_vertices[2] ); edge_edge_collision_function( m_x0old, m_x1old, m_x2old, m_x3old, m_x0new, m_x1new, m_x2new, m_x3new, vertex_ts[3], vertex_us[3], vertex_vs[3], m_interval_hex_vertices[3] ); edge_edge_collision_function( m_x0old, m_x1old, m_x2old, m_x3old, m_x0new, m_x1new, m_x2new, m_x3new, vertex_ts[4], vertex_us[4], vertex_vs[4], m_interval_hex_vertices[4] ); edge_edge_collision_function( m_x0old, m_x1old, m_x2old, m_x3old, m_x0new, m_x1new, m_x2new, m_x3new, vertex_ts[5], vertex_us[5], vertex_vs[5], m_interval_hex_vertices[5] ); edge_edge_collision_function( m_x0old, m_x1old, m_x2old, m_x3old, m_x0new, m_x1new, m_x2new, m_x3new, vertex_ts[6], vertex_us[6], vertex_vs[6], m_interval_hex_vertices[6] ); edge_edge_collision_function( m_x0old, m_x1old, m_x2old, m_x3old, m_x0new, m_x1new, m_x2new, m_x3new, vertex_ts[7], vertex_us[7], vertex_vs[7], m_interval_hex_vertices[7] ); // Plane culling: check if all corners are on one side of the plane passing through the origin bool plane_culled = fixed_plane_culling(8); IntervalType::end_special_arithmetic(); bool hex_plane_culled = false; if ( !plane_culled ) { hex_plane_culled = edge_edge_interval_plane_culling(); } bool safe_parity = false; if ( !plane_culled && !hex_plane_culled ) { // Cast ray from origin against boundary image (6 quads) Vec3d xmin( 1e30 ), xmax( -1e30 ); for ( unsigned int i = 0; i < 8; ++i ) { Vec2d interval0 = m_interval_hex_vertices[i][0].get_actual_interval(); Vec2d interval1 = m_interval_hex_vertices[i][1].get_actual_interval(); Vec2d interval2 = m_interval_hex_vertices[i][2].get_actual_interval(); xmin[0] = std::min( xmin[0], interval0[0] ); xmin[1] = std::min( xmin[1], interval1[0] ); xmin[2] = std::min( xmin[2], interval2[0] ); xmax[0] = std::max( xmax[0], interval0[1] ); xmax[1] = std::max( xmax[1], interval1[1] ); xmax[2] = std::max( xmax[2], interval2[1] ); } const double ray_len = std::max( mag(xmin), mag(xmax) ) + 10.0; m_ray = Vec3d( ray_len, ray_len, 0 ); safe_parity = ray_hex_parity_test( ); } return safe_parity; } /// ---------------------------------------- /// /// Run point-triangle continuous collision detection /// /// ---------------------------------------- bool RootParityCollisionTest::point_triangle_collision( ) { static const bool vertex_ts[6] = { 0, 0, 0, 1, 1, 1 }; static const bool vertex_us[6] = { 0, 1, 0, 0, 1, 0 }; static const bool vertex_vs[6] = { 0, 0, 1, 0, 0, 1 }; // Get the transformed corners of the domain boundary in interval representation IntervalType::begin_special_arithmetic(); point_triangle_collision_function( m_x0old, m_x1old, m_x2old, m_x3old, m_x0new, m_x1new, m_x2new, m_x3new, vertex_ts[0], vertex_us[0], vertex_vs[0], m_interval_hex_vertices[0] ); point_triangle_collision_function( m_x0old, m_x1old, m_x2old, m_x3old, m_x0new, m_x1new, m_x2new, m_x3new, vertex_ts[1], vertex_us[1], vertex_vs[1], m_interval_hex_vertices[1] ); point_triangle_collision_function( m_x0old, m_x1old, m_x2old, m_x3old, m_x0new, m_x1new, m_x2new, m_x3new, vertex_ts[2], vertex_us[2], vertex_vs[2], m_interval_hex_vertices[2] ); point_triangle_collision_function( m_x0old, m_x1old, m_x2old, m_x3old, m_x0new, m_x1new, m_x2new, m_x3new, vertex_ts[3], vertex_us[3], vertex_vs[3], m_interval_hex_vertices[3] ); point_triangle_collision_function( m_x0old, m_x1old, m_x2old, m_x3old, m_x0new, m_x1new, m_x2new, m_x3new, vertex_ts[4], vertex_us[4], vertex_vs[4], m_interval_hex_vertices[4] ); point_triangle_collision_function( m_x0old, m_x1old, m_x2old, m_x3old, m_x0new, m_x1new, m_x2new, m_x3new, vertex_ts[5], vertex_us[5], vertex_vs[5], m_interval_hex_vertices[5] ); // Plane culling: check if all corners are on one side of the plane passing through the origin bool plane_culled = fixed_plane_culling(6); IntervalType::end_special_arithmetic(); if ( plane_culled ) { return false; } bool prism_plane_culled = point_triangle_interval_plane_culling(); if ( prism_plane_culled ) { return false; } // Cast ray from origin against boundary image (3 quads + 2 triangles) Vec3d xmin( 1e30 ), xmax( -1e30 ); for ( unsigned int i = 0; i < 6; ++i ) { Vec2d interval0 = m_interval_hex_vertices[i][0].get_actual_interval(); Vec2d interval1 = m_interval_hex_vertices[i][1].get_actual_interval(); Vec2d interval2 = m_interval_hex_vertices[i][2].get_actual_interval(); xmin[0] = std::min( xmin[0], interval0[0] ); xmin[1] = std::min( xmin[1], interval1[0] ); xmin[2] = std::min( xmin[2], interval2[0] ); xmax[0] = std::max( xmax[0], interval0[1] ); xmax[1] = std::max( xmax[1], interval1[1] ); xmax[2] = std::max( xmax[2], interval2[1] ); } const double ray_len = std::max( mag(xmin), mag(xmax) ) + 10.0; m_ray = Vec3d( ray_len, ray_len, 0 ); bool safe_parity = ray_prism_parity_test( ); return safe_parity; } } // namespace rootparity }