27 #ifndef MPBLOCKS_GJK_H_
28 #define MPBLOCKS_GJK_H_
39 template <
typename T>
int sgn(T val) {
40 return (T(0) < val) - (val < T(0));
44 template <
class Po
int>
69 template <
class Po
int>
70 using PairVec = std::vector< MinkowskiPair<Point> >;
74 template <
class Ops,
class Po
int >
77 Point& b = simplex[0].d;
78 Point& a = simplex[1].d;
83 if( ops.dot( ab,ao ) > 0 )
86 if( ops.threshold( ab,ao ) )
90 dir = ops.cross( ops.cross( ab, ao ), ab );
94 simplex[0] = simplex[1];
102 template <
class Ops,
class Po
int >
106 Point& v2 = simplex[0].d;
107 Point& v1 = simplex[1].d;
108 Point& v0 = simplex[2].d;
116 if( (ops.dot( r_01, r_o ) < 0) && (ops.dot( r_02, r_o ) < 0) )
118 simplex[0] = simplex[2];
125 Point f_012 = ops.cross( r_01, r_02 );
128 Point e_01 = ops.cross( r_01, f_012 );
129 Point e_02 = ops.cross( f_012, r_02 );
131 auto test_e_01 = ops.dot( e_01, r_o );
132 auto test_e_02 = ops.dot( e_02, r_o );
135 if( (test_e_01 < 0) && (test_e_02 < 0) )
139 if( ops.threshold( v0,v1,v2 ) )
143 if( ops.dot( f_012, r_o ) > 0 )
152 std::swap( simplex[0], simplex[1] );
162 simplex[0] = simplex[1];
163 simplex[1] = simplex[2];
165 dir = ops.cross( ops.cross( r_01, r_o ), r_01 );
170 simplex[1] = simplex[2];
172 dir = ops.cross( ops.cross( r_02, r_o ), r_02 );
182 template <
class Ops,
class Po
int >
185 Point& v3 = simplex[0].d;
186 Point& v2 = simplex[1].d;
187 Point& v1 = simplex[2].d;
188 Point& v0 = simplex[3].d;
196 if( ops.dot(r3,ro) < 0
197 && ops.dot(r2,ro) < 0
198 && ops.dot(r1,ro) < 0 )
200 simplex[0] = simplex[3];
206 Point f_12 = ops.cross(r1,r2);
207 Point f_23 = ops.cross(r2,r3);
208 Point f_31 = ops.cross(r3,r1);
210 auto test_f_12 = ops.dot(f_12,ro);
211 auto test_f_23 = ops.dot(f_23,ro);
212 auto test_f_31 = ops.dot(f_31,ro);
223 Point e_21 = ops.cross(f_12, r2);
224 Point e_23 = ops.cross(r2, f_23);
225 Point e_13 = ops.cross(f_31, r1);
226 Point e_12 = ops.cross(r1, f_12);
227 Point e_32 = ops.cross(f_23, r3);
228 Point e_31 = ops.cross(r3, f_31);
230 auto test_21 = ops.dot( e_21, ro );
231 auto test_23 = ops.dot( e_23, ro );
232 auto test_13 = ops.dot( e_13, ro );
233 auto test_12 = ops.dot( e_12, ro );
234 auto test_32 = ops.dot( e_32, ro );
235 auto test_31 = ops.dot( e_31, ro );
238 if( test_12 > 0 && test_13 > 0 )
240 simplex[0] = simplex[2];
241 simplex[1] = simplex[3];
243 dir = ops.cross( ops.cross (r1, ro ), r1 );
246 else if( test_23 > 0 && test_21 > 0 )
248 simplex[0] = simplex[1];
249 simplex[1] = simplex[3];
251 dir = ops.cross( ops.cross (r2, ro ), r2 );
254 else if( test_32 > 0 && test_31 > 0)
256 simplex[1] = simplex[3];
258 dir = ops.cross( ops.cross (r3, ro ), r3 );
261 else if( test_f_12 > 0 && test_12 < 0 && test_21 < 0 )
263 simplex[0] = simplex[1];
264 simplex[1] = simplex[2];
265 simplex[2] = simplex[3];
270 else if( test_f_23 > 0 && test_23 < 0 && test_32 < 0 )
272 simplex[2] = simplex[3];
279 simplex[1] = simplex[2];
280 simplex[2] = simplex[3];
294 template <
class Ops,
class Po
int >
297 switch(simplex.size())
312 assert(!
"GJK: attempting to advance an overfull simplex");
364 template <
class Ops,
class SupportFn,
class Po
int>
366 Point& a, Point& b, Point& d,
int maxIter=100 )
369 typedef std::vector<MPair> PointVec;
374 simplex.emplace_back( a, b );
376 while( maxIter-- > 0 )
379 if( ops.dot( d,(a-b) ) < 0 )
381 simplex.emplace_back( a, b );
413 template <
class Ops,
class Po
int >
416 Point& b = simplex[0].d;
417 Point& a = simplex[1].d;
421 Point ab_n = ops.normalize(ab);
423 auto d_ab = ops.dot( -a, ab_n );
426 Point c = a + d_ab * ab_n;
431 simplex[0] = simplex[1];
439 template <
class Ops,
class Po
int >
443 Point& v2 = simplex[0].d;
444 Point& v1 = simplex[1].d;
445 Point& v0 = simplex[2].d;
448 if( ops.containsOrigin(v0,v1,v2) )
452 Point r_01 = ops.normalize(v1-v0);
453 Point r_02 = ops.normalize(v2-v0);
457 auto p_01 = ops.dot(r_01,r_o);
458 auto p_02 = ops.dot(r_02,r_o);
461 if( p_01 < 0 && p_02 < 0 )
463 simplex[0] = simplex[2];
471 v = (v0 + p_01*ops.normalize(r_01));
476 v = (v0 + p_02*ops.normalize(r_02));
477 simplex[1] = simplex[2];
484 template <
class Ops,
class Po
int >
488 Point& v2 = simplex[0].d;
489 Point& v1 = simplex[1].d;
490 Point& v0 = simplex[2].d;
493 Point r_01 = ops.normalize(v1-v0);
494 Point r_02 = ops.normalize(v2-v0);
497 Point n = ops.normalize( ops.cross(r_01,r_02) );
498 auto f = ops.dot(n,v0);
523 Point bxo = ops.normalize( ops.cross(r_01,r_op) );
524 Point oxc = ops.normalize( ops.cross(r_op,r_02) );
525 Point bxc = ops.normalize( ops.cross(r_01,r_02) );
530 if(
sgn( ops.dot(bxo,oxc) ) > 0 &&
sgn( ops.dot(bxo,bxc) ) > 0 )
535 auto p_01 = ops.dot(r_01,r_o);
536 auto p_02 = ops.dot(r_02,r_o);
539 if( p_01 < 0 && p_02 < 0 )
541 simplex[0] = simplex[2];
549 v = (v0 + p_01*ops.normalize(r_01));
550 simplex[0] = simplex[1];
551 simplex[1] = simplex[2];
556 v = (v0 + p_02*ops.normalize(r_02));
557 simplex[1] = simplex[2];
566 template <
class Ops,
class Po
int >
570 Point& v3 = simplex[0].d;
571 Point& v2 = simplex[1].d;
572 Point& v1 = simplex[2].d;
573 Point& v0 = simplex[3].d;
577 Point r12 = ops.normalize(v2-v1);
578 Point r13 = ops.normalize(v3-v1);
579 if( ops.dot( ops.cross(r12,r13), v0-v1 ) < 0 )
581 std::swap(simplex[0],simplex[2]);
585 simplex[0] = simplex[3];
592 Point r3 = ops.normalize(v3-v0);
593 Point r2 = ops.normalize(v2-v0);
594 Point r1 = ops.normalize(v1-v0);
598 auto p_1 = ops.dot(ro,r1);
599 auto p_2 = ops.dot(ro,r2);
600 auto p_3 = ops.dot(ro,r3);
604 if( p_1 < 0 && p_2 < 0 && p_3 < 0 )
606 simplex[0] = simplex[3];
615 Point n_12 = ops.normalize( ops.cross(r1,r2) );
616 Point n_23 = ops.normalize( ops.cross(r2,r3) );
617 Point n_31 = ops.normalize( ops.cross(r3,r1) );
619 auto f_12 = ops.dot(n_12,ro);
620 auto f_23 = ops.dot(n_23,ro);
621 auto f_31 = ops.dot(n_31,ro);
625 if( f_12 < 0 && f_23 < 0 && f_31 < 0 )
632 Point n_12_2 = ops.normalize( ops.cross(n_12, r2) );
633 Point n_23_2 = ops.normalize( ops.cross(r2, n_23) );
634 Point n_31_1 = ops.normalize( ops.cross(n_31, r1) );
635 Point n_12_1 = ops.normalize( ops.cross(r1, n_12) );
636 Point n_23_3 = ops.normalize( ops.cross(n_23, r3) );
637 Point n_31_3 = ops.normalize( ops.cross(r3, n_31) );
640 auto f_12_2 = ops.dot( n_12_2, ro );
641 auto f_23_2 = ops.dot( n_23_2, ro );
642 auto f_31_1 = ops.dot( n_31_1, ro );
643 auto f_12_1 = ops.dot( n_12_1, ro );
644 auto f_23_3 = ops.dot( n_23_3, ro );
645 auto f_31_3 = ops.dot( n_31_3, ro );
648 if( f_12_1 > 0 && f_31_1 > 0 )
650 simplex[0] = simplex[2];
651 simplex[1] = simplex[3];
657 else if( f_12_2 > 0 && f_23_2 > 0 )
659 simplex[0] = simplex[1];
660 simplex[1] = simplex[3];
666 else if( f_31_3 > 0 && f_23_3 > 0)
668 simplex[1] = simplex[3];
674 else if( f_12 > 0 && f_12_1 < 0 && f_12_2 < 0 )
676 simplex[0] = simplex[1];
677 simplex[1] = simplex[2];
678 simplex[2] = simplex[3];
680 v = ops.dot(v0,n_12)*n_12;
684 else if( f_23 > 0 && f_23_2 < 0 && f_23_3 < 0 )
686 simplex[2] = simplex[3];
688 v = ops.dot(v0,n_23)*n_23;
693 simplex[1] = simplex[2];
694 simplex[2] = simplex[3];
696 v = ops.dot(v0,n_31)*n_31;
708 template <
class Ops,
class Po
int >
711 switch(simplex.size())
722 assert(!
"GJK: attempting to advance an overfull simplex");
730 template <
class Ops,
class Po
int >
734 switch(simplex.size())
749 assert(!
"GJK: attempting to advance an overfull simplex");
762 template <
class Ops,
class SupportFn,
class Point,
763 class SimplexHistory,
766 Point& a, Point& b, Point& v,
767 SimplexHistory sHist,
768 PointHistory vHist,
int maxIter=100 )
774 simplex.push_back( MPair(a,b) );
777 *(sHist++) = simplex;
780 while( maxIter-- > 0 )
783 if( std::abs( ops.dot(v,v) + ops.dot( -v,(a-b) ) ) < 1e-6 )
786 simplex.push_back( MPair(a,b) );
787 *(sHist++) = simplex;
799 template<
int NDim,
class Po
int >
800 bool isEqual(
const Point& a,
const Point& b )
802 for(
int i=0; i < NDim; i++)
809 template <
class Ops,
class SupportFn,
class Po
int>
811 Point& a, Point& b, Point& v,
int maxIter=100 )
817 simplex.push_back( MPair(a,b) );
820 while( maxIter-- > 0 )
823 if( std::abs( ops.dot(v,v) + ops.dot( -v,(a-b) ) ) < 1e-6 )
827 for(
auto& m : simplex )
828 if( isEqual<3>(m.d,newPair.d) )
831 simplex.push_back( newPair );
842 template <
class Ops,
class SupportFn,
class Point,
843 class SimplexHistory,
847 Point& a, Point& b, Point& v,
848 SimplexHistory sHist,
850 ErrorHistory eHist,
int maxIter=100 )
856 simplex.push_back( MPair(a,b) );
859 *(sHist++) = simplex;
863 while( maxIter-- > 0 )
866 auto e = ops.dot(v,v) + ops.dot( -v,(a-b) );
868 if( std::abs( e ) < 1e-6 )
870 *(sHist++) = simplex;
876 for(
auto& m : simplex )
878 if( isEqual<3>(m.d,newPair.d) )
880 *(sHist++) = simplex;
885 simplex.push_back( newPair );
886 *(sHist++) = simplex;
bool advanceSimplex3(Ops &ops, PairVec< Point > &simplex, Point &dir)
returns true if the origin is contained in the triangle
bool growSimplex3_2d(Ops &ops, PairVec< Point > &simplex, Point &v)
returns true if the origin is contained in the triangle
bool advanceSimplex(Ops &ops, std::vector< MinkowskiPair< Point > > &simplex, Point &dir)
returns true if the origin is contained in the simplex, and if it is not, returns false and generates...
std::vector< MinkowskiPair< Point > > PairVec
bool advanceSimplex2(Ops &ops, PairVec< Point > &simplex, Point &dir)
returns true if the origin is contained in the segment
Result collisionDistance_3d_debug(Ops ops, SupportFn supportFn, Point &a, Point &b, Point &v, SimplexHistory sHist, PointHistory vHist, ErrorHistory eHist, int maxIter=100)
bool growSimplex4_3d(Ops &ops, PairVec< Point > &simplex, Point &v, int depth=0)
returns true if the origin is contained in the tetrahedron
Result collisionDistance_3d(Ops ops, SupportFn supportFn, Point &a, Point &b, Point &v, int maxIter=100)
MinkowskiPair(const Point &a, const Point &b)
bool growSimplex2(Ops &ops, PairVec< Point > &simplex, Point &v)
returns true if the origin is contained in the segment
bool growSimplex3_3d(Ops &ops, PairVec< Point > &simplex, Point &v)
returns true if the origin is contained in the triangle
bool growSimplex_2d(Ops &ops, std::vector< MinkowskiPair< Point > > &simplex, Point &v)
returns true if the origin is contained in the simplex, and if it is not, returns false and generates...
bool advanceSimplex4(Ops &ops, PairVec< Point > &simplex, Point &dir)
returns true if the origin is contained in the tetrahedron
bool isEqual(const Point &a, const Point &b)
Result collisionDistance_2d_debug(Ops ops, SupportFn supportFn, Point &a, Point &b, Point &v, SimplexHistory sHist, PointHistory vHist, int maxIter=100)
bool growSimplex_3d(Ops &ops, std::vector< MinkowskiPair< Point > > &simplex, Point &v)
returns true if the origin is contained in the simplex, and if it is not, returns false and generates...
Result isCollision(Ops ops, SupportFn supportFn, Point &a, Point &b, Point &d, int maxIter=100)
GJK algorithm, determines if two convex objects are in collision.