PeriDyno 1.2.1
Loading...
Searching...
No Matches
CollisionDetectionAlgorithm.inl
Go to the documentation of this file.
1#include "Platform.h"
3#include "Vector/Vector3D.h"
4#include "ComputeGeometry.h"
5
6namespace dyno
7{
8
9 #define REAL_infinity 1.0e30
10 #define REAL_EQUAL(a,b) (((a < b + EPSILON) && (a > b - EPSILON)) ? true : false)
11 #define REAL_GREAT(a,b) ((a > EPSILON + b)? true: false)
12 #define REAL_LESS(a,b) ((a + EPSILON < b)? true: false)
13
15 {
17 };
18
19 template<typename Real>
20 DYN_FUNC float fsign(Real v)
21 {
22 return v < 0 ? -Real(1) : Real(1);
23 }
24
25 template<typename Real>
27 {
28 m.normal = -m.normal;
29
30 for (uint i = 0; i < m.contactCount; i++) {
31 m.contacts[i].position += m.contacts[i].penetration * m.normal;
32 }
33 }
34
35 //--------------------------------------------------------------------------------------------------
36 // qBoxtoBox
37 //--------------------------------------------------------------------------------------------------
38 template<typename Real>
39 DYN_FUNC inline bool trackFaceAxis(int& axis, Real& sMax, Vector<Real, 3>& axisNormal, int n, Real s, const Vector<Real, 3>& normal)
40 {
41 if (s > Real(0))
42 return true;
43
44 if (s > sMax)
45 {
46 sMax = s;
47 axis = n;
48 axisNormal = normal;
49 }
50
51 return false;
52 }
53
54 //--------------------------------------------------------------------------------------------------
55 template<typename Real>
56 DYN_FUNC inline bool trackEdgeAxis(int& axis, Real& sMax, Vector<Real, 3>& axisNormal, int n, Real s, const Vector<Real, 3>& normal)
57 {
58 if (s > Real(0))
59 return true;
60
61 Real l = Real(1) / normal.norm();
62 s *= l;
63
64 if (s > sMax)
65 {
66 sMax = s;
67 axis = n;
68 axisNormal = normal * l;
69 }
70
71 return false;
72 }
73
74
92 template<typename Real>
93 //--------------------------------------------------------------------------------------------------
94 DYN_FUNC void computeReferenceEdgesAndBasis(unsigned char* out, SquareMatrix<Real, 3>* basis, Vector<Real, 3>* e, const Vector<Real, 3>& eR, const Transform<Real, 3>& rtx, Vector<Real, 3> n, int axis)
95 {
96 n = rtx.rotation().transpose()*n;
97
98 if (axis >= 3)
99 axis -= 3;
100
101 auto rot_t = rtx.rotation();
103
104 switch (axis)
105 {
106 case 0:
107 if (n.x > Real(0.0))
108 {
109 out[0] = 1;
110 out[1] = 8;
111 out[2] = 7;
112 out[3] = 9;
113
114 *e = Vector<Real, 3>(eR.y, eR.z, eR.x);
115 //basis->SetRows(rtx.rotation.ey, rtx.rotation.ez, rtx.rotation.ex);
116 outB.setCol(0, rot_t.col(1));
117 outB.setCol(1, rot_t.col(2));
118 outB.setCol(2, rot_t.col(0));
119 }
120 else
121 {
122 out[0] = 11;
123 out[1] = 3;
124 out[2] = 10;
125 out[3] = 5;
126
127 *e = Vector<Real, 3>(eR.z, eR.y, eR.x);
128 //basis->SetRows(rtx.rotation.ez, rtx.rotation.ey, -rtx.rotation.ex);
129 outB.setCol(0, rot_t.col(2));
130 outB.setCol(1, rot_t.col(1));
131 outB.setCol(2, -rot_t.col(0));
132 }
133 break;
134
135 case 1:
136 if (n.y > Real(0.0))
137 {
138 out[0] = 0;
139 out[1] = 1;
140 out[2] = 2;
141 out[3] = 3;
142
143 *e = Vector<Real, 3>(eR.z, eR.x, eR.y);
144 //basis->SetRows(rtx.rotation.ez, rtx.rotation.ex, rtx.rotation.ey);
145 outB.setCol(0, rot_t.col(2));
146 outB.setCol(1, rot_t.col(0));
147 outB.setCol(2, rot_t.col(1));
148 }
149 else
150 {
151 out[0] = 4;
152 out[1] = 5;
153 out[2] = 6;
154 out[3] = 7;
155
156 *e = Vector<Real, 3>(eR.z, eR.x, eR.y);
157 //basis->SetRows(rtx.rotation.ez, -rtx.rotation.ex, -rtx.rotation.ey);
158 outB.setCol(0, rot_t.col(2));
159 outB.setCol(1, -rot_t.col(0));
160 outB.setCol(2, -rot_t.col(1));
161 }
162 break;
163
164 case 2:
165 if (n.z > Real(0.0))
166 {
167 out[0] = 11;
168 out[1] = 4;
169 out[2] = 8;
170 out[3] = 0;
171
172 *e = Vector<Real, 3>(eR.y, eR.x, eR.z);
173 //basis->SetRows(-rtx.rotation.ey, rtx.rotation.ex, rtx.rotation.ez);
174 outB.setCol(0, -rot_t.col(1));
175 outB.setCol(1, rot_t.col(0));
176 outB.setCol(2, rot_t.col(2));
177 }
178 else
179 {
180 out[0] = 6;
181 out[1] = 10;
182 out[2] = 2;
183 out[3] = 9;
184
185 *e = Vector<Real, 3>(eR.y, eR.x, eR.z);
186 //basis->SetRows(-rtx.rotation.ey, -rtx.rotation.ex, -rtx.rotation.ez);
187 outB.setCol(0, -rot_t.col(1));
188 outB.setCol(1, -rot_t.col(0));
189 outB.setCol(2, -rot_t.col(2));
190 }
191 break;
192 }
193
194 *basis = outB;
195 }
196
197 //--------------------------------------------------------------------------------------------------
198 template<typename Real>
200 {
201 n = -itx.rotation().transpose()*n;
202 Vector<Real, 3> absN = abs(n);
203
204 if (absN.x > absN.y && absN.x > absN.z)
205 {
206 if (n.x > Real(0.0))
207 {
208 out[0].v = Vector<Real, 3>(e.x, e.y, -e.z);
209 out[1].v = Vector<Real, 3>(e.x, e.y, e.z);
210 out[2].v = Vector<Real, 3>(e.x, -e.y, e.z);
211 out[3].v = Vector<Real, 3>(e.x, -e.y, -e.z);
212 }
213 else
214 {
215 out[0].v = Vector<Real, 3>(-e.x, -e.y, e.z);
216 out[1].v = Vector<Real, 3>(-e.x, e.y, e.z);
217 out[2].v = Vector<Real, 3>(-e.x, e.y, -e.z);
218 out[3].v = Vector<Real, 3>(-e.x, -e.y, -e.z);
219 }
220 }
221 else if (absN.y > absN.x && absN.y > absN.z)
222 {
223 if (n.y > Real(0.0))
224 {
225 out[0].v = Vector<Real, 3>(-e.x, e.y, e.z);
226 out[1].v = Vector<Real, 3>(e.x, e.y, e.z);
227 out[2].v = Vector<Real, 3>(e.x, e.y, -e.z);
228 out[3].v = Vector<Real, 3>(-e.x, e.y, -e.z);
229 }
230 else
231 {
232 out[0].v = Vector<Real, 3>(e.x, -e.y, e.z);
233 out[1].v = Vector<Real, 3>(-e.x, -e.y, e.z);
234 out[2].v = Vector<Real, 3>(-e.x, -e.y, -e.z);
235 out[3].v = Vector<Real, 3>(e.x, -e.y, -e.z);
236 }
237 }
238 else
239 {
240 if (n.z > Real(0.0))
241 {
242 out[0].v = Vector<Real, 3>(-e.x, e.y, e.z);
243 out[1].v = Vector<Real, 3>(-e.x, -e.y, e.z);
244 out[2].v = Vector<Real, 3>(e.x, -e.y, e.z);
245 out[3].v = Vector<Real, 3>(e.x, e.y, e.z);
246 }
247 else
248 {
249 out[0].v = Vector<Real, 3>(e.x, -e.y, -e.z);
250 out[1].v = Vector<Real, 3>(-e.x, -e.y, -e.z);
251 out[2].v = Vector<Real, 3>(-e.x, e.y, -e.z);
252 out[3].v = Vector<Real, 3>(e.x, e.y, -e.z);
253 }
254 }
255
256 for (int i = 0; i < 4; ++i)
257 out[i].v = itx * out[i].v;
258 }
259
260 //--------------------------------------------------------------------------------------------------
261#define InFront( a ) \
262 ((a) < float( 0.0 ))
263
264#define Behind( a ) \
265 ((a) >= float( 0.0 ))
266
267#define On( a ) \
268 ((a) < float( 0.005 ) && (a) > -float( 0.005 ))
269
270 template<typename Real>
271 DYN_FUNC int orthographic(ClipVertex* out, Real sign, Real e, int axis, int clipEdge, ClipVertex* in, int inCount)
272 {
273 int outCount = 0;
274 ClipVertex a = in[inCount - 1];
275
276 for (int i = 0; i < inCount; ++i)
277 {
278 ClipVertex b = in[i];
279
280 Real da = sign * a.v[axis] - e;
281 Real db = sign * b.v[axis] - e;
282
283 ClipVertex cv;
284
285 // B
286 if (On(da) || On(db))
287 {
288 if (InFront(db) || On(db))
289 out[outCount++] = b;
290 }
291 else if ((InFront(da) && InFront(db)))
292 {
293 out[outCount++] = b;
294 }
295 // I
296 else if (InFront(da) && Behind(db))
297 {
298 cv.v = a.v + (b.v - a.v) * (da / (da - db));
299 out[outCount++] = cv;
300 }
301 else if (Behind(da) && InFront(db))
302 {
303 //Remove the duplicated point in case inCount == 2
304 if (inCount > 2) {
305 cv.v = a.v + (b.v - a.v) * (da / (da - db));
306 out[outCount++] = cv;
307 }
308 out[outCount++] = b;
309 }
310
311 a = b;
312 }
313
314 return outCount;
315 }
316
317 //--------------------------------------------------------------------------------------------------
318 // Resources (also see q3BoxtoBox's resources):
319 template<typename Real>
320 DYN_FUNC int clip(ClipVertex* outVerts, float* outDepths, const Vector<Real, 3>& rPos, const Vector<Real, 3>& e, unsigned char* clipEdges, const SquareMatrix<Real, 3>& basis, ClipVertex* incident)
321 {
322 int inCount = 4;
323 int outCount;
324 ClipVertex in[8];
325 ClipVertex out[8];
326
327 for (int i = 0; i < 4; ++i)
328 in[i].v = basis.transpose()*(incident[i].v - rPos);
329
330 outCount = orthographic(out, Real(1.0), e.x, 0, clipEdges[0], in, inCount);
331
332 if (outCount == 0)
333 return 0;
334
335 inCount = orthographic(in, Real(1.0), e.y, 1, clipEdges[1], out, outCount);
336
337 if (inCount == 0)
338 return 0;
339
340 outCount = orthographic(out, Real(-1.0), e.x, 0, clipEdges[2], in, inCount);
341
342 if (outCount == 0)
343 return 0;
344
345 inCount = orthographic(in, Real(-1.0), e.y, 1, clipEdges[3], out, outCount);
346
347 // Keep incident vertices behind the reference face
348 outCount = 0;
349 for (int i = 0; i < inCount; ++i)
350 {
351 Real d = in[i].v.z - e.z;
352
353 if (d <= Real(0.0))
354 {
355 outVerts[outCount].v = basis * in[i].v + rPos;
356 outDepths[outCount++] = d;
357 }
358 }
359
360 //assert(outCount <= 8);
361
362 return outCount;
363 }
364
365 template<typename Real>
366 DYN_FUNC int clipEdgeAgainstRectangle(ClipVertex* outVerts, float* outDepths, const Vector<Real, 3>& rPos, const Vector<Real, 3>& e, unsigned char* clipEdges, const SquareMatrix<Real, 3>& basis, ClipVertex* incident)
367 {
368 int inCount = 2;
369 int outCount;
370 ClipVertex in[2];
371 ClipVertex out[2];
372
373 for (int i = 0; i < inCount; ++i)
374 in[i].v = basis.transpose() * (incident[i].v - rPos);
375
376 outCount = orthographic(out, Real(1.0), e.x, 0, clipEdges[0], in, inCount);
377
378 if (outCount == 0)
379 return 0;
380
381 inCount = orthographic(in, Real(1.0), e.y, 1, clipEdges[1], out, outCount);
382
383 if (inCount == 0)
384 return 0;
385
386 outCount = orthographic(out, Real(-1.0), e.x, 0, clipEdges[2], in, inCount);
387
388 if (outCount == 0)
389 return 0;
390
391 inCount = orthographic(in, Real(-1.0), e.y, 1, clipEdges[3], out, outCount);
392
393 // Keep incident vertices behind the reference face
394 outCount = 0;
395 for (int i = 0; i < inCount; ++i)
396 {
397 Real d = in[i].v.z - e.z;
398
399 if (d <= Real(0.0))
400 {
401 outVerts[outCount].v = basis * in[i].v + rPos;
402 outDepths[outCount++] = d;
403 }
404 }
405
406 return outCount;
407 }
408
409 //--------------------------------------------------------------------------------------------------
410 template<typename Real>
411 DYN_FUNC inline void edgesContact(Vector<Real, 3>& CA, Vector<Real, 3>& CB, const Vector<Real, 3>& PA, const Vector<Real, 3>& QA, const Vector<Real, 3>& PB, const Vector<Real, 3>& QB)
412 {
413 Vector<Real, 3> DA = QA - PA;
414 Vector<Real, 3> DB = QB - PB;
415 Vector<Real, 3> r = PA - PB;
416 Real a = DA.dot(DA);
417 Real e = DB.dot(DB);
418 Real f = DB.dot(r);
419 Real c = DA.dot(r);
420
421 Real b = DA.dot(DB);
422 Real denom = a * e - b * b;
423
424 Real TA = (b * f - c * e) / denom;
425 Real TB = (b * TA + f) / e;
426
427 CA = PA + DA * TA;
428 CB = PB + DB * TB;
429 }
430
431 // ---------------------------------------- [ MSDF ] ----------------------------------------
432 template<typename Real>
433 DYN_FUNC inline void checkSignedDistance(
434 Real lowerBoundaryA,
435 Real upperBoundaryA, // A
436 Real lowerBoundaryB,
437 Real upperBoundaryB, // B
438 Real& intersectionDistance, // +:outside -:inside
439 Real& boundaryA, // A
440 Real& boundaryB // B
441 )
442 {
443 if (!((lowerBoundaryA > upperBoundaryB) || (lowerBoundaryB > upperBoundaryA)))
444 {
445 // boundaryB < boundaryA :B (->) [default: N]
446 // boundaryA < boundaryB :B (<-) [-N]
447 if (lowerBoundaryA < lowerBoundaryB)
448 {
449 if (upperBoundaryA > upperBoundaryB)
450 {
451 // |---B---|
452 // |-----A-----|
453 if (upperBoundaryB - lowerBoundaryA > upperBoundaryA - lowerBoundaryB)
454 {
455 // |---B---|(->)
456 // |-----A-----|
457 boundaryA = upperBoundaryA;
458 boundaryB = lowerBoundaryB;
459 intersectionDistance = - (upperBoundaryA - lowerBoundaryB);
460 }
461 else
462 {
463 // (<-)|---B---|
464 // |-----A-----|
465 boundaryA = lowerBoundaryA;
466 boundaryB = upperBoundaryB;
467 intersectionDistance = - (upperBoundaryB - lowerBoundaryA);
468 }
469 }
470 else
471 {
472 // |---B---|(->)
473 // |----A----|
474 boundaryA = upperBoundaryA;
475 boundaryB = lowerBoundaryB;
476 intersectionDistance = - (upperBoundaryA - lowerBoundaryB);
477 }
478 }
479 else
480 {
481 if (upperBoundaryA > upperBoundaryB)
482 {
483 // (<-)|---B---|
484 // |----A----|
485 boundaryA = lowerBoundaryA;
486 boundaryB = upperBoundaryB;
487 intersectionDistance = - (upperBoundaryB - lowerBoundaryA);
488 }
489 else
490 {
491 // |-----B------|
492 // |---A---|
493 //intersectionDistance = upperBoundaryA - lowerBoundaryA;
494 if (upperBoundaryB - lowerBoundaryA > upperBoundaryA - lowerBoundaryB)
495 {
496 // |-----B-----|(->)
497 // |---A---|
498 boundaryA = upperBoundaryA;
499 boundaryB = lowerBoundaryB;
500 intersectionDistance = - (upperBoundaryA - lowerBoundaryB);
501 }
502 else
503 {
504 // (<-)|------B------|
505 // |---A---|
506 boundaryA = lowerBoundaryA;
507 boundaryB = upperBoundaryB;
508 intersectionDistance = - (upperBoundaryB - lowerBoundaryA);
509 }
510 }
511 }
512 }
513 else
514 {
515 // boundaryA < boundaryB :B (->) [default: N]
516 // boundaryB < boundaryA :B (<-) [-N]
517 // |---A---| (->) |---B---|
518 if (upperBoundaryA < lowerBoundaryB)
519 {
520 boundaryA = upperBoundaryA;
521 boundaryB = lowerBoundaryB;
522 intersectionDistance = (lowerBoundaryB - upperBoundaryA);
523 }
524 // |---B---| (<-) |---A---|
525 if (upperBoundaryB < lowerBoundaryA)
526 {
527 boundaryA = lowerBoundaryA;
528 boundaryB = upperBoundaryB;
529 intersectionDistance = (lowerBoundaryA - upperBoundaryB);
530 }
531 }
532 }
533
534 template<typename Real>
535 DYN_FUNC inline bool checkPointInBoundary(const Vec3f& p, const Vec3f& N, const Real& b, const Real& r)
536 {
537 Real c = p.dot(N);
538 return (!REAL_GREAT(c, b + r) && !REAL_LESS(c, b - r));
539 };
540
541 template<typename Real>
542 DYN_FUNC inline void updateSDF(
543 Real& boundaryA,
544 Real& boundaryB,
545 Real& depth,
546 Vec3f& normal,
547 Real currentBoundaryA,
548 Real currentBoundaryB,
549 Real currentDepth,
550 Vec3f currentN
551 )
552 {
553 // SDF Calculate on Convex Hull
554 // - : minimum distance
555 // + : maximum distance
556 currentN = ( (currentBoundaryB < currentBoundaryA) ^ (REAL_LESS(currentDepth, 0)) ) ? -currentN : currentN;
557 if (REAL_LESS(currentDepth, 0) && REAL_GREAT(currentDepth , depth))
558 {
559 depth = currentDepth;
560 normal = currentN;
561 boundaryA = currentBoundaryA;
562 boundaryB = currentBoundaryB;
563 }
564 }
565
566 template<typename Real, typename ShapeA, typename ShapeB>
567 DYN_FUNC inline void checkSignedDistanceAxis(Real& intersectionDistance, Real& BoundaryA, Real& BoundaryB, const Vec3f axisNormal, ShapeA& shapeA, ShapeB& shapeB, const Real radiusA, const Real radiusB)
568 {
569 // Contact normal on B
570 Real lowerBoundaryA, upperBoundaryA, lowerBoundaryB, upperBoundaryB;
571
572 // projection to axis
573 projectOnAxis(lowerBoundaryA, upperBoundaryA, axisNormal, shapeA, radiusA);
574 projectOnAxis(lowerBoundaryB, upperBoundaryB, axisNormal, shapeB, radiusB);
575
576 checkSignedDistance(lowerBoundaryA, upperBoundaryA, lowerBoundaryB, upperBoundaryB, intersectionDistance, BoundaryA, BoundaryB);
577 }
578
579
580 template<typename Real, typename ShapeA, typename ShapeB>
581 DYN_FUNC inline void checkAxisPoint(
583 ShapeA& shapeA,
584 ShapeB& shapeB,
585 const Real radiusA,
586 const Real radiusB,
587 Vec3f pA,
588 Vec3f pB,
589 const Real rA = 0.f,
590 const Real rB = 0.f // for Sphere
591 )
592 {
593 Vec3f N = pB - pA;
594 Real D = 0;
595 Real bA, bB;
596 if (N.norm() > EPSILON) N /= N.norm(); else return;
597 checkSignedDistanceAxis(D, bA, bB, N, shapeA, shapeB, radiusA, radiusB);
598
599 if (!checkPointInBoundary(pA, N, bA, radiusA + rA) || !checkPointInBoundary(pB, N, bB, radiusB + rB)) return;
600 sat.update(SeparationType::CT_POINT, bA, bB, D, N, pA, pB);
601 }
602
603
604 template<typename Real, typename ShapeA, typename ShapeB>
605 DYN_FUNC inline void checkAxisEdge(
607 ShapeA& shapeA,
608 ShapeB& shapeB,
609 const Real radiusA,
610 const Real radiusB,
611 Segment3D edgeA,
612 Segment3D edgeB
613 )
614 {
615 Vec3f dirA = edgeA.direction();
616 Vec3f dirB = edgeB.direction();
617 Segment3D proj = edgeA.proximity(edgeB);
618 Vec3f N = dirA.cross(dirB);
619 Real D = 0;
620 Real bA, bB;
621 if (N.norm() > EPSILON) N /= N.norm(); else return;
622 checkSignedDistanceAxis(D, bA, bB, N, shapeA, shapeB, radiusA, radiusB);
623
624 if (!checkPointInBoundary(proj.v0, N, bA, radiusA) || !checkPointInBoundary(proj.v1, N, bB, radiusB)) return;
625 sat.update(SeparationType::CT_EDGE, bA, bB, D, N, proj.v0, proj.v1);
626 }
627
628 template<typename Real, typename ShapeA, typename ShapeB>
629 DYN_FUNC inline void checkAxisTri(
631 ShapeA& shapeA,
632 ShapeB& shapeB,
633 const Real radiusA,
634 const Real radiusB,
635 Triangle3D tri,
636 SeparationType type // [faceA or faceB]
637 )
638 {
639 Vec3f N = tri.normal();
640 Real D = 0;
641 Real bA, bB;
642 if (N.norm() > EPSILON) N /= N.norm(); else return;
643 checkSignedDistanceAxis(D, bA, bB, N, shapeA, shapeB, radiusA, radiusB);
644 Real bb = (type == CT_TRIA) ? bA : bB;
645 Real rr = (type == CT_TRIA) ? radiusA : radiusB;
646 for (int i = 0; i < 3; ++i)
647 if (!checkPointInBoundary(tri.v[i], N, bb, rr)) return;
648 sat.update(type, bA, bB, D, N, tri.v[0], tri.v[1], tri.v[2]);
649 }
650
651 template<typename Real, typename ShapeA, typename ShapeB>
652 DYN_FUNC inline void checkAxisRect(
654 ShapeA& shapeA,
655 ShapeB& shapeB,
656 const Real radiusA,
657 const Real radiusB,
658 Rectangle3D rect,
659 SeparationType type
660 )
661 {
662 Vec3f N = rect.normal();
663 Real D = 0;
664 Real bA, bB;
665 if (N.norm() > EPSILON) N /= N.norm(); else return;
666 checkSignedDistanceAxis(D, bA, bB, N, shapeA, shapeB, radiusA, radiusB);
667 Real bb = (type == CT_RECTA) ? bA : bB;
668 Real rr = (type == CT_RECTA) ? radiusA : radiusB;
669 for (int i = 0; i < 4; ++i)
670 if (!checkPointInBoundary(rect.vertex(i).origin, N, bb, rr)) return;
671 sat.update(type, bA, bB, D, N, rect.center, rect.axis[0], rect.axis[1], Vec3f(rect.extent[0], rect.extent[1], 0.f));
672 }
673
674 // ---------------------------------------- [ Sphere ] ----------------------------------------
675 template<typename Real>
676 DYN_FUNC inline void projectOnAxis(
677 Real& lowerBoundary,
678 Real& upperBoundary,
679 const Vec3f axisNormal,
680 Sphere3D sphere,
681 const Real radius
682 )
683 {
684 lowerBoundary = upperBoundary = sphere.center.dot(axisNormal);
685
686 lowerBoundary -= radius + sphere.radius;
687 upperBoundary += radius + sphere.radius;
688 }
689
690 template<typename Real>
691 DYN_FUNC inline void setupContactOnSphere(
694 const TSphere3D<Real>& sphereB,
695 const Real radiusA,
696 const Real radiusB)
697 {
698 Vec3f contactPoint = sat.pointB() - m.normal * (sphereB.radius);
699 m.pushContact(contactPoint, sat.depth());
700 }
701
702 template<typename Real>
703 DYN_FUNC inline int ClippingWithTri(
705 const TTriangle3D<Real>& triA,
706 const TSphere3D<Real>& sphereB,
707 const Vector<Real, 3>& transA,
708 const Vector<Real, 3>& transB
709 )
710 {
711 return 0;
712 }
713
714 template<typename Real>
715 DYN_FUNC inline int ClippingWithRect(
717 const TRectangle3D<Real>& rectA,
718 const TSphere3D<Real>& sphereB,
719 const Vector<Real, 3>& transA,
720 const Vector<Real, 3>& transB
721 )
722 {
723 return 0;
724 }
725
726 // ---------------------------------------- [ Segment ] ----------------------------------------
727 template<typename Real>
728 DYN_FUNC inline void projectOnAxis(
729 Real& lowerBoundary,
730 Real& upperBoundary,
731 const Vec3f axisNormal,
732 Segment3D seg,
733 const Real radius
734 )
735 {
736 Real t = seg.v0.dot(axisNormal); lowerBoundary = upperBoundary = t;
737 t = seg.v1.dot(axisNormal); lowerBoundary = glm::min(lowerBoundary, t); upperBoundary = glm::max(upperBoundary, t);
738
739 lowerBoundary -= radius;
740 upperBoundary += radius;
741 }
742
743 template<typename Real>
744 DYN_FUNC inline int ClippingWithTri(
746 const TTriangle3D<Real>& triA,
747 const TSegment3D<Real>& segB,
748 const Vector<Real, 3>& transA,
749 const Vector<Real, 3>& transB
750 )
751 {
752 Triangle3D triT = Triangle3D(triA.v[0] + transA, triA.v[1] + transA, triA.v[2] + transA);
753 Segment3D segT = Segment3D(segB.v0 + transB, segB.v1 + transB);
754
755 int num = 0;
756 Vec3f oA = triT.v[0];
757 Vec3f nA = triT.normal();
758 Vec3f poly[2];
759
760 num = cgeo::intrSegWithPlane(poly, oA, nA, segT.v0, segT.v1);
761 if (num > 0) num = cgeo::intrPolyWithTri(q, num, poly, triT.v[0], triT.v[1], triT.v[2]);
762
763 return num;
764 }
765
766 template<typename Real>
767 DYN_FUNC inline int ClippingWithRect(
769 const TRectangle3D<Real>& rectA,
770 const TSegment3D<Real>& segB,
771 const Vector<Real, 3>& transA,
772 const Vector<Real, 3>& transB
773 )
774 {
775 Rectangle3D rectT = rectA; rectT.center+= transA;
776 Segment3D segT = Segment3D(segB.v0 + transB, segB.v1 + transB);
777
778 int num = 0;
779 Vec3f oA = rectT.center;
780 Vec3f nA = rectT.normal();
781 Vec3f poly[2];
782
783 num = cgeo::intrSegWithPlane(poly, oA, nA, segT.v0, segT.v1);
784 if(num > 0) num = cgeo::intrPolyWithRect(q, num, poly, rectT.vertex(0).origin, rectT.vertex(1).origin, rectT.vertex(2).origin, rectT.vertex(3).origin);
785 return num;
786 }
787
788 template<typename Real>
789 DYN_FUNC inline void setupContactOnSeg(
792 const TSegment3D<Real>& segB,
793 const Real radiusA,
794 const Real radiusB)
795 {
796 Real depth = sat.depth();
797 if (sat.type() == CT_POINT || sat.type() == CT_EDGE)
798 {
799 Vec3f contactPoint = sat.pointB() - m.normal * radiusB;
800 m.pushContact(contactPoint, depth);
801 }
802 else if (sat.face() == CT_TRIA)
803 {
804 Vec3f q[2]; Vec3f transA, transB;
805 transA = m.normal * (radiusA + depth); // depth < 0
806 transB = -m.normal * radiusB;
807 int num = ClippingWithTri(q, sat.tri(), segB, transA, transB);
808 for (int i = 0; i < num; ++i) m.pushContact(q[i], depth);
809 }
810 else if (sat.face() == CT_RECTA)
811 {
812 Vec3f q[2]; Vec3f transA, transB;
813 transA = m.normal * (radiusA + depth); // depth < 0
814 transB = -m.normal * radiusB;
815 int num = ClippingWithRect(q, sat.rect(), segB, transA, transB);
816 for (int i = 0; i < num; ++i) m.pushContact(q[i], depth);
817 }
818 };
819
820 /*
821 // return the closest point on the ray
822 template<typename Real>
823 DYN_FUNC inline Real rayInterRound2DHalfSeg(
824 const Vec2f rayO, // Ray's Origin arbitraryon 2D Material Space
825 const Vec2f rayD, // Ray's Direction arbitraryon 2D Material Space
826 const Real halfl,
827 const Real radius) // 2D HalfSeg Space (-halfl, 0) - (halfl,0), Normal: (0,1)
828 {
829 if (REAL_LESS(rayO.y, 0.f) && REAL_LESS(rayD.y, 0.f)) return -1.f;
830 Real t = -1.f, para = REAL_infinity; Vec2f p;
831 // check body line
832 if (!REAL_EQUAL(rayD.y, 0.f))
833 {
834 t = (radius - rayO.y) / rayD.y;
835 p = rayO + rayD * t;
836 if (REAL_GREAT(t, 0.f) && REAL_LESS(t, para) && REAL_GREAT(p.x, - halfl) && REAL_LESS(p.x, +halfl)) para = t;
837 }
838 // check left caps
839 Real a = rayD.x * rayD.x + rayD.y * rayD.y;
840 Real b = 2 * ((rayO.x - halfl) * rayD.x + rayO.y * rayD.y);
841 Real c = (rayO.x - halfl) * (rayO.x - halfl) + rayO.y * rayO.y - radius * radius;
842 Real h = b * b - 4 * a * c;
843 if (REAL_GREAT(h, 0.f))
844 {
845 Real sh = sqrt(h);
846 t = (-b - sh) / (2 * a);
847 p = rayO + rayD * t;
848 if (REAL_GREAT(t, 0.f) && REAL_LESS(t, para) && REAL_GREAT(p.y, 0.f) && REAL_LESS(p.x, -halfl)) para = t;
849 t = (-b + sh) / (2 * a);
850 p = rayO + rayD * t;
851 if (REAL_GREAT(t, 0.f) && REAL_LESS(t, para) && REAL_GREAT(p.y, 0.f) && REAL_LESS(p.x, -halfl)) para = t;
852 }
853 // check right caps
854 b += 4 * halfl * rayD.x;
855 c += halfl * halfl + 4 * halfl * rayD.x;
856 h = b * b - 4 * a * c;
857 if (REAL_GREAT(h, 0.f))
858 {
859 Real sh = sqrt(h);
860 t = (-b - sh) / (2 * a);
861 p = rayO + rayD * t;
862 if (REAL_GREAT(t, 0.f) && REAL_LESS(t, para) && REAL_GREAT(p.y, 0.f) && REAL_GREAT(p.x, +halfl)) para = t;
863 t = (-b + sh) / (2 * a);
864 p = rayO + rayD * t;
865 if (REAL_GREAT(t, 0.f) && REAL_LESS(t, para) && REAL_GREAT(p.y, 0.f) && REAL_GREAT(p.x, +halfl)) para = t;
866 }
867
868 return para;
869 }
870
871 template<typename Real>
872 DYN_FUNC inline Vec3f rayInterRoundSeg(
873 const Vec3f rayOrigin, // on seg
874 const Vec3f rayDir, // along outside normal
875 Segment3D seg,
876 Real radius // radius > 0
877 )
878 {
879 Vec3f dir = seg.direction(); dir.normalize();
880 Vec3f d, a, f, c;
881 Real t = dir.dot(rayDir), len2, sum;
882 if (REAL_LESS(t, 0.f))
883 {
884 if (REAL_EQUAL(t, -1.f) || REAL_EQUAL((rayOrigin - seg.v0).normSquared(), 0.f)) return seg.v0 + rayDir * radius;
885 d = seg.v0 - rayOrigin;
886 }
887 else
888 {
889 if (REAL_EQUAL(t, 1.f) || REAL_EQUAL((rayOrigin - seg.v1).normSquared(), 0.f)) return seg.v1 + rayDir * radius;
890 d = seg.v1 - rayOrigin;
891 }
892
893
894 f = d.cross(rayDir);
895
896 a = f.cross(d);
897 a.normalize();
898 a *= radius;
899
900 c = d + a;
901
902 t = c.dot(a) / rayDir.dot(a);
903 len2 = c.normSquared();
904 if (t * t < len2)
905 {
906 return rayOrigin + rayDir * t;
907 }
908
909 len2 = d.normSquared();
910 sum = (d[0] + d[1] + d[2]);
911 t = -2 * sum + sqrt(sum * sum - len2 + radius * radius);
912
913 return rayOrigin + rayDir * t;
914 }
915 */
916
917 // ---------------------------------------- [ Tri ] ----------------------------------------
918 template<typename Real>
919 DYN_FUNC inline void projectOnAxis(
920 Real& lowerBoundary,
921 Real& upperBoundary,
922 const Vec3f axisNormal,
923 Triangle3D tri,
924 const Real radius
925 )
926 {
927 Real t = tri.v[0].dot(axisNormal); lowerBoundary = upperBoundary = t;
928 t = tri.v[1].dot(axisNormal); lowerBoundary = glm::min(lowerBoundary, t); upperBoundary = glm::max(upperBoundary, t);
929 t = tri.v[2].dot(axisNormal); lowerBoundary = glm::min(lowerBoundary, t); upperBoundary = glm::max(upperBoundary, t);
930
931 lowerBoundary -= radius;
932 upperBoundary += radius;
933 }
934
935 template<typename Real>
936 DYN_FUNC inline int ClippingWithTri(
938 const TTriangle3D<Real>& triA,
939 const TTriangle3D<Real>& triB,
940 const Vector<Real, 3>& transA,
941 const Vector<Real, 3>& transB
942 )
943 {
944 Triangle3D triTA = Triangle3D(triA.v[0] + transA, triA.v[1] + transA, triA.v[2] + transA);
945 Triangle3D triTB = Triangle3D(triB.v[0] + transB, triB.v[1] + transB, triB.v[2] + transB);
946
947 int num = 0;
948 Vec3f oA = triTA.v[0];
949 Vec3f nA = triTA.normal();
950 Vec3f poly[3];
951
952 num = cgeo::intrTriWithPlane(poly, oA, nA, triTB.v[0], triTB.v[1], triTB.v[2]);
953 if (num > 0) num = cgeo::intrPolyWithTri(q, num, poly, triTA.v[0], triTA.v[1], triTA.v[2]);
954
955 return num;
956 }
957
958 template<typename Real>
959 DYN_FUNC inline int ClippingWithRect(
961 const TRectangle3D<Real>& rectA,
962 const TTriangle3D<Real>& triB,
963 const Vector<Real, 3>& transA,
964 const Vector<Real, 3>& transB
965 )
966 {
967 Rectangle3D rectT = rectA; rectT.center += transA;
968 Triangle3D triT = Triangle3D(triB.v[0] + transB, triB.v[1] + transB, triB.v[2] + transB);
969
970 int num = 0;
971 Vec3f oA = rectT.center;
972 Vec3f nA = rectT.normal();
973 Vec3f poly[3];
974
975 num = cgeo::intrTriWithPlane(poly, oA, nA, triT.v[0], triT.v[1], triT.v[2]);
976 if (num > 0) num = cgeo::intrPolyWithRect(q, num, poly, rectT.vertex(0).origin, rectT.vertex(1).origin, rectT.vertex(2).origin, rectT.vertex(3).origin);
977 return num;
978 }
979
980 template<typename Real, typename Shape>
981 DYN_FUNC inline void setupContactOnTri(
984 const Shape& shapeA,
985 const TTriangle3D<Real>& triB,
986 const Real radiusA,
987 const Real radiusB)
988 {
989 Real depth = sat.depth();
990 if (sat.type() == CT_POINT || sat.type() == CT_EDGE)
991 {
992 Vec3f contactPoint = sat.pointB();
993 m.pushContact(contactPoint, depth);
994 }
995 else if (sat.face() == CT_TRIA)
996 {
997 Vec3f q[6]; Vec3f transA, transB;
998 transA = m.normal * (radiusA + depth); // depth < 0
999 transB = -m.normal * radiusB;
1000 int num = ClippingWithTri(q, sat.tri(), triB, transA, transB);
1001 for (int i = 0; i < num; ++i) m.pushContact(q[i], depth);
1002 }
1003 else if (sat.face() == CT_RECTA)
1004 {
1005 Vec3f q[8]; Vec3f transA, transB;
1006 transA = m.normal * (radiusA + depth); // depth < 0
1007 transB = -m.normal * radiusB;
1008 int num = ClippingWithRect(q, sat.rect(), triB, transA, transB);
1009 for (int i = 0; i < num; ++i) m.pushContact(q[i], depth);
1010 }
1011 else if (sat.face() == CT_TRIB)
1012 {
1013 Vec3f q[6]; Vec3f transA, transB;
1014 transA = m.normal * (radiusA + depth); // depth < 0
1015 transB = -m.normal * (radiusB);
1016 int num = ClippingWithTri(q, sat.tri(), shapeA, transB, transA);
1017 for (int i = 0; i < num; ++i) m.pushContact(q[i], depth);
1018 }
1019 };
1020
1021 // ---------------------------------------- [ Tet ] ----------------------------------------
1022 template<typename Real>
1023 DYN_FUNC inline void projectOnAxis(
1024 Real& lowerBoundary,
1025 Real& upperBoundary,
1026 const Vec3f axisNormal,
1027 Tet3D tet,
1028 const Real radius
1029 )
1030 {
1031 Real t = tet.v[0].dot(axisNormal); lowerBoundary = upperBoundary = t;
1032 t = tet.v[1].dot(axisNormal); lowerBoundary = glm::min(lowerBoundary, t); upperBoundary = glm::max(upperBoundary, t);
1033 t = tet.v[2].dot(axisNormal); lowerBoundary = glm::min(lowerBoundary, t); upperBoundary = glm::max(upperBoundary, t);
1034 t = tet.v[3].dot(axisNormal); lowerBoundary = glm::min(lowerBoundary, t); upperBoundary = glm::max(upperBoundary, t);
1035
1036 lowerBoundary -= radius;
1037 upperBoundary += radius;
1038 }
1039
1040 template<typename Real>
1041 DYN_FUNC inline int ClippingWithTri(
1042 Vector<Real, 3>* q,
1043 const TTriangle3D<Real>& triA,
1044 const TTet3D<Real>& tetB,
1045 const Vector<Real, 3>& transA,
1046 const Vector<Real, 3>& transB
1047 )
1048 {
1049 Triangle3D triTA = Triangle3D(triA.v[0] + transA, triA.v[1] + transA, triA.v[2] + transA);
1050 Tet3D tetTB = Tet3D(tetB.v[0] + transB, tetB.v[1] + transB, tetB.v[2] + transB, tetB.v[3] + transB);
1051
1052 int num = 0;
1053 Vec3f oA = triTA.v[0];
1054 Vec3f nA = triTA.normal();
1055 Vec3f poly[4];
1056
1057 num = cgeo::intrTetWithPlane(poly, oA, nA, tetTB.v[0], tetTB.v[1], tetTB.v[2], tetTB.v[3]);
1058 if (num > 0) num = cgeo::intrPolyWithTri(q, num, poly, triTA.v[0], triTA.v[1], triTA.v[2]);
1059
1060 return num;
1061 }
1062
1063 template<typename Real>
1064 DYN_FUNC inline int ClippingWithRect(
1065 Vector<Real, 3>* q,
1066 const TRectangle3D<Real>& rectA,
1067 const TTet3D<Real>& tetB,
1068 const Vector<Real, 3>& transA,
1069 const Vector<Real, 3>& transB
1070 )
1071 {
1072 Rectangle3D rectT = rectA; rectT.center += transA;
1073 Tet3D tetT = Tet3D(tetB.v[0] + transB, tetB.v[1] + transB, tetB.v[2] + transB, tetB.v[3] + transB);
1074
1075 int num = 0;
1076 Vec3f oA = rectT.center;
1077 Vec3f nA = rectT.normal();
1078 Vec3f poly[4];
1079
1080 num = cgeo::intrTetWithPlane(poly, oA, nA, tetT.v[0], tetT.v[1], tetT.v[2], tetT.v[3]);
1081 if (num > 0) num = cgeo::intrPolyWithRect(q, num, poly, rectT.vertex(0).origin, rectT.vertex(1).origin, rectT.vertex(2).origin, rectT.vertex(3).origin);
1082 return num;
1083 }
1084
1085 template<typename Real, typename Shape>
1086 DYN_FUNC inline void setupContactOnTet(
1087 TManifold<Real>& m,
1089 const Shape& shapeA,
1090 const TTet3D<Real>& tetB,
1091 const Real radiusA,
1092 const Real radiusB)
1093 {
1094 Real depth = sat.depth();
1095 if (sat.type() == CT_POINT || sat.type() == CT_EDGE)
1096 {
1097 Vec3f contactPoint = sat.pointB();
1098 m.pushContact(contactPoint, depth);
1099 }
1100 else if (sat.face() == CT_TRIA)
1101 {
1102 Vec3f q[6]; Vec3f transA, transB;
1103 transA = m.normal * (radiusA + depth); // depth < 0
1104 transB = -m.normal * radiusB;
1105 int num = ClippingWithTri(q, sat.tri(), tetB, transA, transB);
1106 for (int i = 0; i < num; ++i) m.pushContact(q[i], depth);
1107 }
1108 else if (sat.face() == CT_RECTA)
1109 {
1110 Vec3f q[8]; Vec3f transA, transB;
1111 transA = m.normal * (radiusA + depth); // depth < 0
1112 transB = -m.normal * radiusB;
1113 int num = ClippingWithRect(q, sat.rect(), tetB, transA, transB);
1114 for (int i = 0; i < num; ++i) m.pushContact(q[i], depth);
1115 }
1116 else if (sat.face() == CT_TRIB)
1117 {
1118 Vec3f q[6]; Vec3f transA, transB;
1119 transA = m.normal * (radiusA + depth); // depth < 0
1120 transB = -m.normal * (radiusB);
1121 int num = ClippingWithTri(q, sat.tri(), shapeA, transB, transA);
1122 for (int i = 0; i < num; ++i) m.pushContact(q[i], depth);
1123 }
1124 };
1125
1126 // ---------------------------------------- [ Box ] ----------------------------------------
1127 template<typename Real>
1128 DYN_FUNC inline void projectOnAxis(
1129 Real& lowerBoundary,
1130 Real& upperBoundary,
1131 const Vec3f axisNormal,
1132 OrientedBox3D box,
1133 const Real radius
1134 )
1135 {
1136 Vec3f center = box.center;
1137 Vec3f u = box.u;
1138 Vec3f v = box.v;
1139 Vec3f w = box.w;
1140 Vec3f extent = box.extent;
1141 Vec3f p;
1142
1143 p = (center - u * extent[0] - v * extent[1] - w * extent[2]);
1144 Real t = p.dot(axisNormal); lowerBoundary = upperBoundary = t;
1145
1146 p = (center - u * extent[0] - v * extent[1] + w * extent[2]);
1147 t = p.dot(axisNormal); lowerBoundary = glm::min(lowerBoundary, t); upperBoundary = glm::max(upperBoundary, t);
1148
1149 p = (center - u * extent[0] + v * extent[1] - w * extent[2]);
1150 t = p.dot(axisNormal); lowerBoundary = glm::min(lowerBoundary, t); upperBoundary = glm::max(upperBoundary, t);
1151
1152 p = (center - u * extent[0] + v * extent[1] + w * extent[2]);
1153 t = p.dot(axisNormal); lowerBoundary = glm::min(lowerBoundary, t); upperBoundary = glm::max(upperBoundary, t);
1154
1155 p = (center + u * extent[0] - v * extent[1] - w * extent[2]);
1156 t = p.dot(axisNormal); lowerBoundary = glm::min(lowerBoundary, t); upperBoundary = glm::max(upperBoundary, t);
1157
1158 p = (center + u * extent[0] - v * extent[1] + w * extent[2]);
1159 t = p.dot(axisNormal); lowerBoundary = glm::min(lowerBoundary, t); upperBoundary = glm::max(upperBoundary, t);
1160
1161 p = (center + u * extent[0] + v * extent[1] - w * extent[2]);
1162 t = p.dot(axisNormal); lowerBoundary = glm::min(lowerBoundary, t); upperBoundary = glm::max(upperBoundary, t);
1163
1164 p = (center + u * extent[0] + v * extent[1] + w * extent[2]);
1165 t = p.dot(axisNormal); lowerBoundary = glm::min(lowerBoundary, t); upperBoundary = glm::max(upperBoundary, t);
1166
1167 lowerBoundary -= radius;
1168 upperBoundary += radius;
1169 }
1170
1171 template<typename Real>
1172 DYN_FUNC inline int ClippingWithTri(
1173 Vector<Real, 3>* q,
1174 const TTriangle3D<Real>& triA,
1175 const TOrientedBox3D<Real>& boxB,
1176 const Vector<Real, 3>& transA,
1177 const Vector<Real, 3>& transB
1178 )
1179 {
1180 Triangle3D triTA = Triangle3D(triA.v[0] + transA, triA.v[1] + transA, triA.v[2] + transA);
1181 OrientedBox3D boxTB = boxB; boxTB.center += transB;
1182
1183 int num = 0;
1184 Vec3f oA = triTA.v[0];
1185 Vec3f nA = triTA.normal();
1186 Vec3f poly[4];
1187
1188 num = cgeo::intrBoxWithPlane(poly, oA, nA, boxTB.center, boxTB.u * boxTB.extent[0], boxTB.v * boxTB.extent[1], boxTB.w * boxTB.extent[2]);
1189 if (num > 0) num = cgeo::intrPolyWithTri(q, num, poly, triTA.v[0], triTA.v[1], triTA.v[2]);
1190
1191 return num;
1192 }
1193
1194 template<typename Real>
1195 DYN_FUNC inline int ClippingWithRect(
1196 Vector<Real, 3>* q,
1197 const TRectangle3D<Real>& rectA,
1198 const TOrientedBox3D<Real>& boxB,
1199 const Vector<Real, 3>& transA,
1200 const Vector<Real, 3>& transB
1201 )
1202 {
1203 Rectangle3D rectT = rectA; rectT.center += transA;
1204 OrientedBox3D boxTB = boxB; boxTB.center += transB;
1205
1206 int num = 0;
1207 Vec3f oA = rectT.center;
1208 Vec3f nA = rectT.normal();
1209 Vec3f poly[4];
1210
1211 num = cgeo::intrBoxWithPlane(poly, oA, nA, boxTB.center, boxTB.u * boxTB.extent[0], boxTB.v * boxTB.extent[1], boxTB.w * boxTB.extent[2]);
1212 if (num > 0) num = cgeo::intrPolyWithRect(q, num, poly, rectT.vertex(0).origin, rectT.vertex(1).origin, rectT.vertex(2).origin, rectT.vertex(3).origin);
1213 return num;
1214 }
1215
1216
1217 template<typename Real, typename Shape>
1218 DYN_FUNC inline void setupContactOnBox(
1219 TManifold<Real>& m,
1221 const Shape& shapeA,
1222 const TOrientedBox3D<Real>& boxB,
1223 const Real radiusA,
1224 const Real radiusB)
1225 {
1226 Real depth = sat.depth();
1227 if (sat.type() == CT_POINT || sat.type() == CT_EDGE)
1228 {
1229 Vec3f contactPoint = sat.pointB();
1230 m.pushContact(contactPoint, depth);
1231 }
1232 else if (sat.face() == CT_TRIA)
1233 {
1234 Vec3f q[6]; Vec3f transA, transB;
1235 transA = m.normal * (radiusA + depth); // depth < 0
1236 transB = -m.normal * radiusB;
1237 int num = ClippingWithTri(q, sat.tri(), boxB, transA, transB);
1238 for (int i = 0; i < num; ++i) m.pushContact(q[i], depth);
1239 }
1240 else if (sat.face() == CT_RECTA)
1241 {
1242 Vec3f q[8]; Vec3f transA, transB;
1243 transA = m.normal * (radiusA + depth); // depth < 0
1244 transB = -m.normal * radiusB;
1245 int num = ClippingWithRect(q, sat.rect(), boxB, transA, transB);
1246 for (int i = 0; i < num; ++i) m.pushContact(q[i], depth);
1247 }
1248 else if (sat.face() == CT_RECTB)
1249 {
1250 Vec3f q[6]; Vec3f transA, transB;
1251 transA = m.normal * (radiusA + depth); // depth < 0
1252 transB = -m.normal * (radiusB);
1253 int num = ClippingWithRect(q, sat.rect(), shapeA, transB, transA);
1254 for (int i = 0; i < num; ++i) m.pushContact(q[i], depth);
1255 }
1256 };
1257
1258 // ---------------------------------------- [Sphere - Sphere] ----------------------------------------
1259
1260 template<typename Real>
1261 DYN_FUNC void CollisionDetection<Real>::MSDF(SeparationData& sat, const Sphere3D& sphereA, const Sphere3D& sphereB, const Real radiusA, const Real radiusB)
1262 {
1263 auto checkAxisP = [&](Vec3f pA, Vec3f pB) { checkAxisPoint(sat, sphereA, sphereB, radiusA, radiusB, pA, pB, sphereA.radius, sphereB.radius); };
1264
1265 // Minkowski Point-Point Normal
1266 // check direction of minimum distance from B's Point to A's Point
1267 checkAxisP(sphereA.center, sphereB.center);
1268 }
1269
1270
1271
1272 template<typename Real>
1273 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const Sphere3D& sphereA, const Sphere3D& sphereB, const Real radiusA, const Real radiusB)
1274 {
1275 SeparationData sat;
1276 // Contact normal on sphereB
1277 MSDF(sat, sphereA, sphereB, radiusA, radiusB);
1278
1279 if (REAL_LESS(sat.depth(), 0) && REAL_GREAT(sat.depth(), -REAL_infinity))
1280 {
1281 m.normal = sat.normal(); // contact normal on sphereB
1282
1283 setupContactOnSphere(m, sat, sphereB, radiusA, radiusB);
1284 }
1285 else m.contactCount = 0;
1286 }
1287
1288 // ---------------------------------------- [Seg - Sphere] ----------------------------------------
1289
1290 template<typename Real>
1291 DYN_FUNC void CollisionDetection<Real>::MSDF(SeparationData& sat, const Segment3D& segA, const Sphere3D& sphereB, const Real radiusA, const Real radiusB)
1292 {
1293 auto checkAxisP = [&](Vec3f pA, Vec3f pB) { checkAxisPoint(sat, segA, sphereB, radiusA, radiusB, pA, pB, 0.f, sphereB.radius); };
1294
1295 // Minkowski Point-Point Normal
1296 // check direction of minimum distance from B's Point to A's Point
1297 Vec3f pB = sphereB.center;
1298 Point3D queryP(pB);
1299 Point3D projP = queryP.project(segA);
1300 checkAxisP(projP.origin, pB);
1301 }
1302
1303
1304 template<typename Real>
1305 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const Sphere3D& sphereA, const Segment3D& segB, const Real radiusA, const Real radiusB)
1306 {
1307 SeparationData sat;
1308 // Contact normal on sphereA
1309 MSDF(sat, segB, sphereA, radiusB, radiusA);
1310
1311 Real depth = sat.depth();
1312 if (REAL_LESS(depth, 0) && REAL_GREAT(depth, -REAL_infinity))
1313 {
1314 sat.reverse(); // contact normal on segB
1315 m.normal = sat.normal();
1316 /*
1317 auto setupContactOnSeg = [&]()
1318 {
1319 Vec3f contactPoint = sat.pointB() - m.normal * (radiusB);
1320 m.pushContact(contactPoint, depth);
1321 };
1322 */
1323
1324 setupContactOnSeg(m, sat, segB, radiusA, radiusB);
1325
1326 }
1327 else m.contactCount = 0;
1328 }
1329
1330 template<typename Real>
1331 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const Segment3D& segA, const Sphere3D& sphereB, const Real radiusA, const Real radiusB)
1332 {
1333 SeparationData sat;
1334 // Contact normal on sphereB
1335 MSDF(sat, segA, sphereB, radiusA, radiusB);
1336 Real depth = sat.depth();
1337 if (REAL_LESS(depth, 0) && REAL_GREAT(depth, -REAL_infinity))
1338 {
1339 m.normal = sat.normal(); // contact normal on sphereB
1340
1341 /*
1342 auto setupContactOnSphere = [&]()
1343 {
1344 Vec3f contactPoint = sat.pointB()- m.normal * (sphereB.radius);
1345 m.pushContact(contactPoint, depth);
1346 };
1347 */
1348
1349 setupContactOnSphere(m, sat, sphereB, radiusA, radiusB);
1350
1351 }
1352 else m.contactCount = 0;
1353 }
1354
1355 // ---------------------------------------- [Tri - Sphere] ----------------------------------------
1356 template<typename Real>
1357 DYN_FUNC void CollisionDetection<Real>::MSDF(SeparationData& sat, const Triangle3D& triA, const Sphere3D& sphereB, const Real radiusA, const Real radiusB)
1358 {
1359 auto checkAxisP = [&](Vec3f pA, Vec3f pB) { checkAxisPoint(sat, triA, sphereB, radiusA, radiusB, pA, pB, 0.f, sphereB.radius); };
1360
1361 // Minkowski Point-Point Normal
1362 // check direction of minimum distance from B's Point to A's Point
1363 Vec3f pB = sphereB.center;
1364 Point3D queryP(pB);
1365 Point3D projP = queryP.project(triA);
1366 checkAxisP(projP.origin, pB);
1367 }
1368
1369
1370
1371 template<typename Real>
1372 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const Sphere3D& sphereA, const Triangle3D& triB, const Real radiusA, const Real radiusB)
1373 {
1374 SeparationData sat;
1375 // Contact normal on sphereA
1376 MSDF(sat, triB, sphereA, radiusB, radiusA);
1377 Real depth = sat.depth();
1378
1379 if (REAL_LESS(depth, 0) && REAL_GREAT(depth, -REAL_infinity))
1380 {
1381 sat.reverse(); // contact normal on triB
1382 m.normal = sat.normal();
1383
1384 setupContactOnTri(m, sat, sphereA, triB, radiusA, radiusB);
1385 }
1386 else m.contactCount = 0;
1387 }
1388
1389 template<typename Real>
1390 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const Triangle3D& triA, const Sphere3D& sphereB, const Real radiusA, const Real radiusB)
1391 {
1392 SeparationData sat;
1393 // Contact normal on sphereB
1394 MSDF(sat, triA, sphereB, radiusA, radiusB);
1395 Real depth = sat.depth();
1396
1397 if (REAL_LESS(depth, 0) && REAL_GREAT(depth, -REAL_infinity))
1398 {
1399 m.normal = sat.normal(); // contact normal on sphereB
1400
1401 /*
1402 auto setupContactOnSphere = [&]()
1403 {
1404 Vec3f contactPoint = sat.pointB() - m.normal * (sphereB.radius);
1405 m.pushContact(contactPoint, depth);
1406 };
1407 */
1408
1409 setupContactOnSphere(m, sat, sphereB, radiusA, radiusB);
1410 }
1411 else m.contactCount = 0;
1412 }
1413
1414 // ---------------------------------------- [Tet - Sphere] ----------------------------------------
1415 template<typename Real>
1416 DYN_FUNC void CollisionDetection<Real>::MSDF(SeparationData& sat, const Tet3D& tetA, const Sphere3D& sphereB, const Real radiusA, const Real radiusB)
1417 {
1418 auto checkAxisP = [&](Vec3f pA, Vec3f pB) { checkAxisPoint(sat, tetA, sphereB, radiusA, radiusB, pA, pB, 0.f, sphereB.radius); };
1419
1420 // Minkowski Point-Point Normal
1421 // check direction of minimum distance from B's Point to A's Point
1422 Vec3f pB = sphereB.center;
1423 Point3D queryP(pB);
1424 Point3D projP = queryP.project(tetA);
1425 checkAxisP(projP.origin, pB);
1426 }
1427
1428 template<typename Real>
1429 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const Sphere3D& sphereA, const Tet3D& tetB, const Real radiusA, const Real radiusB)
1430 {
1431 SeparationData sat;
1432 // Contact normal on sphereA
1433 MSDF(sat, tetB, sphereA, radiusB, radiusA);
1434 Real depth = sat.depth();
1435
1436 if (REAL_LESS(depth, 0) && REAL_GREAT(depth, -REAL_infinity))
1437 {
1438 sat.reverse(); // contact normal on tetB
1439 m.normal = sat.normal();
1440
1441 setupContactOnTet(m, sat, sphereA, tetB, radiusA, radiusB);
1442
1443 }
1444 else m.contactCount = 0;
1445 }
1446
1447 template<typename Real>
1448 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const Tet3D& tetA, const Sphere3D& sphereB, const Real radiusA, const Real radiusB)
1449 {
1450 SeparationData sat;
1451 // Contact normal on sphereB
1452 MSDF(sat, tetA, sphereB, radiusA, radiusB);
1453 Real depth = sat.depth();
1454
1455 if (REAL_LESS(depth, 0) && REAL_GREAT(depth, -REAL_infinity))
1456 {
1457 m.normal = sat.normal(); // contact normal on sphereB
1458
1459 /*
1460 auto setupContactOnSphere = [&]()
1461 {
1462 Vec3f contactPoint = sat.pointB() - m.normal * (sphereB.radius);
1463 m.pushContact(contactPoint, depth);
1464 };
1465 */
1466
1467 setupContactOnSphere(m, sat, sphereB, radiusA, radiusB);
1468 }
1469 else m.contactCount = 0;
1470 }
1471
1472 // ---------------------------------------- [Box - Sphere] ----------------------------------------
1473 template<typename Real>
1474 DYN_FUNC void CollisionDetection<Real>::MSDF(SeparationData& sat, const OBox3D& boxA, const Sphere3D& sphereB, const Real radiusA, const Real radiusB)
1475 {
1476 auto checkAxisP = [&](Vec3f pA, Vec3f pB) { checkAxisPoint(sat, boxA, sphereB, radiusA, radiusB, pA, pB, 0.f, sphereB.radius); };
1477
1478 // Minkowski Point-Point Normal
1479 // check direction of minimum distance from B's Point to A's Point
1480 Vec3f pB = sphereB.center;
1481 Point3D queryP(pB);
1482 Point3D projP = queryP.project(boxA);
1483 checkAxisP(projP.origin, pB);
1484 }
1485
1486 template<typename Real>
1487 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const Sphere3D& sphereA, const OBox3D& boxB, const Real radiusA, const Real radiusB)
1488 {
1489 SeparationData sat;
1490 // Contact normal on sphereA
1491 MSDF(sat, boxB, sphereA, radiusB, radiusA);
1492 Real depth = sat.depth();
1493 //printf("Dep :%f\n", depth);
1494 if (REAL_LESS(depth, 0) && REAL_GREAT(depth, -REAL_infinity))
1495 {
1496 sat.reverse(); // contact normal on boxB
1497 m.normal = sat.normal();
1498
1499 setupContactOnBox(m, sat, sphereA, boxB, radiusA, radiusB);
1500 }
1501 else m.contactCount = 0;
1502 }
1503
1504 template<typename Real>
1505 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const OBox3D& boxA, const Sphere3D& sphereB, const Real radiusA, const Real radiusB)
1506 {
1507 SeparationData sat;
1508 // Contact normal on sphereB
1509 MSDF(sat, boxA, sphereB, radiusA, radiusB);
1510 Real depth = sat.depth();
1511
1512 if (REAL_LESS(depth, 0) && REAL_GREAT(depth, -REAL_infinity))
1513 {
1514 m.normal = sat.normal(); // contact normal on sphereB
1515
1516 setupContactOnSphere(m, sat, sphereB, radiusA, radiusB);
1517 }
1518 else m.contactCount = 0;
1519 }
1520
1521
1522 // ---------------------------------------- [Seg - Seg] ----------------------------------------
1523 template<typename Real>
1524 DYN_FUNC void CollisionDetection<Real>::MSDF(SeparationData& sat, const Segment3D& segA, const Segment3D& segB, const Real radiusA, const Real radiusB)
1525 {
1526 auto checkAxisP = [&](Vec3f pA, Vec3f pB) { checkAxisPoint(sat, segA, segB, radiusA, radiusB, pA, pB); };
1527 auto checkAxisE = [&](Segment3D edgeA, Segment3D edgeB) { checkAxisEdge(sat, segA, segB, radiusA, radiusB, edgeA, edgeB);};
1528
1529 // Minkowski Point-Point Normal
1530 // check direction of minimum distance from B's point to A's edge
1531 for (int j = 0; j < 2; j++)
1532 {
1533 Vec3f pB = (j == 0) ? (segB.v0) : (segB.v1);
1534 Point3D queryP(pB);
1535 Point3D projP = queryP.project(segA);
1536 checkAxisP(projP.origin, pB);
1537 }
1538 for (int j = 0; j < 2; j++)
1539 {
1540 Vec3f pA = (j == 0) ? (segA.v0) : (segA.v1);
1541 Point3D queryP(pA);
1542 Point3D projP = queryP.project(segB);
1543 checkAxisP(pA, projP.origin);
1544 }
1545
1546 // Minkowski Edge-Edge Normal
1547 // segA x segB
1548 checkAxisE(segA, segB);
1549 }
1550
1551 /*
1552 template<typename Real>
1553 DYN_FUNC void CollisionDetection<Real>::MSDF(const Segment3D& segA, const Segment3D& segB, Real& depth, Coord3D& normal, Real& boundaryA, Real& boundaryB, const Real radiusA, const Real radiusB)
1554 {
1555 depth = -REAL_infinity;
1556 bool sign = true; // < 0
1557 auto checkAxis = [&](Vec3f N)
1558 {
1559 Real D = 0;
1560 Real bA, bB;
1561 if (N.norm() > EPSILON) N /= N.norm(); else return;
1562 checkSignedDistanceAxis(D, bA, bB, N, segA, segB, radiusA, radiusB);
1563
1564 updateSDF(boundaryA, boundaryB, depth, normal, bA, bB, D, N);
1565 };
1566 Vec3f axisTmp;
1567
1568 // Minkowski Point-Edge Normal
1569 // check direction of minimum distance from B's point to A's edge
1570 for (int j = 0; j < 2; j++)
1571 {
1572 Vec3f pB = (j == 0) ? (segB.v0) : (segB.v1);
1573 Point3D queryP(pB);
1574 Point3D projP = queryP.project(segA);
1575 axisTmp = (projP - queryP).direction();
1576 checkAxis(axisTmp);
1577 }
1578
1579 // Minkowski Face Normal
1580 // 1. segA x segB
1581 Vec3f dirSegA = segA.direction();
1582 Vec3f dirSegB = segB.direction();
1583 axisTmp = dirSegA.cross(dirSegB);
1584 checkAxis(axisTmp);
1585 }
1586 */
1587
1588 template<typename Real>
1589 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const Segment3D& segA, const Segment3D& segB, const Real radiusA, const Real radiusB)
1590 {
1591 SeparationData sat;
1592 // Contact normal on segB
1593 MSDF(sat, segA, segB, radiusA, radiusB);
1594 Real depth = sat.depth();
1595
1596 if (REAL_LESS(depth, 0) && REAL_GREAT(depth, -REAL_infinity))
1597 {
1598 m.normal = sat.normal(); // contact normal on segB
1599 /*
1600 auto setupContactOnSeg = [&]()
1601 {
1602 Vec3f contactPoint = sat.pointB() - m.normal * radiusB;
1603 m.pushContact(contactPoint, depth);
1604 };
1605 */
1606
1607 setupContactOnSeg(m, sat, segB, radiusA, radiusB);
1608 }
1609 else m.contactCount = 0;
1610 }
1611
1612 // ---------------------------------------- [Tri - Seg] ----------------------------------------
1613
1614 template<typename Real>
1615 DYN_FUNC void CollisionDetection<Real>::MSDF(SeparationData& sat, const Triangle3D& triA, const Segment3D& segB, const Real radiusA, const Real radiusB)
1616 {
1617 auto checkAxisP = [&](Vec3f pA, Vec3f pB) { checkAxisPoint(sat, triA, segB, radiusA, radiusB, pA, pB); };
1618 auto checkAxisE = [&](Segment3D edgeA, Segment3D edgeB) { checkAxisEdge(sat, triA, segB, radiusA, radiusB, edgeA, edgeB); };
1619 auto checkAxisT = [&](Triangle3D face) { checkAxisTri(sat, triA, segB, radiusA, radiusB, face, SeparationType::CT_TRIA); };
1620
1621 // Minkowski Face Normal
1622 // tri face
1623 checkAxisT(triA);
1624
1625 // Minkowski Edge-Edge Normal
1626 // segA x segB
1627 checkAxisE(Segment3D(triA.v[0], triA.v[1]), segB);
1628 checkAxisE(Segment3D(triA.v[0], triA.v[2]), segB);
1629 checkAxisE(Segment3D(triA.v[1], triA.v[2]), segB);
1630
1631
1632 // Minkowski Point-Point Normal
1633 // check direction of minimum distance from B's point to A's edge
1634 for (int j = 0; j < 2; j++)
1635 {
1636 Vec3f pB = (j == 0) ? (segB.v0) : (segB.v1);
1637 Point3D queryP(pB);
1638 Point3D projP = queryP.project(triA);
1639 checkAxisP(projP.origin, pB);
1640 }
1641
1642 for (int j = 0; j < 3; j++)
1643 {
1644 Vec3f pA = triA.v[j];
1645 Point3D queryP(pA);
1646 Point3D projP = queryP.project(segB);
1647 checkAxisP(pA, projP.origin);
1648 }
1649
1650
1651
1652 }
1653
1654 /*
1655 template<typename Real>
1656 DYN_FUNC void CollisionDetection<Real>::MSDF(const Triangle3D& triA, const Segment3D& segB, Real& depth, Coord3D& normal, Real& boundaryA, Real& boundaryB, const Real radiusA, const Real radiusB)
1657 {
1658 depth = -REAL_infinity;
1659 bool sign = true; // < 0
1660 auto checkAxis = [&](Vec3f N)
1661 {
1662 Real D = 0;
1663 Real bA, bB;
1664 if (N.norm() > EPSILON) N /= N.norm(); else return;
1665 checkSignedDistanceAxis(D, bA, bB, N, triA, segB, radiusA, radiusB);
1666
1667 updateSDF(boundaryA, boundaryB, depth, normal, bA, bB, D, N);
1668 };
1669 Vec3f axisTmp;
1670
1671 // Minkowski Face Normal
1672 // 1. tri face
1673 axisTmp = triA.normal();
1674 checkAxis(axisTmp);
1675
1676 // 2. edge cross
1677 Vec3f dirSeg = segB.direction();
1678 for (int i = 0; i < 2; i++)
1679 for (int j = i + 1; j < 3; ++j)
1680 {
1681 Vec3f triDir = triA.v[j] - triA.v[i];
1682 axisTmp = dirSeg.cross(triDir);
1683 checkAxis(axisTmp);
1684 }
1685
1686 // Minkowski Point-Edge Normal
1687 // check direction of minimum distance from B's point to A's edge
1688 for (int j = 0; j < 2; j++)
1689 {
1690 Vec3f pB = (j == 0) ? (segB.v0) : (segB.v1);
1691 Point3D queryP(pB);
1692 Point3D projP = queryP.project(triA);
1693 axisTmp = (projP - queryP).direction();
1694 checkAxis(axisTmp);
1695 }
1696 }
1697 */
1698
1699 template<typename Real>
1700 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const Triangle3D& triA, const Segment3D& segB, const Real radiusA, const Real radiusB)
1701 {
1702 SeparationData sat;
1703 // Contact normal on segB
1704 MSDF(sat, triA, segB, radiusA, radiusB);
1705 Real depth = sat.depth();
1706
1707 if (REAL_LESS(depth, 0) && REAL_GREAT(depth, -REAL_infinity))
1708 {
1709 m.normal = sat.normal(); // contact normal on segB
1710
1711
1712 setupContactOnSeg(m, sat, segB, radiusA, radiusB);
1713
1714 }
1715 else m.contactCount = 0;
1716 }
1717
1718 template<typename Real>
1719 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const Segment3D& segA, const Triangle3D& triB, const Real radiusA, const Real radiusB)
1720 {
1721 SeparationData sat;
1722 // Contact normal on segA
1723 MSDF(sat, triB, segA, radiusB, radiusA);
1724 Real depth = sat.depth();
1725
1726 if (REAL_LESS(depth, 0) && REAL_GREAT(depth, -REAL_infinity))
1727 {
1728 sat.reverse(); // contact normal on triB
1729 m.normal = sat.normal(); // contact normal on triB
1730
1731 setupContactOnTri(m, sat, segA, triB, radiusA, radiusB);
1732 }
1733 else m.contactCount = 0;
1734 }
1735
1736
1737 // ---------------------------------------- [Tet - Seg] ----------------------------------------
1738 template<typename Real>
1739 DYN_FUNC void CollisionDetection<Real>::MSDF(SeparationData& sat, const Tet3D& tetA, const Segment3D& segB, const Real radiusA, const Real radiusB)
1740 {
1741 auto checkAxisP = [&](Vec3f pA, Vec3f pB) { checkAxisPoint(sat, tetA, segB, radiusA, radiusB, pA, pB); };
1742 auto checkAxisE = [&](Segment3D edgeA, Segment3D edgeB) { checkAxisEdge(sat, tetA, segB, radiusA, radiusB, edgeA, edgeB); };
1743 auto checkAxisT = [&](Triangle3D face) { checkAxisTri(sat, tetA, segB, radiusA, radiusB, face, SeparationType::CT_TRIA); };
1744
1745 // Minkowski Face Normal
1746 // tet face
1747 checkAxisT(tetA.face(0));
1748 checkAxisT(tetA.face(1));
1749 checkAxisT(tetA.face(2));
1750 checkAxisT(tetA.face(3));
1751
1752 // Minkowski Edge-Edge Normal
1753 // tetA x segB
1754 checkAxisE(Segment3D(tetA.v[0], tetA.v[1]), segB);
1755 checkAxisE(Segment3D(tetA.v[0], tetA.v[2]), segB);
1756 checkAxisE(Segment3D(tetA.v[1], tetA.v[2]), segB);
1757 checkAxisE(Segment3D(tetA.v[0], tetA.v[3]), segB);
1758 checkAxisE(Segment3D(tetA.v[1], tetA.v[3]), segB);
1759 checkAxisE(Segment3D(tetA.v[2], tetA.v[3]), segB);
1760
1761
1762 // Minkowski Point-Point Normal
1763 // check direction of minimum distance from B's point to A's edge
1764 for (int j = 0; j < 2; j++)
1765 {
1766 Vec3f pB = (j == 0) ? (segB.v0) : (segB.v1);
1767 Point3D queryP(pB);
1768 Point3D projP = queryP.project(tetA);
1769 checkAxisP(projP.origin, pB);
1770 }
1771
1772 for (int j = 0; j < 4; j++)
1773 {
1774 Vec3f pA = tetA.v[j];
1775 Point3D queryP(pA);
1776 Point3D projP = queryP.project(segB);
1777 checkAxisP(pA, projP.origin);
1778 }
1779 }
1780
1781 /*
1782 template<typename Real>
1783 DYN_FUNC void CollisionDetection<Real>::MSDF(const Tet3D& tetA, const Segment3D& segB, Real& depth, Coord3D& normal, Real& boundaryA, Real& boundaryB, const Real radiusA, const Real radiusB)
1784 {
1785 depth = -REAL_infinity;
1786 bool sign = true; // < 0
1787 auto checkAxis = [&](Vec3f N)
1788 {
1789 Real D = 0;
1790 Real bA, bB;
1791 if (N.norm() > EPSILON) N /= N.norm(); else return;
1792 checkSignedDistanceAxis(D, bA, bB, N, tetA, segB, radiusA, radiusB);
1793
1794 updateSDF(boundaryA, boundaryB, depth, normal, bA, bB, D, N);
1795 };
1796 Vec3f axisTmp;
1797
1798 // Minkowski Face Normal
1799 // 1. tet face (u, v, w)
1800 for (int i = 0; i < 4; ++i)
1801 {
1802 axisTmp = tetA.face(i).normal();
1803 checkAxis(axisTmp);
1804 }
1805
1806 // 2. edge cross
1807 Vec3f dirSeg = segB.direction();
1808 for (int i = 0; i < 3; i++)
1809 for (int j = i + 1; j < 4; ++j)
1810 {
1811 Vec3f tetDir = tetA.v[j] - tetA.v[i];
1812 axisTmp = dirSeg.cross(tetDir);
1813 checkAxis(axisTmp);
1814 }
1815
1816 // Minkowski Point-Edge Normal
1817 // check direction of minimum distance from B's point to A's edge
1818 for (int j = 0; j < 2; j++)
1819 {
1820 Vec3f pB = (j == 0) ? (segB.v0) : (segB.v1);
1821 Point3D queryP(pB);
1822 Point3D projP = queryP.project(tetA);
1823 axisTmp = (projP - queryP).direction();
1824 checkAxis(axisTmp);
1825 }
1826 }
1827
1828 template<typename Real>
1829 DYN_FUNC inline void setupContactOnTet(
1830 Segment3D seg,
1831 Tet3D tet,
1832 const Real radiusA,
1833 const Real radiusB,
1834 const Real depth, // <0
1835 TManifold<Real>& m)
1836 {
1837 //Gen contact point on tet
1838
1839 int count = 0;
1840 Vec3f axisNormal = m.normal;
1841
1842 auto setContact = [&](Segment3D minPQ, Real gap)
1843 {
1844 if (minPQ.length() < gap)
1845 {
1846 if (count >= 8) return;
1847 m.contacts[count].penetration = depth;
1848 m.contacts[count].position = minPQ.endPoint();
1849 count++;
1850 }
1851 };
1852
1853 auto checkFace = [&](Vec3f v0, Vec3f v1, Vec3f v2, Vec3f Nz)
1854 {
1855 if (count >= 8) return;
1856 Triangle3D tri(v0, v1, v2);
1857 // inter & prox
1858 auto minPQ = seg.proximity(tri);
1859 // -: outside
1860 // +: inside
1861 Real gap = (Nz.dot(minPQ.direction()) < 0) ? radiusA + radiusB : radiusB;
1862 setContact(minPQ, gap);
1863
1864 // if parallel need to check the two points on segment
1865 for (int i = 0; i < 2; i++)
1866 {
1867 Vec3f v = (i == 0) ? seg.v0 : seg.v1;
1868 TPoint3D<Real> q = TPoint3D<Real>(v).project(tri);
1869 m.pushContact(q, depth);
1870 }
1871 };
1872
1873 // Check intersection and proximity for each tri face
1874 Vec3f centerTet = tet.barycenter().origin;
1875 for (int i = 0; i < 4; i++)
1876 {
1877 // Outer norm on tri face.
1878 Vec3f outerNorm = tet.face(i).normal();
1879 Vec3f dir = centerTet - tet.face(i).v[0];
1880 if (dir.dot(outerNorm) > 0.f) outerNorm = -outerNorm;
1881
1882 checkFace(tet.face(i).v[0], tet.face(i).v[1], tet.face(i).v[2], outerNorm);
1883 }
1884
1885 m.contactCount = count;
1886
1887 printf("tet contact:%d\n", count);
1888 }
1889 */
1890
1891 template<typename Real>
1892 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const Segment3D& segA, const Tet3D& tetB, const Real radiusA, const Real radiusB)
1893 {
1894 SeparationData sat;
1895 // Contact normal on segA
1896 MSDF(sat, tetB, segA, radiusB, radiusA);
1897 Real depth = sat.depth();
1898
1899 if (REAL_LESS(depth, 0) && REAL_GREAT(depth, -REAL_infinity))
1900 {
1901 sat.reverse();
1902 m.normal = sat.normal(); // contact normal on tetB
1903
1904 setupContactOnTet(m, sat, segA, tetB, radiusA, radiusB);
1905 }
1906 else m.contactCount = 0;
1907 }
1908
1909 template<typename Real>
1910 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const Tet3D& tetA, const Segment3D& segB, const Real radiusA, const Real radiusB)
1911 {
1912 SeparationData sat;
1913 // Contact normal on segB
1914 MSDF(sat, tetA, segB, radiusA, radiusB);
1915 Real depth = sat.depth();
1916
1917 if (REAL_LESS(depth, 0) && REAL_GREAT(depth, -REAL_infinity))
1918 {
1919 m.normal = sat.normal(); // contact normal on segB
1920
1921 setupContactOnSeg(m, sat, segB, radiusA, radiusB);
1922
1923 }
1924 else m.contactCount = 0;
1925 }
1926
1927
1928 // ---------------------------------------- [Box - Seg] ----------------------------------------
1929
1930 template<typename Real>
1931 DYN_FUNC void CollisionDetection<Real>::MSDF(SeparationData& sat, const OBox3D& boxA, const Segment3D& segB, const Real radiusA, const Real radiusB)
1932 {
1933 auto checkAxisP = [&](Vec3f pA, Vec3f pB) { checkAxisPoint(sat, boxA, segB, radiusA, radiusB, pA, pB); };
1934 auto checkAxisE = [&](Segment3D edgeA, Segment3D edgeB) { checkAxisEdge(sat, boxA, segB, radiusA, radiusB, edgeA, edgeB); };
1935 //auto checkAxisT = [&](Triangle3D face) { checkAxisTri(sat, boxA, segB, radiusA, radiusB, face, SeparationType::CT_TRIA); };
1936 auto checkAxisR = [&](Rectangle3D face) { checkAxisRect(sat, boxA, segB, radiusA, radiusB, face, SeparationType::CT_RECTA); };
1937
1938 // Minkowski Face Normal
1939 // box face
1940 for (int j = 0; j < 6; j++)
1941 {
1942 Rectangle3D faceA = boxA.face(j);
1943 checkAxisR(faceA);
1944 }
1945
1946 // Minkowski Edge-Edge Normal
1947 // boxA x segB
1948 for (int j = 0; j < 12; j++)
1949 {
1950 Segment3D edgeA = boxA.edge(j);
1951 checkAxisE(edgeA, segB);
1952 }
1953
1954 // Minkowski Point-Point Normal
1955 // check direction of minimum distance from B's point to A's edge
1956 for (int j = 0; j < 2; j++)
1957 {
1958 Vec3f pB = (j == 0) ? (segB.v0) : (segB.v1);
1959 Point3D queryP(pB);
1960 Point3D projP = queryP.project(boxA);
1961 checkAxisP(projP.origin, pB);
1962 }
1963
1964 for (int j = 0; j < 8; j++)
1965 {
1966 Vec3f pA = boxA.vertex(j).origin;
1967 Point3D queryP(pA);
1968 Point3D projP = queryP.project(segB);
1969 checkAxisP(pA, projP.origin);
1970 }
1971 }
1972
1973 /*
1974 template<typename Real>
1975 DYN_FUNC void CollisionDetection<Real>::MSDF(const OBox3D& boxA, const Segment3D& segB, Real& depth, Coord3D& normal, Real& boundaryA, Real& boundaryB, const Real radiusA, const Real radiusB)
1976 {
1977 depth = -REAL_infinity;
1978 bool sign = true; // < 0
1979 auto checkAxis = [&](Vec3f N)
1980 {
1981 Real D = 0;
1982 Real bA, bB;
1983 if (N.norm() > EPSILON) N /= N.norm(); else return;
1984 checkSignedDistanceAxis(D, bA, bB, N, boxA, segB, radiusA, radiusB);
1985
1986 updateSDF(boundaryA, boundaryB, depth, normal, bA, bB, D, N);
1987 };
1988 Vec3f axisTmp;
1989
1990 // Minkowski Face Normal
1991 // 1. box face (u, v, w)
1992 axisTmp = boxA.u / boxA.u.norm(); checkAxis(axisTmp);
1993 axisTmp = boxA.v / boxA.v.norm(); checkAxis(axisTmp);
1994 axisTmp = boxA.w / boxA.w.norm(); checkAxis(axisTmp);
1995 // 2. edge cross
1996 Vec3f dirSeg = segB.direction();
1997 for (int j = 0; j < 3; j++)
1998 {
1999 Vec3f boxDir = (j == 0) ? (boxA.u) : ((j == 1) ? (boxA.v) : (boxA.w));
2000 axisTmp = dirSeg.cross(boxDir);
2001 checkAxis(axisTmp);
2002 }
2003
2004 // Minkowski Point-Edge Normal
2005 // check direction of minimum distance from B's point to A's edge
2006 for (int j = 0; j < 2; j++)
2007 {
2008 Vec3f pB = (j == 0) ? (segB.v0) : (segB.v1);
2009 Point3D queryP(pB);
2010 Point3D projP = queryP.project(boxA);
2011 axisTmp = (projP - queryP).direction();
2012 checkAxis(axisTmp);
2013 }
2014 }
2015
2016
2017 template<typename Real>
2018 DYN_FUNC inline void setupContactOnBox(
2019 Segment3D seg,
2020 OrientedBox3D box,
2021 const Real radiusA,
2022 const Real radiusB,
2023 const Real depth, // <0
2024 TManifold<Real>& m)
2025 {
2026 //Gen contact point on box
2027
2028 // Intersecte on Margin : F-V, V-F, E-E
2029
2030 // Intersecte on Polygon : E-F, F-E, B-V
2031
2032
2033 int count = 0;
2034 Vec3f axisNormal = m.normal;
2035
2036 auto setContact = [&](Segment3D minPQ, Real gap)
2037 {
2038 if (minPQ.length() < gap)
2039 {
2040 if (count >= 8) return;
2041 m.contacts[count].penetration = depth;
2042 m.contacts[count].position = minPQ.endPoint();
2043 count++;
2044 }
2045 };
2046
2047 auto checkFace = [&](Vec3f c, Vec3f Nx, Vec3f Ny, Vec3f Nz, Real Ex, Real Ey)
2048 {
2049 if (count >= 8) return;
2050 Rectangle3D rect(c, Nx, Ny, Vec2f(Ex, Ey));
2051 // inter & prox
2052 auto minPQ = seg.proximity(rect);
2053 Real gap = (Nz.dot(minPQ.direction()) < 0) ? radiusA + radiusB : radiusA;
2054 setContact(minPQ, gap);
2055
2056 // if parallel need to check the two points on segment
2057 for (int i = 0; i < 2; i++)
2058 {
2059 Vec3f v = (i == 0) ? seg.v0 : seg.v1;
2060 TPoint3D<Real> p(v);
2061 TPoint3D<Real> q = TPoint3D<Real>(p).project(rect);
2062 TSegment3D<Real> pq = q - p;
2063 setContact(pq, gap);
2064 }
2065 };
2066
2067 // Check intersection and proximity for each face
2068 // -u +u
2069 for (int iu = -1; iu <= 1; iu += 2)
2070 {
2071 Vec3f c = box.center + box.u * box.extent[0] * iu;
2072 checkFace(c, box.v, box.w, box.u * Real(iu), box.extent[1], box.extent[2]);
2073 }
2074 // -v +v
2075 for (int iv = -1; iv <= 1; iv += 2)
2076 {
2077 Vec3f c = box.center + box.v * box.extent[1] * iv;
2078 checkFace(c, box.u, box.w, box.v * Real(iv), box.extent[0], box.extent[2]);
2079 }
2080 // -w +w
2081 for (int iw = -1; iw <= 1; iw += 2)
2082 {
2083 Vec3f c = box.center + box.w * box.extent[2] * iw;
2084 checkFace(c, box.u, box.v, box.w * Real(iw), box.extent[0], box.extent[1]);
2085 }
2086
2087 m.contactCount = count;
2088
2089 printf("box contact:%d\n", count);
2090 }
2091 */
2092
2093
2094 template<typename Real>
2095 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const Segment3D& segA, const OBox3D& boxB, const Real radiusA, const Real radiusB)
2096 {
2097 SeparationData sat;
2098 // Contact normal on segA
2099 MSDF(sat, boxB, segA, radiusB, radiusA);
2100 Real depth = sat.depth();
2101
2102 if (REAL_LESS(depth, 0) && REAL_GREAT(depth, -REAL_infinity))
2103 {
2104 sat.reverse();
2105 m.normal = sat.normal(); // contact normal on boxB
2106
2107 setupContactOnBox(m, sat, segA, boxB, radiusA, radiusB);
2108
2109 }
2110 else m.contactCount = 0;
2111 }
2112
2113 template<typename Real>
2114 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const OBox3D& boxA, const Segment3D& segB, const Real radiusA, const Real radiusB)
2115 {
2116 SeparationData sat;
2117 // Contact normal on segB
2118 MSDF(sat, boxA, segB, radiusA, radiusB);
2119 Real depth = sat.depth();
2120
2121 if (REAL_LESS(depth, 0) && REAL_GREAT(depth, -REAL_infinity))
2122 {
2123 m.normal = sat.normal(); // contact normal on segB
2124
2125 setupContactOnSeg(m, sat, segB, radiusA, radiusB);
2126
2127 }
2128 else m.contactCount = 0;
2129 }
2130
2131
2132 // ---------------------------------------- [Tri - Tri] ----------------------------------------
2133
2134 template<typename Real>
2135 DYN_FUNC void CollisionDetection<Real>::MSDF(SeparationData& sat, const Triangle3D& triA, const Triangle3D& triB, const Real radiusA, const Real radiusB)
2136 {
2137 auto checkAxisP = [&](Vec3f pA, Vec3f pB) { checkAxisPoint(sat, triA, triB, radiusA, radiusB, pA, pB); };
2138 auto checkAxisE = [&](Segment3D edgeA, Segment3D edgeB) { checkAxisEdge(sat, triA, triB, radiusA, radiusB, edgeA, edgeB); };
2139 auto checkAxisT = [&](Triangle3D face, auto type) { checkAxisTri(sat, triA, triB, radiusA, radiusB, face, type); };
2140
2141 // Minkowski Face Normal
2142 // tri face
2143 checkAxisT(triA, SeparationType::CT_TRIA);
2144 checkAxisT(triB, SeparationType::CT_TRIB);
2145
2146
2147 // Minkowski Edge-Edge Normal
2148 // triA x triB
2149 for (int i = 0; i < 3; i++)
2150 for (int j = 0; j < 3; j++)
2151 {
2152 int ni = (i == 2) ? 0 : i + 1;
2153 int nj = (j == 2) ? 0 : j + 1;
2154 checkAxisE(Segment3D(triA.v[i], triA.v[ni]), Segment3D(triB.v[j], triB.v[nj]));
2155 }
2156
2157 // Minkowski Point-Point Normal
2158 for (int j = 0; j < 3; j++)
2159 {
2160 Vec3f pA = triA.v[j];
2161 Point3D queryP(pA);
2162 Point3D projP = queryP.project(triB);
2163 checkAxisP(pA, projP.origin);
2164 }
2165
2166 for (int j = 0; j < 3; j++)
2167 {
2168 Vec3f pB = triB.v[j];
2169 Point3D queryP(pB);
2170 Point3D projP = queryP.project(triA);
2171 checkAxisP(projP.origin, pB);
2172 }
2173 }
2174
2175 /*
2176 template<typename Real>
2177 DYN_FUNC void CollisionDetection<Real>::MSDF(const Triangle3D& triA, const Triangle3D& triB, Real& depth, Coord3D& normal, Real& boundaryA, Real& boundaryB, const Real radiusA, const Real radiusB)
2178 {
2179 depth = -REAL_infinity;
2180 bool sign = true; // < 0
2181 auto checkAxis = [&](Vec3f N)
2182 {
2183 Real D = 0;
2184 Real bA, bB;
2185 if (N.norm() > EPSILON) N /= N.norm(); else return;
2186 checkSignedDistanceAxis(D, bA, bB, N, triA, triB, radiusA, radiusB);
2187
2188 updateSDF(boundaryA, boundaryB, depth, normal, bA, bB, D, N);
2189 };
2190 Vec3f axisTmp;
2191
2192 // Minkowski Face Normal
2193 // 1. triA face
2194 axisTmp = triA.normal();
2195 checkAxis(axisTmp);
2196
2197 // 2. triB face
2198 axisTmp = triB.normal();
2199 checkAxis(axisTmp);
2200
2201 // 3. triA's edge x triB's edge
2202 for (int i = 0; i < 3; i++)
2203 for (int j = 0; j < 3; j++)
2204 {
2205 Vec3f triDirA = triA.v[(i + 1) % 3] - triA.v[i];
2206 Vec3f triDirB = triB.v[(j + 1) % 3] - triB.v[j];
2207 axisTmp = triDirA.cross(triDirB);
2208 checkAxis(axisTmp);
2209 }
2210
2211 // Minkowski Point-Edge Normal
2212 // check direction of minimum distance from B's point to A's edge
2213 for (int j = 0; j < 3; j++)
2214 {
2215 Vec3f pB = triB.v[j];
2216 Point3D queryP(pB);
2217 Point3D projP = queryP.project(triA);
2218 axisTmp = (projP - queryP).direction();
2219 checkAxis(axisTmp);
2220 }
2221 }
2222 */
2223
2224 template<typename Real>
2225 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const Triangle3D& triA, const Triangle3D& triB, const Real radiusA, const Real radiusB)
2226 {
2227 SeparationData sat;
2228 // Contact normal on triB
2229 MSDF(sat, triA, triB, radiusA, radiusB);
2230 Real depth = sat.depth();
2231
2232 if (REAL_LESS(depth, 0) && REAL_GREAT(depth, -REAL_infinity))
2233 {
2234 m.normal = sat.normal(); // contact normal on triB
2235 setupContactOnTri(m, sat, triA, triB, radiusA, radiusB);
2236
2237 }
2238 else m.contactCount = 0;
2239 }
2240
2241
2242 // ---------------------------------------- [Tet - Tri] ----------------------------------------
2243
2244 template<typename Real>
2245 DYN_FUNC void CollisionDetection<Real>::MSDF(SeparationData& sat, const Tet3D& tetA, const Triangle3D& triB, const Real radiusA, const Real radiusB)
2246 {
2247 auto checkAxisP = [&](Vec3f pA, Vec3f pB) { checkAxisPoint(sat, tetA, triB, radiusA, radiusB, pA, pB); };
2248 auto checkAxisE = [&](Segment3D edgeA, Segment3D edgeB) { checkAxisEdge(sat, tetA, triB, radiusA, radiusB, edgeA, edgeB); };
2249 auto checkAxisT = [&](Triangle3D face, auto type) { checkAxisTri(sat, tetA, triB, radiusA, radiusB, face, type); };
2250
2251 // Minkowski Face Normal
2252 // face
2253 checkAxisT(tetA.face(0), SeparationType::CT_TRIA);
2254 checkAxisT(tetA.face(1), SeparationType::CT_TRIA);
2255 checkAxisT(tetA.face(2), SeparationType::CT_TRIA);
2256 checkAxisT(tetA.face(3), SeparationType::CT_TRIA);
2257 checkAxisT(triB, SeparationType::CT_TRIB);
2258
2259
2260 // Minkowski Edge-Edge Normal
2261 // tetA x triB
2262 for (int i = 0; i < 6; i++)
2263 for (int j = 0; j < 3; j++)
2264 {
2265 int nj = (j == 2) ? 0 : j + 1;
2266 checkAxisE(tetA.edge(i), Segment3D(triB.v[j], triB.v[nj]));
2267 }
2268
2269 // Minkowski Point-Point Normal
2270 for (int j = 0; j < 4; j++)
2271 {
2272 Vec3f pA = tetA.v[j];
2273 Point3D queryP(pA);
2274 Point3D projP = queryP.project(triB);
2275 checkAxisP(pA, projP.origin);
2276 }
2277
2278 for (int j = 0; j < 3; j++)
2279 {
2280 Vec3f pB = triB.v[j];
2281 Point3D queryP(pB);
2282 Point3D projP = queryP.project(tetA);
2283 checkAxisP(projP.origin, pB);
2284 }
2285 }
2286
2287 /*
2288 template<typename Real>
2289 DYN_FUNC void CollisionDetection<Real>::MSDF(const Tet3D& tetA, const Triangle3D& triB, Real& depth, Coord3D& normal, Real& boundaryA, Real& boundaryB, const Real radiusA, const Real radiusB)
2290 {
2291 depth = -REAL_infinity;
2292 bool sign = true; // < 0
2293 auto checkAxis = [&](Vec3f N)
2294 {
2295 Real D = 0;
2296 Real bA, bB;
2297 if (N.norm() > EPSILON) N /= N.norm(); else return;
2298 checkSignedDistanceAxis(D, bA, bB, N, tetA, triB, radiusA, radiusB);
2299
2300 updateSDF(boundaryA, boundaryB, depth, normal, bA, bB, D, N);
2301 };
2302 Vec3f axisTmp;
2303
2304 // Minkowski Face Normal
2305 // 1. tet face (u, v, w)
2306 for (int i = 0; i < 4; ++i)
2307 {
2308 axisTmp = tetA.face(i).normal();
2309 checkAxis(axisTmp);
2310 }
2311
2312 // 2. Tri face
2313 axisTmp = triB.normal();
2314 checkAxis(axisTmp);
2315
2316 // 2. edge cross
2317 for (int i = 0; i < 3; i++)
2318 for (int j = i + 1; j < 4; ++j)
2319 {
2320 Vec3f tetDir = tetA.v[j] - tetA.v[i];
2321 for (int k = 0; k < 3; k++)
2322 {
2323 Vec3f triDir = triB.v[(k + 1) % 3] - triB.v[k];
2324 axisTmp = tetDir.cross(triDir);
2325 checkAxis(axisTmp);
2326 }
2327 }
2328
2329 // Minkowski Point-Edge Normal
2330 // check direction of minimum distance from B's point to A's edge
2331 for (int j = 0; j < 3; j++)
2332 {
2333 Vec3f pB = triB.v[j];
2334 Point3D queryP(pB);
2335 Point3D projP = queryP.project(tetA);
2336 axisTmp = (projP - queryP).direction();
2337 checkAxis(axisTmp);
2338 }
2339 }
2340 */
2341
2342 template<typename Real>
2343 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const Triangle3D& triA, const Tet3D& tetB, const Real radiusA, const Real radiusB)
2344 {
2345 SeparationData sat;
2346 // Contact normal on triA
2347 MSDF(sat, tetB, triA, radiusA, radiusB);
2348 Real depth = sat.depth();
2349
2350 if (REAL_LESS(depth, 0) && REAL_GREAT(depth, -REAL_infinity))
2351 {
2352 sat.reverse(); // contact normal on tetB
2353 m.normal = sat.normal();
2354
2355 setupContactOnTet(m, sat, triA, tetB, radiusA, radiusB);
2356 }
2357 else m.contactCount = 0;
2358 }
2359
2360 template<typename Real>
2361 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const Tet3D& tetA, const Triangle3D& triB, const Real radiusA, const Real radiusB)
2362 {
2363 SeparationData sat;
2364 // Contact normal on triB
2365 MSDF(sat, tetA, triB, radiusA, radiusB);
2366 Real depth = sat.depth();
2367
2368 if (REAL_LESS(depth, 0) && REAL_GREAT(depth, -REAL_infinity))
2369 {
2370 m.normal = sat.normal(); // contact normal on triB
2371
2372 setupContactOnTri(m, sat, tetA, triB, radiusA, radiusB);
2373 }
2374 else m.contactCount = 0;
2375 }
2376
2377 // ---------------------------------------- [Box - Tri] ----------------------------------------
2378
2379 template<typename Real>
2380 DYN_FUNC void CollisionDetection<Real>::MSDF(SeparationData& sat, const OBox3D& boxA, const Triangle3D& triB, const Real radiusA, const Real radiusB)
2381 {
2382 auto checkAxisP = [&](Vec3f pA, Vec3f pB) { checkAxisPoint(sat, boxA, triB, radiusA, radiusB, pA, pB); };
2383 auto checkAxisE = [&](Segment3D edgeA, Segment3D edgeB) { checkAxisEdge(sat, boxA, triB, radiusA, radiusB, edgeA, edgeB); };
2384 auto checkAxisT = [&](Triangle3D face) { checkAxisTri(sat, boxA, triB, radiusA, radiusB, face, CT_TRIB); };
2385 auto checkAxisR = [&](Rectangle3D face) { checkAxisRect(sat, boxA, triB, radiusA, radiusB, face, CT_RECTA); };
2386
2387 // Minkowski Face Normal
2388 // face
2389 for (int j = 0; j < 6; j++) checkAxisR(boxA.face(j));
2390 checkAxisT(triB);
2391
2392 // Minkowski Edge-Edge Normal
2393 // boxA x triB
2394 for (int i = 0; i < 12; i++)
2395 for (int j = 0; j < 3; j++)
2396 {
2397 int nj = (j == 2) ? 0 : j + 1;
2398 checkAxisE(boxA.edge(i), Segment3D(triB.v[j], triB.v[nj]));
2399 }
2400
2401 // Minkowski Point-Point Normal
2402 for (int j = 0; j < 8; j++)
2403 {
2404 Vec3f pA = boxA.vertex(j).origin;
2405 Point3D queryP(pA);
2406 Point3D projP = queryP.project(triB);
2407 checkAxisP(pA, projP.origin);
2408 }
2409
2410 for (int j = 0; j < 3; j++)
2411 {
2412 Vec3f pB = triB.v[j];
2413 Point3D queryP(pB);
2414 Point3D projP = queryP.project(boxA);
2415 checkAxisP(projP.origin, pB);
2416 }
2417 }
2418
2419 /*
2420 template<typename Real>
2421 DYN_FUNC void CollisionDetection<Real>::MSDF(const OBox3D& boxA, const Triangle3D& triB, Real& depth, Coord3D& normal, Real& boundaryA, Real& boundaryB, const Real radiusA, const Real radiusB)
2422 {
2423 depth = -REAL_infinity;
2424 bool sign = true; // < 0
2425 auto checkAxis = [&](Vec3f N)
2426 {
2427 Real D = 0;
2428 Real bA, bB;
2429 if (N.norm() > EPSILON) N /= N.norm(); else return;
2430 checkSignedDistanceAxis(D, bA, bB, N, boxA, triB, radiusA, radiusB);
2431
2432 updateSDF(boundaryA, boundaryB, depth, normal, bA, bB, D, N);
2433 };
2434 Vec3f axisTmp;
2435
2436 // Minkowski Face Normal
2437 // 1. Box face (u, v, w)
2438 axisTmp = boxA.u / boxA.u.norm(); checkAxis(axisTmp);
2439 axisTmp = boxA.v / boxA.v.norm(); checkAxis(axisTmp);
2440 axisTmp = boxA.w / boxA.w.norm(); checkAxis(axisTmp);
2441
2442 // 2. Tri face
2443 axisTmp = triB.normal();
2444 checkAxis(axisTmp);
2445
2446 // 2. edge cross
2447 for (int i = 0; i < 3; i++)
2448 {
2449 Vec3f boxDir = (i == 0) ? (boxA.u) : ((i == 1) ? (boxA.v) : (boxA.w));
2450 for (int j = 0; j < 3; j++)
2451 {
2452 Vec3f triDir = triB.v[(j + 1) % 3] - triB.v[j];
2453 axisTmp = boxDir.cross(triDir);
2454 checkAxis(axisTmp);
2455 }
2456 }
2457
2458 // Minkowski Point-Edge Normal
2459 // check direction of minimum distance from B's point to A's edge
2460 for (int j = 0; j < 3; j++)
2461 {
2462 Vec3f pB = triB.v[j];
2463 Point3D queryP(pB);
2464 Point3D projP = queryP.project(boxA);
2465 axisTmp = (projP - queryP).direction();
2466 checkAxis(axisTmp);
2467 }
2468 }
2469 */
2470
2471
2472 template<typename Real>
2473 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const Triangle3D& triA, const OBox3D& boxB, const Real radiusA, const Real radiusB)
2474 {
2475 SeparationData sat;
2476 // Contact normal on triA
2477 MSDF(sat, boxB, triA, radiusA, radiusB);
2478 Real depth = sat.depth();
2479
2480 if (REAL_LESS(depth, 0) && REAL_GREAT(depth, -REAL_infinity))
2481 {
2482 sat.reverse(); // contact normal on boxB
2483 m.normal = sat.normal();
2484
2485 setupContactOnBox(m, sat, triA, boxB, radiusA, radiusB);
2486 }
2487 else m.contactCount = 0;
2488 }
2489
2490 template<typename Real>
2491 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const OBox3D& boxA, const Triangle3D& triB, const Real radiusA, const Real radiusB)
2492 {
2493 SeparationData sat;
2494 // Contact normal on triB
2495 MSDF(sat, boxA, triB, radiusA, radiusB);
2496 Real depth = sat.depth();
2497
2498 if (REAL_LESS(depth, 0) && REAL_GREAT(depth, -REAL_infinity))
2499 {
2500 m.normal = sat.normal(); // contact normal on triB
2501
2502 setupContactOnTri(m, sat, boxA, triB, radiusA, radiusB);
2503 }
2504 else m.contactCount = 0;
2505 }
2506
2507
2508 // ---------------------------------------- [Tet - Tet] ----------------------------------------
2509 template<typename Real>
2510 DYN_FUNC void CollisionDetection<Real>::MSDF(SeparationData& sat, const Tet3D& tetA, const Tet3D& tetB, const Real radiusA, const Real radiusB)
2511 {
2512 auto checkAxisP = [&](Vec3f pA, Vec3f pB) { checkAxisPoint(sat, tetA, tetB, radiusA, radiusB, pA, pB); };
2513 auto checkAxisE = [&](Segment3D edgeA, Segment3D edgeB) { checkAxisEdge(sat, tetA, tetB, radiusA, radiusB, edgeA, edgeB); };
2514 auto checkAxisT = [&](Triangle3D face, auto type) { checkAxisTri(sat, tetA, tetB, radiusA, radiusB, face, type); };
2515
2516 // Minkowski Face Normal
2517 // tet face
2518 checkAxisT(tetA.face(0), SeparationType::CT_TRIA);
2519 checkAxisT(tetA.face(1), SeparationType::CT_TRIA);
2520 checkAxisT(tetA.face(2), SeparationType::CT_TRIA);
2521 checkAxisT(tetA.face(3), SeparationType::CT_TRIA);
2522
2523 checkAxisT(tetB.face(0), SeparationType::CT_TRIB);
2524 checkAxisT(tetB.face(1), SeparationType::CT_TRIB);
2525 checkAxisT(tetB.face(2), SeparationType::CT_TRIB);
2526 checkAxisT(tetB.face(3), SeparationType::CT_TRIB);
2527
2528 // Minkowski Edge-Edge Normal
2529 // tetA x tetB
2530 for (int i = 0; i < 6; i++)
2531 for (int j = 0; j < 6; j++)
2532 {
2533 Segment3D edgeA = tetA.edge(i);
2534 Segment3D edgeB = tetB.edge(j);
2535 checkAxisE(edgeA, edgeB);
2536 }
2537
2538 // Minkowski Point-Point Normal
2539 // check direction of minimum distance from B's point to A's edge
2540 for (int j = 0; j < 4; j++)
2541 {
2542 Vec3f pA = tetB.v[j];
2543 Point3D queryP(pA);
2544 Point3D projP = queryP.project(tetA);
2545 checkAxisP(pA, projP.origin);
2546 }
2547
2548 for (int j = 0; j < 4; j++)
2549 {
2550 Vec3f pA = tetA.v[j];
2551 Point3D queryP(pA);
2552 Point3D projP = queryP.project(tetB);
2553 checkAxisP(pA, projP.origin);
2554 }
2555 }
2556
2557 /*
2558 template<typename Real>
2559 DYN_FUNC void CollisionDetection<Real>::MSDF(const Tet3D& tetA, const Tet3D& tetB, Real& depth, Coord3D& normal, Real& boundaryA, Real& boundaryB, const Real radiusA, const Real radiusB)
2560 {
2561 depth = -REAL_infinity;
2562 bool sign = true; // < 0
2563 auto checkAxis = [&](Vec3f N)
2564 {
2565 Real D = 0;
2566 Real bA, bB;
2567 if (N.norm() > EPSILON) N /= N.norm(); else return;
2568 checkSignedDistanceAxis(D, bA, bB, N, tetA, tetB, radiusA, radiusB);
2569
2570 updateSDF(boundaryA, boundaryB, depth, normal, bA, bB, D, N);
2571 };
2572 Vec3f axisTmp;
2573
2574 // Minkowski Face Normal
2575 // 1. tetA face
2576 for (int i = 0; i < 4; i++)
2577 {
2578 axisTmp = tetA.face(i).normal();
2579 checkAxis(axisTmp);
2580 }
2581
2582 // 2. tetB face
2583 for (int i = 0; i < 4; i++)
2584 {
2585 axisTmp = tetB.face(i).normal();
2586 checkAxis(axisTmp);
2587 }
2588
2589 // 3. tetA's edge x tetB's edge
2590 for (int i = 0; i < 3; i++)
2591 for (int j = i + 1; j < 4; ++j)
2592 {
2593 Vec3f tetDirA = tetA.v[j] - tetA.v[i];
2594 for (int k = 0; k < 3; k++)
2595 for (int l = k + 1; l < 4; l++)
2596 {
2597 Vec3f tetDirB = tetB.v[k] - tetB.v[l];
2598 axisTmp = tetDirA.cross(tetDirB);
2599 checkAxis(axisTmp);
2600 }
2601 }
2602
2603 // Minkowski Point-Edge Normal
2604 // check direction of minimum distance from B's point to A's edge
2605 for (int i = 0; i <4; i++)
2606 {
2607 Vec3f pB = tetB.v[i];
2608 Point3D queryP(pB);
2609 Point3D projP = queryP.project(tetA);
2610 axisTmp = (projP - queryP).direction();
2611 checkAxis(axisTmp);
2612 }
2613 }
2614 */
2615
2616 template<typename Real>
2617 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const Tet3D& tetA, const Tet3D& tetB, const Real radiusA, const Real radiusB)
2618 {
2619 SeparationData sat;
2620 // Contact normal on tetB
2621 MSDF(sat, tetA, tetB, radiusA, radiusB);
2622 Real depth = sat.depth();
2623
2624 if (REAL_LESS(depth, 0) && REAL_GREAT(depth, -REAL_infinity))
2625 {
2626 m.normal = sat.normal(); // contact normal on tetB
2627
2628 setupContactOnTet(m, sat, tetA, tetB, radiusA, radiusB);
2629 }
2630 else m.contactCount = 0;
2631 }
2632
2633 // ---------------------------------------- [Box - Tet] ----------------------------------------
2634
2635 template<typename Real>
2636 DYN_FUNC void CollisionDetection<Real>::MSDF(SeparationData& sat, const OBox3D& boxA, const Tet3D& tetB, const Real radiusA, const Real radiusB)
2637 {
2638 auto checkAxisP = [&](Vec3f pA, Vec3f pB) { checkAxisPoint(sat, boxA, tetB, radiusA, radiusB, pA, pB); };
2639 auto checkAxisE = [&](Segment3D edgeA, Segment3D edgeB) { checkAxisEdge(sat, boxA, tetB, radiusA, radiusB, edgeA, edgeB); };
2640 auto checkAxisT = [&](Triangle3D face) { checkAxisTri(sat, boxA, tetB, radiusA, radiusB, face, CT_TRIB); };
2641 auto checkAxisR = [&](Rectangle3D face) { checkAxisRect(sat, boxA, tetB, radiusA, radiusB, face, CT_RECTA); };
2642
2643 // Minkowski Face Normal
2644 // face
2645 // box face
2646 for (int j = 0; j < 6; j++) checkAxisR(boxA.face(j));
2647 checkAxisT(tetB.face(0));
2648 checkAxisT(tetB.face(1));
2649 checkAxisT(tetB.face(2));
2650 checkAxisT(tetB.face(3));
2651
2652
2653 // Minkowski Edge-Edge Normal
2654 // boxA x tetB
2655 for (int i = 0; i < 12; i++)
2656 for (int j = 0; j < 6; j++)
2657 {
2658 checkAxisE(boxA.edge(i), tetB.edge(j));
2659 }
2660
2661 // Minkowski Point-Point Normal
2662 for (int j = 0; j < 8; j++)
2663 {
2664 Vec3f pA = boxA.vertex(j).origin;
2665 Point3D queryP(pA);
2666 Point3D projP = queryP.project(tetB);
2667 checkAxisP(pA, projP.origin);
2668 }
2669
2670 for (int j = 0; j < 4; j++)
2671 {
2672 Vec3f pB = tetB.v[j];
2673 Point3D queryP(pB);
2674 Point3D projP = queryP.project(boxA);
2675 checkAxisP(projP.origin, pB);
2676 }
2677 }
2678
2679 /*
2680 template<typename Real>
2681 DYN_FUNC void CollisionDetection<Real>::MSDF(const OBox3D& boxA, const Tet3D& tetB, Real& depth, Coord3D& normal, Real& boundaryA, Real& boundaryB, const Real radiusA, const Real radiusB)
2682 {
2683 depth = -REAL_infinity;
2684 bool sign = true; // < 0
2685 auto checkAxis = [&](Vec3f N)
2686 {
2687 Real D = 0;
2688 Real bA, bB;
2689 if (N.norm() > EPSILON) N /= N.norm(); else return;
2690 checkSignedDistanceAxis(D, bA, bB, N, boxA, tetB, radiusA, radiusB);
2691
2692 updateSDF(boundaryA, boundaryB, depth, normal, bA, bB, D, N);
2693 };
2694 Vec3f axisTmp;
2695
2696 // Minkowski Face Normal
2697 // 1. Box face (u, v, w)
2698 axisTmp = boxA.u / boxA.u.norm(); checkAxis(axisTmp);
2699 axisTmp = boxA.v / boxA.v.norm(); checkAxis(axisTmp);
2700 axisTmp = boxA.w / boxA.w.norm(); checkAxis(axisTmp);
2701
2702 // 2. tet face
2703 axisTmp = tetB.face(0).normal(); checkAxis(axisTmp);
2704 axisTmp = tetB.face(1).normal(); checkAxis(axisTmp);
2705 axisTmp = tetB.face(2).normal(); checkAxis(axisTmp);
2706 axisTmp = tetB.face(3).normal(); checkAxis(axisTmp);
2707
2708 // 2. edge cross
2709 for (int i = 0; i < 3; i++)
2710 {
2711 Vec3f boxDir = (i == 0) ? (boxA.u) : ((i == 1) ? (boxA.v) : (boxA.w));
2712 for (int j = 0; j < 3; j++)
2713 for (int k = j + 1; k < 4; k++)
2714 {
2715 Vec3f tetDir = tetB.v[k] - tetB.v[j];
2716 axisTmp = boxDir.cross(tetDir);
2717 checkAxis(axisTmp);
2718 }
2719 }
2720
2721 // Minkowski Point-Edge Normal
2722 // check direction of minimum distance from B's point to A's edge
2723 for (int j = 0; j < 4; j++)
2724 {
2725 Vec3f pB = tetB.v[j];
2726 Point3D queryP(pB);
2727 Point3D projP = queryP.project(boxA);
2728 axisTmp = (projP - queryP).direction();
2729 checkAxis(axisTmp);
2730 }
2731 }
2732 */
2733
2734
2735 template<typename Real>
2736 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const Tet3D& tetA, const OBox3D& boxB, const Real radiusA, const Real radiusB)
2737 {
2738 SeparationData sat;
2739 // Contact normal on tetA
2740 MSDF(sat, boxB, tetA, radiusA, radiusB);
2741 Real depth = sat.depth();
2742
2743 if (REAL_LESS(depth, 0) && REAL_GREAT(depth, -REAL_infinity))
2744 {
2745 sat.reverse(); // contact normal on boxB
2746 m.normal = sat.normal();
2747
2748 setupContactOnBox(m, sat, tetA, boxB, radiusA, radiusB);
2749 }
2750 else m.contactCount = 0;
2751 }
2752
2753 template<typename Real>
2754 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const OBox3D& boxA, const Tet3D& tetB, const Real radiusA, const Real radiusB)
2755 {
2756 SeparationData sat;
2757 // Contact normal on tetB
2758 MSDF(sat, boxA, tetB, radiusA, radiusB);
2759 Real depth = sat.depth();
2760
2761 if (REAL_LESS(depth, 0) && REAL_GREAT(depth, -REAL_infinity))
2762 {
2763 m.normal = sat.normal(); // contact normal on tetB
2764
2765 setupContactOnTet(m, sat, boxA, tetB, radiusA, radiusB);
2766 }
2767 else m.contactCount = 0;
2768 }
2769
2770 // ---------------------------------------- [Box - Box] ----------------------------------------
2771
2772 template<typename Real>
2773 DYN_FUNC void CollisionDetection<Real>::MSDF(SeparationData& sat, const OBox3D& boxA, const OBox3D& boxB, const Real radiusA, const Real radiusB)
2774 {
2775 auto checkAxisP = [&](Vec3f pA, Vec3f pB) { checkAxisPoint(sat, boxA, boxB, radiusA, radiusB, pA, pB); };
2776 auto checkAxisE = [&](Segment3D edgeA, Segment3D edgeB) { checkAxisEdge(sat, boxA, boxB, radiusA, radiusB, edgeA, edgeB); };
2777 auto checkAxisR = [&](Rectangle3D face, auto type) { checkAxisRect(sat, boxA, boxB, radiusA, radiusB, face, type); };
2778
2779 // Minkowski Face Normal
2780 // face
2781 // box face
2782 for (int j = 0; j < 6; j++) checkAxisR(boxA.face(j), CT_RECTA);
2783 for (int j = 0; j < 6; j++) checkAxisR(boxB.face(j), CT_RECTB);
2784
2785
2786 // Minkowski Edge-Edge Normal
2787 // boxA x boxB
2788 for (int i = 0; i < 12; i++)
2789 for (int j = 0; j < 12; j++)
2790 {
2791 checkAxisE(boxA.edge(i), boxB.edge(j));
2792 }
2793
2794 // Minkowski Point-Point Normal
2795 for (int j = 0; j < 8; j++)
2796 {
2797 Vec3f pA = boxA.vertex(j).origin;
2798 Point3D queryP(pA);
2799 Point3D projP = queryP.project(boxB);
2800 checkAxisP(pA, projP.origin);
2801 }
2802
2803 for (int j = 0; j < 8; j++)
2804 {
2805 Vec3f pB = boxB.vertex(j).origin;
2806 Point3D queryP(pB);
2807 Point3D projP = queryP.project(boxA);
2808 checkAxisP(projP.origin, pB);
2809 }
2810 }
2811
2812 /*
2813 template<typename Real>
2814 DYN_FUNC void CollisionDetection<Real>::MSDF(const OBox3D& boxA, const OBox3D& boxB, Real& depth, Coord3D& normal, Real& boundaryA, Real& boundaryB, const Real radiusA, const Real radiusB)
2815 {
2816 depth = -REAL_infinity;
2817 bool sign = true; // < 0
2818 auto checkAxis = [&](Vec3f N)
2819 {
2820 Real D = 0;
2821 Real bA, bB;
2822 if (N.norm() > EPSILON) N /= N.norm(); else return;
2823 checkSignedDistanceAxis(D, bA, bB, N, boxA, boxB, radiusA, radiusB);
2824
2825 updateSDF(boundaryA, boundaryB, depth, normal, bA, bB, D, N);
2826 };
2827 Vec3f axisTmp;
2828
2829 // Minkowski Face Normal
2830 // 1. BoxA face (u, v, w)
2831 axisTmp = boxA.u / boxA.u.norm(); checkAxis(axisTmp);
2832 axisTmp = boxA.v / boxA.v.norm(); checkAxis(axisTmp);
2833 axisTmp = boxA.w / boxA.w.norm(); checkAxis(axisTmp);
2834
2835 // 2. BoxB face (u, v, w)
2836 axisTmp = boxB.u / boxB.u.norm(); checkAxis(axisTmp);
2837 axisTmp = boxB.v / boxB.v.norm(); checkAxis(axisTmp);
2838 axisTmp = boxB.w / boxB.w.norm(); checkAxis(axisTmp);
2839
2840 // 3. boxA's edge x boxB's edge
2841 for (int i = 0; i < 3; i++)
2842 {
2843 Vec3f boxDirA = (i == 0) ? (boxA.u) : ((i == 1) ? (boxA.v) : (boxA.w));
2844 for (int j = 0; j < 3; j++)
2845 {
2846 Vec3f boxDirB = (j == 0) ? (boxB.u) : ((j == 1) ? (boxB.v) : (boxB.w));
2847 axisTmp = boxDirA.cross(boxDirB);
2848 checkAxis(axisTmp);
2849 }
2850 }
2851
2852 // Minkowski Point-Edge Normal
2853 // check direction of minimum distance from B's point to A's edge
2854 for (int i = 0; i < 8; i++)
2855 {
2856 Vec3f pB = boxB.center + ((i & 4) ? 1 : -1) * boxB.u * boxB.extent[0]
2857 + ((i & 2) ? 1 : -1) * boxB.v * boxB.extent[1]
2858 + ((i & 1) ? 1 : -1) * boxB.w * boxB.extent[2];
2859 Point3D queryP(pB);
2860 Point3D projP = queryP.project(boxA);
2861 axisTmp = (projP - queryP).direction();
2862 checkAxis(axisTmp);
2863 }
2864 }
2865 */
2866
2867 template<typename Real>
2868 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const OBox3D& boxA, const OBox3D& boxB, const Real radiusA, const Real radiusB)
2869 {
2870 SeparationData sat;
2871 // Contact normal on boxB
2872 MSDF(sat, boxA, boxB, radiusA, radiusB);
2873 Real depth = sat.depth();
2874
2875 if (REAL_LESS(depth, 0) && REAL_GREAT(depth, -REAL_infinity))
2876 {
2877 m.normal = sat.normal(); // contact normal on boxB
2878
2879 setupContactOnBox(m, sat, boxA, boxB, radiusA, radiusB);
2880 }
2881 else m.contactCount = 0;
2882 }
2883
2884
2885 //--------------------------------------------------------------------------------------------------
2886 template<typename Real>
2888 {
2889 n = rot.transpose()*n;
2890 Vector<Real, 3> absN = abs(n);
2891 Vector<Real, 3> a, b;
2892
2893 // x > y
2894 if (absN.x > absN.y)
2895 {
2896 // x > y > z
2897 if (absN.y > absN.z)
2898 {
2899 a = Vector<Real, 3>(e.x, e.y, e.z);
2900 b = Vector<Real, 3>(e.x, e.y, -e.z);
2901 }
2902 // x > z > y || z > x > y
2903 else
2904 {
2905 a = Vector<Real, 3>(e.x, e.y, e.z);
2906 b = Vector<Real, 3>(e.x, -e.y, e.z);
2907 }
2908 }
2909
2910 // y > x
2911 else
2912 {
2913 // y > x > z
2914 if (absN.x > absN.z)
2915 {
2916 a = Vector<Real, 3>(e.x, e.y, e.z);
2917 b = Vector<Real, 3>(e.x, e.y, -e.z);
2918 }
2919 // z > y > x || y > z > x
2920 else
2921 {
2922 a = Vector<Real, 3>(e.x, e.y, e.z);
2923 b = Vector<Real, 3>(-e.x, e.y, e.z);
2924 }
2925 }
2926
2927 Real signx = fsign(n.x);
2928 Real signy = fsign(n.y);
2929 Real signz = fsign(n.z);
2930
2931 a.x *= signx;
2932 a.y *= signy;
2933 a.z *= signz;
2934 b.x *= signx;
2935 b.y *= signy;
2936 b.z *= signz;
2937
2938 aOut = rot * a + trans;
2939 bOut = rot * b + trans;
2940 }
2941
2942 template<typename Real>
2943 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const OBox3D box0, const OBox3D box1)
2944 {
2945 m.contactCount = 0;
2946
2947 Vector<Real, 3> v = box1.center - box0.center;
2948
2949 Vector<Real, 3> eA = box0.extent;
2950 Vector<Real, 3> eB = box1.extent;
2951
2952 Matrix3D rotA;
2953 rotA.setCol(0, box0.u);
2954 rotA.setCol(1, box0.v);
2955 rotA.setCol(2, box0.w);
2956
2957 Matrix3D rotB;
2958 rotB.setCol(0, box1.u);
2959 rotB.setCol(1, box1.v);
2960 rotB.setCol(2, box1.w);
2961
2962 // B's frame in A's space
2963 Matrix3D C = rotA.transpose() * rotB;
2964 Matrix3D absC;
2965 bool parallel = false;
2966 const float kCosTol = float(1.0e-6);
2967 for (int i = 0; i < 3; ++i)
2968 {
2969 for (int j = 0; j < 3; ++j)
2970 {
2971 float val = abs(C(i, j));
2972 absC(i, j) = val;
2973
2974 if (val + kCosTol >= float(1.0))
2975 parallel = true;
2976 }
2977 }
2978
2979 Matrix3D C_t = C.transpose();
2980 Matrix3D absC_t = absC.transpose();
2981
2982 // Vector from center A to center B in A's space
2983 Vector<Real, 3> t = rotA.transpose() * v;
2984
2985 // Query states
2986 Real s;
2987 Real aMax = -REAL_MAX;
2988 Real bMax = -REAL_MAX;
2989 float eMax = -REAL_MAX;
2990 int aAxis = ~0;
2991 int bAxis = ~0;
2992 int eAxis = ~0;
2993 Vector<Real, 3> nA;
2994 Vector<Real, 3> nB;
2995 Vector<Real, 3> nE;
2996
2997 // Face axis checks
2998
2999 // a's x axis
3000 s = abs(t.x) - (box0.extent.x + absC_t.col(0).dot(box1.extent));
3001 if (trackFaceAxis(aAxis, aMax, nA, 0, s, rotA.col(0)))
3002 return;
3003
3004 // a's y axis
3005 s = abs(t.y) - (box0.extent.y + absC_t.col(1).dot(box1.extent));
3006 if (trackFaceAxis(aAxis, aMax, nA, 1, s, rotA.col(1)))
3007 return;
3008
3009 // a's z axis
3010 s = abs(t.z) - (box0.extent.z + absC_t.col(2).dot(box1.extent));
3011 if (trackFaceAxis(aAxis, aMax, nA, 2, s, rotA.col(2)))
3012 return;
3013
3014 // b's x axis
3015 s = abs(t.dot(C.col(0))) - (box1.extent.x + absC.col(0).dot(box0.extent));
3016 if (trackFaceAxis(bAxis, bMax, nB, 3, s, rotB.col(0)))
3017 return;
3018
3019 // b's y axis
3020 s = abs(t.dot(C.col(1))) - (box1.extent.y + absC.col(1).dot(box0.extent));
3021 if (trackFaceAxis(bAxis, bMax, nB, 4, s, rotB.col(1)))
3022 return;
3023
3024 // b's z axis
3025 s = abs(t.dot(C.col(2))) - (box1.extent.z + absC.col(2).dot(box0.extent));
3026 if (trackFaceAxis(bAxis, bMax, nB, 5, s, rotB.col(2)))
3027 return;
3028
3029 if (!parallel)
3030 {
3031 // Edge axis checks
3032 float rA;
3033 float rB;
3034
3035 // Cross( a.x, b.x )
3036 rA = eA.y * absC(2, 0) + eA.z * absC(1, 0);
3037 rB = eB.y * absC(0, 2) + eB.z * absC(0, 1);
3038 s = abs(t.z * C(1, 0) - t.y * C(2, 0)) - (rA + rB);
3039 if (trackEdgeAxis(eAxis, eMax, nE, 6, s, Vector<Real, 3>(float(0.0), -C(2, 0), C(1, 0))))
3040 return;
3041
3042 // Cross( a.x, b.y )
3043 rA = eA.y * absC(2, 1) + eA.z * absC(1, 1);
3044 rB = eB.x * absC(0, 2) + eB.z * absC(0, 0);
3045 s = abs(t.z * C(1, 1) - t.y * C(2, 1)) - (rA + rB);
3046 if (trackEdgeAxis(eAxis, eMax, nE, 7, s, Vector<Real, 3>(float(0.0), -C(2, 1), C(1, 1))))
3047 return;
3048
3049 // Cross( a.x, b.z )
3050 rA = eA.y * absC(2, 2) + eA.z * absC(1, 2);
3051 rB = eB.x * absC(0, 1) + eB.y * absC(0, 0);
3052 s = abs(t.z * C(1, 2) - t.y * C(2, 2)) - (rA + rB);
3053 if (trackEdgeAxis(eAxis, eMax, nE, 8, s, Vector<Real, 3>(float(0.0), -C(2, 2), C(1, 2))))
3054 return;
3055
3056 // Cross( a.y, b.x )
3057 rA = eA.x * absC(2, 0) + eA.z * absC(0, 0);
3058 rB = eB.y * absC(1, 2) + eB.z * absC(1, 1);
3059 s = abs(t.x * C(2, 0) - t.z * C(0, 0)) - (rA + rB);
3060 if (trackEdgeAxis(eAxis, eMax, nE, 9, s, Vector<Real, 3>(C(2, 0), float(0.0), -C(0, 0))))
3061 return;
3062
3063 // Cross( a.y, b.y )
3064 rA = eA.x * absC(2, 1) + eA.z * absC(0, 1);
3065 rB = eB.x * absC(1, 2) + eB.z * absC(1, 0);
3066 s = abs(t.x * C(2, 1) - t.z * C(0, 1)) - (rA + rB);
3067 if (trackEdgeAxis(eAxis, eMax, nE, 10, s, Vector<Real, 3>(C(2, 1), float(0.0), -C(0, 1))))
3068 return;
3069
3070 // Cross( a.y, b.z )
3071 rA = eA.x * absC(2, 2) + eA.z * absC(0, 2);
3072 rB = eB.x * absC(1, 1) + eB.y * absC(1, 0);
3073 s = abs(t.x * C(2, 2) - t.z * C(0, 2)) - (rA + rB);
3074 if (trackEdgeAxis(eAxis, eMax, nE, 11, s, Vector<Real, 3>(C(2, 2), float(0.0), -C(0, 2))))
3075 return;
3076
3077 // Cross( a.z, b.x )
3078 rA = eA.x * absC(1, 0) + eA.y * absC(0, 0);
3079 rB = eB.y * absC(2, 2) + eB.z * absC(2, 1);
3080 s = abs(t.y * C(0, 0) - t.x * C(1, 0)) - (rA + rB);
3081 if (trackEdgeAxis(eAxis, eMax, nE, 12, s, Vector<Real, 3>(-C(1, 0), C(0, 0), float(0.0))))
3082 return;
3083
3084 // Cross( a.z, b.y )
3085 rA = eA.x * absC(1, 1) + eA.y * absC(0, 1);
3086 rB = eB.x * absC(2, 2) + eB.z * absC(2, 0);
3087 s = abs(t.y * C(0, 1) - t.x * C(1, 1)) - (rA + rB);
3088 if (trackEdgeAxis(eAxis, eMax, nE, 13, s, Vector<Real, 3>(-C(1, 1), C(0, 1), float(0.0))))
3089 return;
3090
3091 // Cross( a.z, b.z )
3092 rA = eA.x * absC(1, 2) + eA.y * absC(0, 2);
3093 rB = eB.x * absC(2, 1) + eB.y * absC(2, 0);
3094 s = abs(t.y * C(0, 2) - t.x * C(1, 2)) - (rA + rB);
3095 if (trackEdgeAxis(eAxis, eMax, nE, 14, s, Vector<Real, 3>(-C(1, 2), C(0, 2), float(0.0))))
3096 return;
3097 }
3098
3099 // Artificial axis bias to improve frame coherence
3100 const float kRelTol = float(0.95);
3101 const float kAbsTol = float(0.01);
3102 int axis;
3103 float sMax;
3105 float faceMax = std::max(aMax, bMax);
3106 if (kRelTol * eMax > faceMax + kAbsTol)
3107 {
3108 axis = eAxis;
3109 sMax = eMax;
3110 n = nE;
3111 }
3112 else
3113 {
3114 if (kRelTol * bMax > aMax + kAbsTol)
3115 {
3116 axis = bAxis;
3117 sMax = bMax;
3118 n = nB;
3119 }
3120 else
3121 {
3122 axis = aAxis;
3123 sMax = aMax;
3124 n = nA;
3125 }
3126 }
3127
3128 if (n.dot(v) < float(0.0))
3129 n = -n;
3130
3131 if (axis == ~0)
3132 return;
3133
3134 Transform3D atx(box0.center, rotA);
3135 Transform3D btx(box1.center, rotB);
3136
3137 if (axis < 6)
3138 {
3139 Transform3D rtx;
3140 Transform3D itx;
3141 Vector<Real, 3> eR;
3142 Vector<Real, 3> eI;
3143 bool flip;
3144
3145 if (axis < 3)
3146 {
3147 rtx = atx;
3148 itx = btx;
3149 eR = eA;
3150 eI = eB;
3151 flip = false;
3152 }
3153 else
3154 {
3155 rtx = btx;
3156 itx = atx;
3157 eR = eB;
3158 eI = eA;
3159 flip = true;
3160 n = -n;
3161 }
3162
3163 // Compute reference and incident edge information necessary for clipping
3164 ClipVertex incident[4];
3165 computeIncidentFace(incident, itx, eI, n);
3166 unsigned char clipEdges[4];
3167 Matrix3D basis;
3169 computeReferenceEdgesAndBasis(clipEdges, &basis, &e, eR, rtx, n, axis);
3170
3171 // Clip the incident face against the reference face side planes
3172 ClipVertex out[8];
3173 float depths[8];
3174 int outNum;
3175 outNum = clip(out, depths, rtx.translation(), e, clipEdges, basis, incident);
3176
3177 if (outNum)
3178 {
3179 m.contactCount = outNum;
3180 m.normal = flip ? -n : n;
3181
3182 for (int i = 0; i < outNum; ++i)
3183 {
3184 m.contacts[i].position = flip ? (out[i].v + depths[i] * m.normal) : out[i].v;
3185 m.contacts[i].penetration = depths[i];
3186 }
3187 }
3188 }
3189 else
3190 {
3191 n = rotA * n;
3192
3193 if (n.dot(v) < float(0.0))
3194 n = -n;
3195
3196 Vector<Real, 3> PA, QA;
3197 Vector<Real, 3> PB, QB;
3198 computeSupportEdge(PA, QA, rotA, box0.center, eA, n);
3199 computeSupportEdge(PB, QB, rotB, box1.center, eB, -n);
3200
3201 Vector<Real, 3> CA, CB;
3202 edgesContact(CA, CB, PA, QA, PB, QB);
3203
3204 m.normal = n;
3205 m.contactCount = 1;
3206
3207 m.contacts[0].penetration = sMax;
3208 m.contacts[0].position = CB;
3209 }
3210 }
3211
3212 template<typename Real>
3213 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const Sphere3D& sphere, const OBox3D& box)
3214 {
3215 m.contactCount = 0;
3216
3217 Point3D c0(sphere.center);
3218 Real r0 = sphere.radius;
3219
3220 Point3D vproj = c0.project(box);
3221 bool bInside = c0.inside(box);
3222
3223 Segment3D dir = bInside ? c0 - vproj : vproj - c0;
3224 Real sMax = bInside ? -dir.direction().norm() - r0 : dir.direction().norm() - r0;
3225
3226 if (sMax >= 0)
3227 return;
3228
3229 m.normal = dir.direction().normalize();
3230 m.contacts[0].penetration = sMax;
3231 m.contacts[0].position = vproj.origin;
3232 m.contactCount = 1;
3233 }
3234
3235
3236 template<typename Real>
3237 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const Capsule3D& cap0, const Capsule3D& cap1)
3238 {
3239 m.contactCount = 0;
3240
3241 Segment3D s0(cap0.centerline());
3242 Segment3D s1(cap1.centerline());
3243 Real r0 = cap0.radius + cap1.radius;
3244
3245 auto n0 = s0.direction().normalize();
3246 auto n1 = s1.direction().normalize();
3247
3248 Vector<Real, 3> s0xs1 = n0.cross(n1);
3249
3250 Real absTol = Real(0.0001);
3251
3252 bool parallel = s0xs1.norm() < absTol ? true : false;
3253 bool overlap = true;
3254 //If parallel
3255 if (parallel)
3256 {
3257 TLine3D<Real> line(s0.v0, s0.direction());
3258
3259 TPoint3D<Real> p0 = TPoint3D<Real>(s1.v0).project(line);
3260 TPoint3D<Real> p1 = TPoint3D<Real>(s1.v1).project(line);
3261
3262 Vector<Real, 3> dir = s1.v0 - p0.origin;
3263 Real d = dir.norm();
3264 Real interpenetration = d - r0;
3265
3266 if (interpenetration >= 0)
3267 return;
3268
3269 Real t0 = s0.parameter(p0.origin);
3270 Real t1 = s0.parameter(p1.origin);
3271
3272 auto interval = Interval<Real>(0, 1).intersect(Interval<Real>(t0, t1));
3273
3274 if (!interval.isEmpty())
3275 {
3276 Vector<Real, 3> clamp_p0 = s0.v0 + interval.leftLimit() * s0.direction();
3277 Vector<Real, 3> clamp_p1 = s0.v0 + interval.rightLimit() * s0.direction();
3278
3279 m.normal = dir.normalize();
3280 m.contacts[0].penetration = interpenetration;
3281 m.contacts[0].position = clamp_p0 + (cap0.radius + interpenetration) * m.normal;
3282 m.contacts[1].penetration = interpenetration;
3283 m.contacts[1].position = clamp_p1 + (cap0.radius + interpenetration) * m.normal;
3284 m.contactCount = 2;
3285 }
3286 else
3287 {
3288 overlap = false;
3289 }
3290 }
3291
3292 if (!parallel || (parallel && !overlap))
3293 {
3294 // From cap0 to cap1
3295 Segment3D dir = s0.proximity(s1);
3296
3297 dir = Point3D(dir.endPoint()) - Point3D(dir.startPoint());
3298
3299 Real sMax = dir.direction().norm() - r0;
3300 if (sMax >= 0)
3301 return;
3302
3303 m.normal = dir.direction().normalize();
3304 m.contacts[0].penetration = sMax;
3305 m.contacts[0].position = dir.v0 + (cap0.radius + sMax) * m.normal;
3306 m.contactCount = 1;
3307 }
3308 }
3309
3310
3311 template<typename Real>
3312 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const Sphere3D& sphere, const Capsule3D& cap)
3313 {
3314 m.contactCount = 0;
3315
3316 Point3D s(sphere.center);
3317 Segment3D c(cap.centerline());
3318 Real r0 = cap.radius + sphere.radius;
3319
3320 Point3D pos = s.project(c);//pos: capsule
3321
3322 // From sphere to capsule
3323 Segment3D dir = pos - s;
3324
3325 Real sMax = dir.direction().norm() - r0;
3326 if (sMax >= 0)
3327 return;
3328
3329 m.normal = dir.direction().normalize();
3330 m.contacts[0].penetration = sMax;
3331 m.contacts[0].position = dir.v0 + (sphere.radius + sMax) * m.normal;
3332 m.contactCount = 1;
3333 }
3334
3335 template<typename Real>
3336 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const Capsule3D& cap, const Sphere3D& sphere)
3337 {
3338 request(m, sphere, cap);
3339
3340 swapContactPair(m);
3341 }
3342
3343 template<typename Real>
3344 DYN_FUNC inline bool checkOverlapAxis(
3345 Real& lowerBoundary1,
3346 Real& upperBoundary1,
3347 Real& lowerBoundary2,
3348 Real& upperBoundary2,
3349 Real& intersectionDistance,
3350 Real& boundary1,
3351 Real& boundary2,
3352 const Vector<Real, 3> axisNormal,
3353 OrientedBox3D box,
3354 Capsule3D cap
3355 )
3356 {
3357
3358 //projection to axis
3359 Segment3D seg = cap.centerline();
3360
3361 lowerBoundary1 = seg.v0.dot(axisNormal) - cap.radius;
3362 upperBoundary1 = seg.v0.dot(axisNormal) + cap.radius;
3363 lowerBoundary1 = glm::min(lowerBoundary1, seg.v1.dot(axisNormal) - cap.radius);
3364 upperBoundary1 = glm::max(upperBoundary1, seg.v1.dot(axisNormal) + cap.radius);
3365
3366
3367 Vector<Real, 3> center = box.center;
3368 Vector<Real, 3> u = box.u;
3369 Vector<Real, 3> v = box.v;
3370 Vector<Real, 3> w = box.w;
3371 Vector<Real, 3> extent = box.extent;
3373 p = (center - u * extent[0] - v * extent[1] - w * extent[2]);
3374 lowerBoundary2 = upperBoundary2 = p.dot(axisNormal);
3375
3376 p = (center - u * extent[0] - v * extent[1] + w * extent[2]);
3377 lowerBoundary2 = glm::min(lowerBoundary2, p.dot(axisNormal));
3378 upperBoundary2 = glm::max(upperBoundary2, p.dot(axisNormal));
3379
3380 p = (center - u * extent[0] + v * extent[1] - w * extent[2]);
3381 lowerBoundary2 = glm::min(lowerBoundary2, p.dot(axisNormal));
3382 upperBoundary2 = glm::max(upperBoundary2, p.dot(axisNormal));
3383
3384 p = (center - u * extent[0] + v * extent[1] + w * extent[2]);
3385 lowerBoundary2 = glm::min(lowerBoundary2, p.dot(axisNormal));
3386 upperBoundary2 = glm::max(upperBoundary2, p.dot(axisNormal));
3387
3388 p = (center + u * extent[0] - v * extent[1] - w * extent[2]);
3389 lowerBoundary2 = glm::min(lowerBoundary2, p.dot(axisNormal));
3390 upperBoundary2 = glm::max(upperBoundary2, p.dot(axisNormal));
3391
3392 p = (center + u * extent[0] - v * extent[1] + w * extent[2]);
3393 lowerBoundary2 = glm::min(lowerBoundary2, p.dot(axisNormal));
3394 upperBoundary2 = glm::max(upperBoundary2, p.dot(axisNormal));
3395
3396 p = (center + u * extent[0] + v * extent[1] - w * extent[2]);
3397 lowerBoundary2 = glm::min(lowerBoundary2, p.dot(axisNormal));
3398 upperBoundary2 = glm::max(upperBoundary2, p.dot(axisNormal));
3399
3400 p = (center + u * extent[0] + v * extent[1] + w * extent[2]);
3401 lowerBoundary2 = glm::min(lowerBoundary2, p.dot(axisNormal));
3402 upperBoundary2 = glm::max(upperBoundary2, p.dot(axisNormal));
3403
3404 return checkOverlap(lowerBoundary1, upperBoundary1, lowerBoundary2, upperBoundary2, intersectionDistance, boundary1, boundary2);
3405 }
3406
3407 template<typename Real>
3408 DYN_FUNC inline bool checkOverlapTetTri(
3409 Real lowerBoundary1,
3410 Real upperBoundary1,
3411 Real lowerBoundary2,
3412 Real upperBoundary2,
3413 Real& intersectionDistance,
3414 Real& boundary1,
3415 Real& boundary2
3416 )
3417 {
3418 if (!((lowerBoundary1 > upperBoundary2) || (lowerBoundary2 > upperBoundary1)))
3419 {
3420 if (lowerBoundary1 < lowerBoundary2)
3421 {
3422 if (upperBoundary1 > upperBoundary2)
3423 {
3424 if (upperBoundary2 - lowerBoundary1 > upperBoundary1 - lowerBoundary2)
3425 {
3426 boundary1 = upperBoundary1;
3427 boundary2 = lowerBoundary2;
3428 intersectionDistance = abs(boundary1 - boundary2);
3429 }
3430 else
3431 {
3432 boundary1 = lowerBoundary1;
3433 boundary2 = upperBoundary2;
3434 intersectionDistance = abs(boundary1 - boundary2);
3435 }
3436 }
3437 else
3438 {
3439 intersectionDistance = upperBoundary1 - lowerBoundary2;
3440 boundary1 = upperBoundary1;
3441 boundary2 = lowerBoundary2;
3442 }
3443 }
3444 else
3445 {
3446 if (upperBoundary1 > upperBoundary2)
3447 {
3448 intersectionDistance = upperBoundary2 - lowerBoundary1;
3449 boundary1 = lowerBoundary1;
3450 boundary2 = upperBoundary2;
3451 }
3452 else
3453 {
3454 //intersectionDistance = upperBoundary1 - lowerBoundary1;
3455 if (upperBoundary2 - lowerBoundary1 > upperBoundary1 - lowerBoundary2)
3456 {
3457 boundary1 = upperBoundary1;
3458 boundary2 = lowerBoundary2;
3459 intersectionDistance = abs(boundary1 - boundary2);
3460 }
3461 else
3462 {
3463 boundary1 = lowerBoundary1;
3464 boundary2 = upperBoundary2;
3465 intersectionDistance = abs(boundary1 - boundary2);
3466 }
3467 }
3468 }
3469 return true;
3470 }
3471 intersectionDistance = Real(0.0f);
3472 return false;
3473 }
3474
3475 template<typename Real>
3476 DYN_FUNC inline bool checkOverlapAxis(
3477 Real& lowerBoundary1,
3478 Real& upperBoundary1,
3479 Real& lowerBoundary2,
3480 Real& upperBoundary2,
3481 Real& intersectionDistance,
3482 Real& boundary1,
3483 Real& boundary2,
3484 const Vector<Real, 3> axisNormal,
3485 Tet3D tet,
3486 Capsule3D cap)
3487 {
3488
3489 Segment3D seg = cap.centerline();
3490 //projection to axis
3491
3492 lowerBoundary1 = seg.v0.dot(axisNormal) - cap.radius;
3493 upperBoundary1 = seg.v0.dot(axisNormal) + cap.radius;
3494 lowerBoundary1 = glm::min(lowerBoundary1, seg.v1.dot(axisNormal) - cap.radius);
3495 upperBoundary1 = glm::max(upperBoundary1, seg.v1.dot(axisNormal) + cap.radius);
3496
3497 for (int i = 0; i < 4; i++)
3498 {
3499 if (i == 0)
3500 {
3501
3502 lowerBoundary2 = upperBoundary2 = tet.v[0].dot(axisNormal);
3503 }
3504 else
3505 {
3506 lowerBoundary2 = glm::min(lowerBoundary2, tet.v[i].dot(axisNormal));
3507 upperBoundary2 = glm::max(upperBoundary2, tet.v[i].dot(axisNormal));
3508 }
3509 }
3510
3511
3512 return checkOverlapTetTri(lowerBoundary1, upperBoundary1, lowerBoundary2, upperBoundary2, intersectionDistance, boundary1, boundary2);
3513 }
3514
3515
3516 template<typename Real>
3517 DYN_FUNC inline void setupContactCaps(
3518 Real boundary1,
3519 Real boundary2,
3520 const Vector<Real, 3> axisNormal,
3521 TCapsule3D<Real> cap,
3523 Real depth,
3524 TManifold<Real>& m)
3525 {
3526 // Gen contact point on box
3527 // On box vertex
3528
3529 // On box edge
3530
3531 // On box face
3532
3533 int cnt1, cnt2;
3534 Vector<Real, 3> boundaryPoints1[4];
3535 Vector<Real, 3> boundaryPoints2[8];
3536 cnt1 = cnt2 = 0;
3537
3538 Real boundaryMin = glm::min(boundary1, boundary2);
3539 Real boundaryMax = glm::max(boundary1, boundary2);
3540 if (abs(cap.startPoint().dot(axisNormal) - boundaryMin) < abs(depth))
3541 boundaryPoints1[cnt1++] = cap.startPoint();
3542 if (abs(cap.endPoint().dot(axisNormal) - boundaryMin) < abs(depth))
3543 boundaryPoints1[cnt1++] = cap.endPoint();
3544
3545
3546 Vector<Real, 3> center = box.center;
3547 Vector<Real, 3> u = box.u;
3548 Vector<Real, 3> v = box.v;
3549 Vector<Real, 3> w = box.w;
3550 Vector<Real, 3> extent = box.extent;
3552 p = (center - u * extent[0] - v * extent[1] - w * extent[2]);
3553 if (abs(p.dot(axisNormal) - boundaryMin) < abs(depth))
3554 boundaryPoints2[cnt2++] = p;
3555
3556 p = (center - u * extent[0] - v * extent[1] + w * extent[2]);
3557 if (abs(p.dot(axisNormal) - boundaryMin) < abs(depth))
3558 boundaryPoints2[cnt2++] = p;
3559
3560 p = (center - u * extent[0] + v * extent[1] - w * extent[2]);
3561 if (abs(p.dot(axisNormal) - boundaryMin) < abs(depth))
3562 boundaryPoints2[cnt2++] = p;
3563
3564 p = (center - u * extent[0] + v * extent[1] + w * extent[2]);
3565 if (abs(p.dot(axisNormal) - boundaryMin) < abs(depth))
3566 boundaryPoints2[cnt2++] = p;
3567
3568 p = (center + u * extent[0] - v * extent[1] - w * extent[2]);
3569 if (abs(p.dot(axisNormal) - boundaryMin) < abs(depth))
3570 boundaryPoints2[cnt2++] = p;
3571
3572 p = (center + u * extent[0] - v * extent[1] + w * extent[2]);
3573 if (abs(p.dot(axisNormal) - boundaryMin) < abs(depth))
3574 boundaryPoints2[cnt2++] = p;
3575
3576 p = (center + u * extent[0] + v * extent[1] - w * extent[2]);
3577 if (abs(p.dot(axisNormal) - boundaryMin) < abs(depth))
3578 boundaryPoints2[cnt2++] = p;
3579
3580 p = (center + u * extent[0] + v * extent[1] + w * extent[2]);
3581 if (abs(p.dot(axisNormal) - boundaryMin) < abs(depth))
3582 boundaryPoints2[cnt2++] = p;
3583
3584 // printf("cnt1 = %d, cnt2 = %d, dep=%.3lf\n", cnt1, cnt2, depth);
3585 if (cnt1 == 1 || cnt2 == 1)
3586 {
3587 m.normal = (boundary1 < boundary2) ? -axisNormal : axisNormal;
3588 m.contacts[0].penetration = depth;
3589 m.contacts[0].position = (cnt1 == 1) ? boundaryPoints1[0] : boundaryPoints2[0];
3590 m.contactCount = 1;
3591 return;
3592 }
3593 else if (cnt1 == 2)
3594 {
3595 Segment3D s1 = cap.centerline();
3596
3597 if (cnt2 == 2)
3598 {
3599 Segment3D s2(boundaryPoints2[0], boundaryPoints2[1]);
3600 Segment3D dir = s1.proximity(s2);//v0: self v1: other
3601 m.normal = (boundary1 > boundary2) ? axisNormal : -axisNormal;
3602 m.contacts[0].penetration = depth;
3603 m.contacts[0].position = dir.v0;
3604 m.contactCount = 1;
3605 return;
3606 }
3607 else //cnt2 == 4
3608 {
3609 //if (cnt2 != 4)
3610 // printf("?????????\n");
3611
3612
3613 for (int tmp_i = 1; tmp_i < 4; tmp_i++)
3614 for (int tmp_j = tmp_i + 1; tmp_j < 4; tmp_j++)
3615 {
3616 if ((boundaryPoints2[tmp_i] - boundaryPoints2[0]).dot(boundaryPoints2[tmp_j] - boundaryPoints2[0]) < EPSILON)
3617 {
3618 int tmp_k = 1 + 2 + 3 - tmp_i - tmp_j;
3619 Vector<Real, 3> p2 = boundaryPoints2[tmp_i];
3620 Vector<Real, 3> p3 = boundaryPoints2[tmp_j];
3621 Vector<Real, 3> p4 = boundaryPoints2[tmp_k];
3622 boundaryPoints2[1] = p2;
3623 boundaryPoints2[2] = p3;
3624 boundaryPoints2[3] = p4;
3625 break;
3626 }
3627 }
3628
3629 //printf("%.3lf %.3lf %.3lf\n", boundaryPoints2[0][0], boundaryPoints2[0][1], boundaryPoints2[0][2]);
3630 //printf("%.3lf %.3lf %.3lf\n", boundaryPoints2[1][0], boundaryPoints2[1][1], boundaryPoints2[1][2]);
3631 //printf("%.3lf %.3lf %.3lf\n", boundaryPoints2[2][0], boundaryPoints2[2][1], boundaryPoints2[2][2]);
3632 //printf("%.3lf %.3lf %.3lf\n", boundaryPoints2[3][0], boundaryPoints2[3][1], boundaryPoints2[3][2]);
3633
3634 m.contactCount = 0;
3635 m.normal = (boundary1 > boundary2) ? axisNormal : -axisNormal;
3636 Triangle3D t2(boundaryPoints2[0], boundaryPoints2[1], boundaryPoints2[2]);
3637 Vector<Real, 3> dirTmp1 = Point3D(s1.v0).project(t2).origin - s1.v0;
3638 Vector<Real, 3> dirTmp2 = Point3D(s1.v1).project(t2).origin - s1.v1;
3639
3640 //printf("%.3lf %.3lf %.3lf\n", axisNormal[0], axisNormal[1], axisNormal[2]);
3641 //printf("%.3lf %.3lf %.3lf %.5lf %.5lf %.5lf\n", dirTmp1[0], dirTmp1[1], dirTmp1[2], dirTmp1.cross(axisNormal)[0], dirTmp1.cross(axisNormal)[1], dirTmp1.cross(axisNormal)[2]);
3642 //printf("%.3lf %.3lf %.3lf %.5lf %.5lf %.5lf\n", dirTmp2[0], dirTmp2[1], dirTmp2[2], dirTmp2.cross(axisNormal)[0], dirTmp2.cross(axisNormal)[1], dirTmp2.cross(axisNormal)[2]);
3643
3644
3645 if (dirTmp1.cross(axisNormal).norm() < 1e-4)
3646 {
3647 m.contacts[m.contactCount].penetration = depth;
3648 m.contacts[m.contactCount].position = s1.v0;
3649 m.contactCount++;
3650 }
3651 if (dirTmp2.cross(axisNormal).norm() < 1e-4)
3652 {
3653 m.contacts[m.contactCount].penetration = depth;
3654 m.contacts[m.contactCount].position = s1.v1;
3655 m.contactCount++;
3656 }
3657 t2 = Triangle3D(boundaryPoints2[3], boundaryPoints2[1], boundaryPoints2[2]);
3658 dirTmp1 = Point3D(s1.v0).project(t2).origin - s1.v0;
3659 dirTmp2 = Point3D(s1.v1).project(t2).origin - s1.v1;
3660
3661 //printf("%.3lf %.3lf %.3lf\n", dirTmp1[0], dirTmp1[1], dirTmp1[2]);
3662 //printf("%.3lf %.3lf %.3lf\n", dirTmp2[0], dirTmp2[1], dirTmp2[2]);
3663
3664 if (dirTmp1.cross(axisNormal).norm() < 1e-4)
3665 {
3666 m.contacts[m.contactCount].penetration = depth;
3667 m.contacts[m.contactCount].position = s1.v0;
3668 m.contactCount++;
3669 }
3670 if (dirTmp2.cross(axisNormal).norm() < 1e-4)
3671 {
3672 m.contacts[m.contactCount].penetration = depth;
3673 m.contacts[m.contactCount].position = s1.v1;
3674 m.contactCount++;
3675 }
3676 for (int i = 0; i < 4; i++)
3677 {
3678 Segment3D s2;
3679 if (i < 2)
3680 s2 = Segment3D(boundaryPoints2[0], boundaryPoints2[i]);
3681 else
3682 s2 = Segment3D(boundaryPoints2[3], boundaryPoints2[i - 2]);
3683 Segment3D dir = s1.proximity(s2);
3684 //printf("dir: %.3lf %.3lf %.3lf\naxisnormal %.3lf %.3lf %.3lf\n%.6lf\n",
3685 // dir.direction()[0], dir.direction()[1], dir.direction()[2],
3686 // axisNormal[0], axisNormal[1], axisNormal[2],
3687 // dir.direction().normalize().cross(axisNormal).norm());
3688 if ((!dir.isValid()) || dir.direction().normalize().cross(axisNormal).norm() < 1e-4)
3689 {
3690 //printf("Yes\n");
3691 if ((dir.v0 - s1.v0).norm() > 1e-4 && (dir.v0 - s1.v1).norm() > 1e-4)
3692 {
3693 m.contacts[m.contactCount].penetration = depth;
3694 m.contacts[m.contactCount].position = dir.v0;
3695 m.contactCount++;
3696 }
3697 }
3698 }
3699 }
3700 }
3701
3702 }
3703
3704 template<typename Real>
3705 DYN_FUNC inline void setupContactTets(
3706 Real boundary1,
3707 Real boundary2,
3708 const Vector<Real, 3> axisNormal,
3709 Tet3D tet,
3710 Capsule3D cap,
3711 Real sMax,
3712 TManifold<Real>& m)
3713 {
3714 int cnt1, cnt2;
3715 unsigned char boundaryPoints1[4], boundaryPoints2[4];
3716 cnt1 = cnt2 = 0;
3717
3718
3719
3720 for (unsigned char i = 0; i < 4; i++)
3721 {
3722 if (abs(tet.v[i].dot(axisNormal) - boundary1) < abs(sMax))
3723 boundaryPoints1[cnt1 ++] = i;
3724 }
3725
3726 if (abs(cap.startPoint().dot(axisNormal) + cap.radius - boundary1) < abs(sMax)
3727 ||
3728 abs(cap.startPoint().dot(axisNormal) - cap.radius - boundary1) < abs(sMax))
3729 boundaryPoints2[cnt2 ++] = 0;
3730
3731 if (abs(cap.endPoint().dot(axisNormal) + cap.radius - boundary1) < abs(sMax)
3732 ||
3733 abs(cap.endPoint().dot(axisNormal) - cap.radius - boundary1) < abs(sMax))
3734 boundaryPoints2[cnt2++] = 1;
3735
3736 if (cnt1 == 1)
3737 {
3738 m.normal = (boundary1 > boundary2) ? axisNormal : -axisNormal;
3739 m.contacts[0].penetration = sMax;
3740 m.contacts[0].position = tet.v[boundaryPoints1[0]];
3741 m.contactCount = 1;
3742 return;
3743 }
3744 if (cnt2 == 1)
3745 {
3746 m.normal = (boundary1 > boundary2) ? axisNormal : -axisNormal;
3747 m.contacts[0].penetration = sMax;
3748 m.contacts[0].position = boundaryPoints2[0] ? cap.endPoint() : cap.startPoint();
3749 m.contactCount = 1;
3750 return;
3751 }
3752 else if (cnt1 == 2)
3753 {
3754 Segment3D s1(tet.v[boundaryPoints1[0]], tet.v[boundaryPoints1[1]]);
3755
3756 //if (cnt2 == 2)
3757 {
3758 Segment3D s2 = cap.centerline();
3759 Segment3D dir = s1.proximity(s2);//v0: self v1: other
3760 m.normal = (boundary1 > boundary2) ? axisNormal : -axisNormal;
3761 m.contacts[0].penetration = sMax;
3762 m.contacts[0].position = dir.v0;
3763 m.contactCount = 1;
3764 return;
3765 }
3766 }
3767 else if (cnt1 == 3)
3768 {
3769 Triangle3D t1(tet.v[boundaryPoints1[0]], tet.v[boundaryPoints1[1]], tet.v[boundaryPoints1[2]]);
3770 //if (cnt2 == 2)
3771 {
3772
3773 Segment3D s2 = cap.centerline();
3774 m.contactCount = 0;
3775 m.normal = (boundary1 > boundary2) ? axisNormal : -axisNormal;
3776
3777 Vector<Real, 3> dirTmp1 = Point3D(s2.v0).project(t1).origin - s2.v0;
3778 Vector<Real, 3> dirTmp2 = Point3D(s2.v1).project(t1).origin - s2.v1;
3779 if (dirTmp1.cross(axisNormal).norm() < 1e-5)
3780 {
3781 m.contacts[m.contactCount].penetration = sMax;
3782 m.contacts[m.contactCount].position = s2.v0;
3783 m.contactCount++;
3784 }
3785 if (dirTmp2.cross(axisNormal).norm() < 1e-5)
3786 {
3787 m.contacts[m.contactCount].penetration = sMax;
3788 m.contacts[m.contactCount].position = s2.v1;
3789 m.contactCount++;
3790 }
3791 for (int i = 0; i < 3; i++)
3792 {
3793 Segment3D s1(t1.v[(i + 1) % 3], t1.v[(i + 2) % 3]);
3794 Segment3D dir = s2.proximity(s1);
3795 if ((!dir.isValid()) || dir.direction().normalize().cross(axisNormal).norm() < 1e-5)
3796 {
3797 if ((dir.v0 - s2.v0).norm() > 1e-5 && (dir.v0 - s2.v1).norm() > 1e-5)
3798 {
3799 m.contacts[m.contactCount].penetration = sMax;
3800 m.contacts[m.contactCount].position = dir.v0;
3801 m.contactCount++;
3802 }
3803 }
3804 }
3805 }
3806
3807 }
3808 }
3809
3810
3811 template<typename Real>
3812 DYN_FUNC inline void setupContactTetTri(
3813 Real boundary1,
3814 Real boundary2,
3815 const Vector<Real, 3> axisNormal,
3816 Tet3D tet,
3817 Triangle3D triangle,
3818 Real sMax,
3819 TManifold<Real>& m)
3820 {
3821 int cnt1, cnt2;
3822 unsigned char boundaryPoints1[4], boundaryPoints2[4];
3823 cnt1 = cnt2 = 0;
3824
3825
3826
3827 for (unsigned char i = 0; i < 4; i++)
3828 {
3829 if (abs(tet.v[i].dot(axisNormal) - boundary1) < abs(sMax) + EPSILON)
3830 boundaryPoints1[cnt1++] = i;
3831 }
3832
3833 for (unsigned char i = 0; i < 3; i++)
3834 {
3835 if (abs(triangle.v[i].dot(axisNormal) - boundary2) < abs(sMax) + EPSILON)
3836 boundaryPoints2[cnt2++] = i;
3837 }
3838
3839 //printf("cnt1 = %d cnt2 = %d smax = %.10lf\n", cnt1, cnt2, sMax);
3840
3841 if (cnt1 == 1 || cnt2 == 1)
3842 {
3843 m.normal = (boundary1 > boundary2) ? axisNormal : -axisNormal;
3844 m.contacts[0].penetration = sMax;
3845 m.contacts[0].position = (cnt1 == 1) ? tet.v[boundaryPoints1[0]] : triangle.v[boundaryPoints2[0]];
3846 m.contactCount = 1;
3847 return;
3848 }
3849 else if (cnt1 == 2)
3850 {
3851 Segment3D s1(tet.v[boundaryPoints1[0]], tet.v[boundaryPoints1[1]]);
3852
3853 if (cnt2 == 2)
3854 {
3855 Segment3D s2(triangle.v[boundaryPoints2[0]], triangle.v[boundaryPoints2[1]]);
3856 Segment3D dir = s1.proximity(s2);//v0: self v1: other
3857 m.normal = (boundary1 > boundary2) ? axisNormal : -axisNormal;
3858 m.contacts[0].penetration = sMax;
3859 m.contacts[0].position = dir.v0;
3860 m.contactCount = 1;
3861 return;
3862 }
3863 else //cnt2 == 3
3864 {
3865 m.contactCount = 0;
3866 m.normal = (boundary1 > boundary2) ? axisNormal : -axisNormal;
3867 Triangle3D t2(triangle.v[boundaryPoints2[0]], triangle.v[boundaryPoints2[1]], triangle.v[boundaryPoints2[2]]);
3868 Vector<Real, 3> dirTmp1 = Point3D(s1.v0).project(t2).origin - s1.v0;
3869 Vector<Real, 3> dirTmp2 = Point3D(s1.v1).project(t2).origin - s1.v1;
3870 if (dirTmp1.cross(axisNormal).norm() < 1e-5)
3871 {
3872 m.contacts[m.contactCount].penetration = sMax;
3873 m.contacts[m.contactCount].position = s1.v0;
3874 m.contactCount++;
3875 }
3876 if (dirTmp2.cross(axisNormal).norm() < 1e-5)
3877 {
3878 m.contacts[m.contactCount].penetration = sMax;
3879 m.contacts[m.contactCount].position = s1.v1;
3880 m.contactCount++;
3881 }
3882 for (int i = 0; i < 3; i++)
3883 {
3884 Segment3D s2(t2.v[(i + 1) % 3], t2.v[(i + 2) % 3]);
3885 Segment3D dir = s1.proximity(s2);
3886
3887 if ((!dir.isValid()) || dir.direction().normalize().cross(axisNormal).norm() < 1e-5)
3888 {
3889 //printf("Yes\n");
3890 if ((dir.v0 - s1.v0).norm() > 1e-5 && (dir.v0 - s1.v1).norm() > 1e-5)
3891 {
3892 m.contacts[m.contactCount].penetration = sMax;
3893 m.contacts[m.contactCount].position = dir.v0;
3894 m.contactCount++;
3895 }
3896 }
3897 }
3898 }
3899 }
3900 else if (cnt1 == 3)
3901 {
3902 Triangle3D t1(tet.v[boundaryPoints1[0]], tet.v[boundaryPoints1[1]], tet.v[boundaryPoints1[2]]);
3903 if (cnt2 == 2)
3904 {
3905
3906 Segment3D s2(triangle.v[boundaryPoints2[0]], triangle.v[boundaryPoints2[1]]);
3907 m.contactCount = 0;
3908 m.normal = (boundary1 > boundary2) ? axisNormal : -axisNormal;
3909
3910 Vector<Real, 3> dirTmp1 = Point3D(s2.v0).project(t1).origin - s2.v0;
3911 Vector<Real, 3> dirTmp2 = Point3D(s2.v1).project(t1).origin - s2.v1;
3912 if (dirTmp1.cross(axisNormal).norm() < 1e-5)
3913 {
3914 m.contacts[m.contactCount].penetration = sMax;
3915 m.contacts[m.contactCount].position = s2.v0;
3916 m.contactCount++;
3917 }
3918 if (dirTmp2.cross(axisNormal).norm() < 1e-5)
3919 {
3920 m.contacts[m.contactCount].penetration = sMax;
3921 m.contacts[m.contactCount].position = s2.v1;
3922 m.contactCount++;
3923 }
3924 for (int i = 0; i < 3; i++)
3925 {
3926 Segment3D s1(t1.v[(i + 1) % 3], t1.v[(i + 2) % 3]);
3927 Segment3D dir = s2.proximity(s1);
3928 if ((!dir.isValid()) || dir.direction().normalize().cross(axisNormal).norm() < 1e-5)
3929 {
3930 if ((dir.v0 - s2.v0).norm() > 1e-5 && (dir.v0 - s2.v1).norm() > 1e-5)
3931 {
3932 m.contacts[m.contactCount].penetration = sMax;
3933 m.contacts[m.contactCount].position = dir.v0;
3934 m.contactCount++;
3935 }
3936 }
3937 }
3938 }
3939 if (cnt2 == 3)
3940 {
3941 Triangle3D t1(tet.v[boundaryPoints1[0]], tet.v[boundaryPoints1[1]], tet.v[boundaryPoints1[2]]);
3942 Triangle3D t2 = triangle;
3943
3944 m.contactCount = 0;
3945 m.normal = (boundary1 > boundary2) ? axisNormal : -axisNormal;
3946
3947 for (int i = 0; i < 3; i++)
3948 {
3949 if ((Point3D(t1.v[i]).project(t2).origin - t1.v[i]).cross(t2.normal()).norm() < 1e-5)
3950 {
3951 m.contacts[m.contactCount].penetration = sMax;
3952 m.contacts[m.contactCount].position = t1.v[i];
3953 m.contactCount++;
3954 }
3955 if ((Point3D(t2.v[i]).project(t1).origin - t2.v[i]).cross(t1.normal()).norm() < 1e-5)
3956 {
3957 m.contacts[m.contactCount].penetration = sMax;
3958 m.contacts[m.contactCount].position = t2.v[i];
3959 m.contactCount++;
3960 }
3961
3962 for (int j = 0; j < 3; j++)
3963 {
3964 Segment3D s1(t1.v[(i + 1) % 3], t1.v[(i + 2) % 3]);
3965 Segment3D s2(t2.v[(j + 1) % 3], t2.v[(j + 2) % 3]);
3966 Segment3D dir = s1.proximity(s2);
3967 if ((!dir.isValid()) || dir.direction().normalize().cross(axisNormal).norm() < 1e-5)
3968 {
3969 if ((dir.v0 - s1.v0).norm() > 1e-5 && (dir.v0 - s1.v1).norm() > 1e-5)
3970 {
3971 m.contacts[m.contactCount].penetration = sMax;
3972 m.contacts[m.contactCount].position = dir.v0;
3973 m.contactCount++;
3974 }
3975 }
3976 }
3977 }
3978
3979 }
3980 }
3981 }
3982
3983 template<typename Real>
3984 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const OBox3D& box, const Capsule3D& cap)
3985 {
3986 m.contactCount = 0;
3987
3988 Vector<Real, 3> v = cap.center - box.center;
3989
3990 Real capExtent = cap.halfLength;
3991 Real radius = cap.radius;
3992 Matrix3D rotCap = cap.rotation.toMatrix3x3();
3993
3994 Vector<Real, 3> boxExt = box.extent;
3995
3996 Matrix3D rotBox;
3997 rotBox.setCol(0, box.u);
3998 rotBox.setCol(1, box.v);
3999 rotBox.setCol(2, box.w);
4000
4001 // Vector from capsule to box in box's space
4002 Vector<Real, 3> t = rotBox.transpose() * v;
4003
4004 // Rotation of capsule in box's space
4005 Matrix3D C = rotBox.transpose() * rotCap;
4006
4007 auto centerline = cap.centerline().direction();
4008 Vector<Real, 3> nCapLocal = rotBox.transpose() * centerline.normalize();
4009
4010 bool parallel = false;
4011 const float kCosTol = float(1.0e-6);
4012 Matrix3D absC;
4013 for (int i = 0; i < 3; ++i)
4014 {
4015 float val = abs(nCapLocal[i]);
4016 if (val <= kCosTol)
4017 parallel = true;
4018
4019 for (int j = 0; j < 3; ++j)
4020 {
4021 absC(i, j) = abs(C(i, j));
4022 }
4023 }
4024
4025 Matrix3D absC_t = absC.transpose();
4026
4027 // Query states
4028 Real s;
4029 Real bMax = -REAL_MAX;
4030 Real eMax = -REAL_MAX;
4031 Real dirMax = -REAL_MAX;
4032 int bAxis = ~0;
4033 int eAxis = ~0;
4034 int dirAxis = ~0;
4035 Vector<Real, 3> nB;
4036 Vector<Real, 3> nE;
4037 Vector<Real, 3> nDir;
4038
4039 // box's x axis
4040 s = abs(t.x) - (box.extent.x + absC_t.col(0).dot(Vector<Real, 3>(0, capExtent, 0))) - radius;
4041 if (trackFaceAxis(bAxis, bMax, nB, 0, s, rotBox.col(0)))
4042 return;
4043
4044 // box's y axis
4045 s = abs(t.y) - (box.extent.y + absC_t.col(1).dot(Vector<Real, 3>(0, capExtent, 0))) - radius;
4046 if (trackFaceAxis(bAxis, bMax, nB, 1, s, rotBox.col(1)))
4047 return;
4048
4049 // box's z axis
4050 s = abs(t.z) - (box.extent.z + absC_t.col(2).dot(Vector<Real, 3>(0, capExtent, 0))) - radius;
4051 if (trackFaceAxis(bAxis, bMax, nB, 2, s, rotBox.col(2)))
4052 return;
4053
4054 if (!parallel)
4055 {
4056 // Edge axis checks
4057 float rA;
4058 float rB;
4059 Vector<Real, 3> eSepAxis;
4060
4061 // Cross( box.x, centerline )
4062 eSepAxis = Vector<Real, 3>(Real(0), -nCapLocal.z, nCapLocal.y);
4063 rA = boxExt.y * abs(nCapLocal.z) + boxExt.z * abs(nCapLocal.y);
4064 rB = radius * eSepAxis.norm();
4065 s = abs(t.z * nCapLocal.y - t.y * nCapLocal.z) - (rA + rB);
4066 if (trackEdgeAxis(eAxis, eMax, nE, 3, s, eSepAxis))
4067 return;
4068
4069 // Cross( box.y, centerline )
4070 eSepAxis = Vector<Real, 3>(nCapLocal.z, Real(0), -nCapLocal.x);
4071 rA = boxExt.x * abs(nCapLocal.z) + boxExt.z * abs(nCapLocal.x);
4072 rB = radius * eSepAxis.norm();
4073 s = abs(t.x * nCapLocal.z - t.z * nCapLocal.x) - (rA + rB);
4074 if (trackEdgeAxis(eAxis, eMax, nE, 4, s, eSepAxis))
4075 return;
4076
4077 // Cross( box.z, centerline )
4078 eSepAxis = Vector<Real, 3>(-nCapLocal.y, nCapLocal.x, Real(0));
4079 rA = boxExt.x * abs(nCapLocal.y) + boxExt.y * abs(nCapLocal.x);
4080 rB = radius * eSepAxis.norm();
4081 s = abs(t.y * nCapLocal.x - t.x * nCapLocal.y) - (rA + rB);
4082 if (trackEdgeAxis(eAxis, eMax, nE, 5, s, eSepAxis))
4083 return;
4084 }
4085
4087 TSegment3D<Real> capCenterline = cap.centerline();
4088 auto num = capCenterline.intersect(box, interSeg);
4089 bool intersected = num > 0 ? true : false;
4090
4091 TSegment3D<Real> prox;
4092 if (!intersected)
4093 {
4094 prox = capCenterline.proximity(box);
4095
4096 Vector<Real, 3> dirSepAxis = prox.direction();
4097 s = dirSepAxis.norm() * dirSepAxis.norm() - radius * dirSepAxis.norm();
4098 if (trackEdgeAxis(dirAxis, dirMax, nDir, 6, s, dirSepAxis))
4099 return;
4100 }
4101
4102 // Artificial axis bias to improve frame coherence
4103 const float kRelTol = float(0.95);
4104 const float kAbsTol = float(0.01);
4105 const float kAbsTol2 = float(0.00001);
4106 int axis;
4107 float sMax;
4108 float ebMax = std::max(eMax, bMax);
4110
4111 if (intersected)
4112 {
4113 axis = bAxis;
4114 sMax = bMax;
4115 n = nB;
4116 }
4117 else
4118 {
4119 if (dirMax > ebMax + kAbsTol2)
4120 {
4121 axis = dirAxis;
4122 sMax = dirMax;
4123 n = nDir;
4124 }
4125 else
4126 {
4127 if (kRelTol * eMax > bMax + kAbsTol)
4128 {
4129 axis = eAxis;
4130 sMax = eMax;
4131 n = nE;
4132 }
4133 else
4134 {
4135 axis = bAxis;
4136 sMax = bMax;
4137 n = nB;
4138 }
4139 }
4140 }
4141
4142 if (n.dot(v) < float(0.0))
4143 n = -n;
4144
4145 if (axis < 3)
4146 {
4147 //Move the center line
4148 Vector<Real, 3> p0 = capCenterline.startPoint() - radius * n;
4149 Vector<Real, 3> p1 = capCenterline.endPoint() - radius * n;
4150
4151 TSegment3D<Real> centerline_translated(p0, p1);
4152
4153 TSegment3D<Real> centerline_inter;
4154 auto num = centerline_translated.intersect(box, centerline_inter);
4155
4156 ClipVertex incident[2];
4157 incident[0].v = p0;
4158 incident[1].v = p1;
4159
4160 Transform3D rtx(box.center, rotBox);
4161
4162 unsigned char clipEdges[4];
4163 Matrix3D basis;
4165 computeReferenceEdgesAndBasis(clipEdges, &basis, &e, boxExt, rtx, n, axis);
4166
4167 // Clip the incident face against the reference face side planes
4168 ClipVertex out[2];
4169 float depths[2];
4170 int outNum;
4171 outNum = clipEdgeAgainstRectangle(out, depths, rtx.translation(), e, clipEdges, basis, incident);
4172
4173 if (outNum)
4174 {
4175 m.contactCount = outNum;
4176 m.normal = n;
4177
4178 for (int i = 0; i < outNum; ++i)
4179 {
4180 m.contacts[i].position = out[i].v;
4181 m.contacts[i].penetration = depths[i];
4182 }
4183 }
4184 }
4185 else if (axis < 6)
4186 {
4187 n = rotBox * n;
4188
4189 Vector<Real, 3> PA, QA;
4190 computeSupportEdge(PA, QA, rotBox, box.center, boxExt, n);
4191
4192 Vector<Real, 3> PB = cap.startPoint();
4193 Vector<Real, 3> QB = cap.endPoint();
4194
4195 Vector<Real, 3> CA, CB;
4196 edgesContact(CA, CB, PA, QA, PB, QB);
4197
4198 m.normal = n;
4199 m.contactCount = 1;
4200
4201 m.contacts[0].penetration = sMax;
4202 m.contacts[0].position = CB - radius * n;
4203 }
4204 else
4205 {
4206 m.normal = n;
4207 m.contactCount = 1;
4208
4209 m.contacts[0].penetration = sMax;
4210 m.contacts[0].position = prox.v0 - radius * n;
4211 }
4212 }
4213
4214 template<typename Real>
4215 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const Capsule3D& cap, const OBox3D& box)
4216 {
4217 request(m, box, cap);
4218
4219 swapContactPair(m);
4220 }
4221
4222 template<typename Real>
4223 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const Tet3D& tet, const Triangle3D& tri)
4224 {
4225 m.contactCount = 0;
4226
4227 Real sMax = (Real)INT_MAX;
4228 Real sIntersect;
4229 Real lowerBoundary1, upperBoundary1, lowerBoundary2, upperBoundary2;
4230 Real l1, u1, l2, u2;
4231 Vector<Real, 3> axis = Vector<Real, 3>(0, 1, 0);
4232 Vector<Real, 3> axisTmp = axis;
4233
4234 Real boundary1, boundary2, b1, b2;
4235
4236
4237
4238 for (int i = 0; i < 4; i++)
4239 {
4240 //tet face axis i
4241 axisTmp = tet.face(i).normal();
4242 if (checkOverlapAxis(l1, u1, l2, u2, sIntersect, b1, b2, axisTmp, tet, tri) == false)
4243 {
4244 //printf("aax\n");
4245 m.contactCount = 0;
4246 return;
4247 }
4248 else
4249 {
4250 if (sIntersect < sMax)
4251 {
4252 sMax = sIntersect;
4253 lowerBoundary1 = l1;
4254 lowerBoundary2 = l2;
4255 upperBoundary1 = u1;
4256 upperBoundary2 = u2;
4257 boundary1 = b1;
4258 boundary2 = b2;
4259 axis = axisTmp;
4260 }
4261 }
4262 }
4263
4264
4265 //triangle face normal
4266 axisTmp = tri.normal();
4267 if (checkOverlapAxis(l1, u1, l2, u2, sIntersect, b1, b2, axisTmp, tet, tri) == false)
4268 {
4269 m.contactCount = 0;
4270 //printf("bbx\n");
4271 return;
4272 }
4273 else
4274 {
4275 if (sIntersect < sMax)
4276 {
4277 sMax = sIntersect;
4278 lowerBoundary1 = l1;
4279 lowerBoundary2 = l2;
4280 upperBoundary1 = u1;
4281 upperBoundary2 = u2;
4282 boundary1 = b1;
4283 boundary2 = b2;
4284 axis = axisTmp;
4285 }
4286 }
4287
4288 const int segmentIndex[6][2] = {
4289 0, 1,
4290 0, 2,
4291 0, 3,
4292 1, 2,
4293 1, 3,
4294 2, 3
4295 };
4296
4297 const int triIndex[6][2] = {
4298 0, 1,
4299 0, 2,
4300 1, 2
4301 };
4302
4303 for (int i = 0; i < 6; i++)
4304 for(int j = 0; j < 3; j ++)
4305 {
4306 Vector<Real, 3> dirTet = tet.v[segmentIndex[i][0]] - tet.v[segmentIndex[i][1]];
4307 Vector<Real, 3> dirTri = tri.v[triIndex[j][0]] - tri.v[triIndex[j][1]];
4308 dirTri /= dirTri.norm();
4309 dirTet /= dirTet.norm();
4310 axisTmp = dirTet.cross(dirTri);
4311 if (axisTmp.norm() > EPSILON)
4312 {
4313 axisTmp /= axisTmp.norm();
4314 }
4315 else //parallel, choose an arbitary direction
4316 {
4317 if (abs(dirTet[0]) > EPSILON)
4318 axisTmp = Vector<Real, 3>(dirTet[1], -dirTet[0], 0);
4319 else
4320 axisTmp = Vector<Real, 3>(0, dirTet[2], -dirTet[1]);
4321 axisTmp /= axisTmp.norm();
4322 }
4323 if (checkOverlapAxis(l1, u1, l2, u2, sIntersect, b1, b2, axisTmp, tet, tri) == false)
4324 {
4325 m.contactCount = 0;
4326 //printf("ccx\n");
4327 return;
4328 }
4329 else
4330 {
4331 if (sIntersect < sMax)
4332 {
4333 sMax = sIntersect;
4334 lowerBoundary1 = l1;
4335 lowerBoundary2 = l2;
4336 upperBoundary1 = u1;
4337 upperBoundary2 = u2;
4338 boundary1 = b1;
4339 boundary2 = b2;
4340 axis = axisTmp;
4341 }
4342 }
4343 }
4344
4345 axisTmp = (tet.v[0] + tet.v[1] + tet.v[2] + tet.v[3]) / 4.0f - (tri.v[0] + tri.v[1] + tri.v[2]) / 3.0f;
4346 axisTmp /= axisTmp.norm();
4347 if (checkOverlapAxis(l1, u1, l2, u2, sIntersect, b1, b2, axisTmp, tet, tri) == false)
4348 {
4349 m.contactCount = 0;
4350 //printf("ccx\n");
4351 return;
4352 }
4353 else
4354 {
4355 if (sIntersect < sMax)
4356 {
4357 sMax = sIntersect;
4358 lowerBoundary1 = l1;
4359 lowerBoundary2 = l2;
4360 upperBoundary1 = u1;
4361 upperBoundary2 = u2;
4362 boundary1 = b1;
4363 boundary2 = b2;
4364 axis = axisTmp;
4365 }
4366 }
4367
4368 //printf("YesYes\n");
4369 setupContactTetTri(boundary1, boundary2, axis, tet, tri, -sMax, m);
4370 }
4371
4372 template<typename Real>
4373 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const Triangle3D& tri, const Tet3D& tet)
4374 {
4375 request(m, tet, tri);
4376 m.normal = -m.normal;
4377 }
4378
4379 //Separating Axis Theorem for tets
4380 template<typename Real>
4381 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const Capsule3D& cap, const Tet3D& tet)
4382 {
4383 m.contactCount = 0;
4384
4385 Real sMax = (Real)INT_MAX;
4386 Real sIntersect;
4387 Real lowerBoundary1, upperBoundary1, lowerBoundary2, upperBoundary2;
4388 Real l1, u1, l2, u2;
4389 Vector<Real, 3> axis = Vector<Real, 3>(0, 1, 0);
4390 Vector<Real, 3> axisTmp = axis;
4391
4392 Real boundary1, boundary2, b1, b2;
4393
4394
4395 for (int i = 0; i < 4; i++)
4396 {
4397 //tet0 face axis i
4398 axisTmp = tet.face(i).normal();
4399 if (checkOverlapAxis(l1, u1, l2, u2, sIntersect, b1, b2, axisTmp, tet, cap) == false)
4400 {
4401 m.contactCount = 0;
4402 return;
4403 }
4404 else
4405 {
4406 if (sIntersect < sMax)
4407 {
4408 sMax = sIntersect;
4409 lowerBoundary1 = l1;
4410 lowerBoundary2 = l2;
4411 upperBoundary1 = u1;
4412 upperBoundary2 = u2;
4413 boundary1 = b1;
4414 boundary2 = b2;
4415 axis = axisTmp;
4416 }
4417 }
4418 //tet1 face axis i
4419 axisTmp = tet.face(i).normal();
4420 if (checkOverlapAxis(l1, u1, l2, u2, sIntersect, b1, b2, axisTmp, tet, cap) == false)
4421 {
4422 m.contactCount = 0;
4423 return;
4424 }
4425 else
4426 {
4427 if (sIntersect < sMax)
4428 {
4429 sMax = sIntersect;
4430 lowerBoundary1 = l1;
4431 lowerBoundary2 = l2;
4432 upperBoundary1 = u1;
4433 upperBoundary2 = u2;
4434 boundary1 = b1;
4435 boundary2 = b2;
4436 axis = axisTmp;
4437 }
4438 }
4439 }
4440
4441 const int segmentIndex[6][2] = {
4442 0, 1,
4443 0, 2,
4444 0, 3,
4445 1, 2,
4446 1, 3,
4447 2, 3
4448 };
4449
4450 axisTmp = cap.centerline().direction();
4451 if (axisTmp.norm() > EPSILON)
4452 {
4453 axisTmp /= axisTmp.norm();
4454 }
4455 if (checkOverlapAxis(l1, u1, l2, u2, sIntersect, b1, b2, axisTmp, tet, cap) == false)
4456 {
4457 m.contactCount = 0;
4458 return;
4459 }
4460 else
4461 {
4462 if (sIntersect < sMax)
4463 {
4464 sMax = sIntersect;
4465 lowerBoundary1 = l1;
4466 lowerBoundary2 = l2;
4467 upperBoundary1 = u1;
4468 upperBoundary2 = u2;
4469 boundary1 = b1;
4470 boundary2 = b2;
4471 axis = axisTmp;
4472 }
4473 }
4474
4475 for (int i = 0; i < 6; i++)
4476 {
4477 Vector<Real, 3> dirTet = tet.v[segmentIndex[i][0]] - tet.v[segmentIndex[i][1]];
4478 Vector<Real, 3> dirCap = cap.centerline().direction();
4479
4480
4481
4482 axisTmp = dirTet.cross(dirCap);
4483 if (axisTmp.norm() > EPSILON)
4484 {
4485 axisTmp /= axisTmp.norm();
4486 }
4487 else //parallel, choose an arbitary direction
4488 {
4489 if (abs(dirTet[0]) > EPSILON)
4490 axisTmp = Vector<Real, 3>(dirTet[1], -dirTet[0], 0);
4491 else
4492 axisTmp = Vector<Real, 3>(0, dirTet[2], -dirTet[1]);
4493 axisTmp /= axisTmp.norm();
4494 }
4495 if (checkOverlapAxis(l1, u1, l2, u2, sIntersect, b1, b2, axisTmp, tet, cap) == false)
4496 {
4497 m.contactCount = 0;
4498 return;
4499 }
4500 else
4501 {
4502 if (sIntersect < sMax)
4503 {
4504 sMax = sIntersect;
4505 lowerBoundary1 = l1;
4506 lowerBoundary2 = l2;
4507 upperBoundary1 = u1;
4508 upperBoundary2 = u2;
4509 boundary1 = b1;
4510 boundary2 = b2;
4511 axis = axisTmp;
4512 }
4513 }
4514 }
4515
4516 setupContactTets(boundary1, boundary2, axis, tet, cap, -sMax, m);
4517
4518 for (uint i = 0; i < m.contactCount; i++)
4519 {
4520 m.contacts[i].position += (cap.radius + m.contacts[i].penetration) * m.normal;
4521 }
4522 }
4523
4524 template<typename Real>
4525 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const Tet3D& tet, const Capsule3D& cap)
4526 {
4527 request(m, cap, tet);
4528
4529 swapContactPair(m);
4530 }
4531
4532 template<typename Real>
4533 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const OBox3D& box, const Sphere3D& sphere)
4534 {
4535 request(m, sphere, box);
4536
4537 swapContactPair(m);
4538 }
4539
4540 template<typename Real>
4541 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const Sphere3D& sphere0, const Sphere3D& sphere1)
4542 {
4543 m.contactCount = 0;
4544
4545 auto c0 = sphere0.center;
4546 auto c1 = sphere1.center;
4547
4548 Real r0 = sphere0.radius;
4549 Real r1 = sphere1.radius;
4550
4551 auto dir = c1 - c0;
4552 Real sMax = dir.norm() - r0 - r1;
4553 if (sMax >= 0)
4554 return;
4555
4556 m.normal = dir.normalize();
4557 m.contacts[0].penetration = sMax;
4558 m.contacts[0].position = c0 + (r0 + sMax) * m.normal;
4559 m.contactCount = 1;
4560 }
4561
4562 template<typename Real>
4563 DYN_FUNC inline bool checkOverlap(
4564 Real lowerBoundary1,
4565 Real upperBoundary1, // A
4566 Real lowerBoundary2,
4567 Real upperBoundary2, // B
4568 Real& intersectionDistance,
4569 Real& boundary1,
4570 Real& boundary2
4571 )
4572 {
4573 if (!((lowerBoundary1 > upperBoundary2) || (lowerBoundary2 > upperBoundary1)))
4574 {
4575 if (lowerBoundary1 < lowerBoundary2)
4576 {
4577 if (upperBoundary1 > upperBoundary2)
4578 {
4579 // |---B---|
4580 // |-----A-----|
4581 //intersectionDistance = upperBoundary2 - lowerBoundary2;
4582 if (upperBoundary2 - lowerBoundary1 > upperBoundary1 - lowerBoundary2)
4583 {
4584 // |---B---|(->)
4585 // |-----A-----|
4586 boundary1 = upperBoundary1;
4587 boundary2 = lowerBoundary2;
4588 intersectionDistance = upperBoundary1 - lowerBoundary2;
4589 }
4590 else
4591 {
4592 // (<-)|---B---|
4593 // |-----A-----|
4594 boundary1 = lowerBoundary1;
4595 boundary2 = upperBoundary2;
4596 intersectionDistance = upperBoundary2 - lowerBoundary1;
4597 }
4598 }
4599 else
4600 {
4601 // |---B---|(->)
4602 // |----A----|
4603 intersectionDistance = upperBoundary1 - lowerBoundary2;
4604 boundary1 = upperBoundary1;
4605 boundary2 = lowerBoundary2;
4606 }
4607 }
4608 else
4609 {
4610 if (upperBoundary1 > upperBoundary2)
4611 {
4612 // (<-)|---B---|
4613 // |----A----|
4614 intersectionDistance = upperBoundary2 - lowerBoundary1;
4615 boundary1 = lowerBoundary1;
4616 boundary2 = upperBoundary2;
4617 }
4618 else
4619 {
4620 // |-----B------|
4621 // |---A---|
4622 //intersectionDistance = upperBoundary1 - lowerBoundary1;
4623 if (upperBoundary2 - lowerBoundary1 > upperBoundary1 - lowerBoundary2)
4624 {
4625 // |-----B-----|(->)
4626 // |---A---|
4627 boundary1 = upperBoundary1;
4628 boundary2 = lowerBoundary2;
4629 intersectionDistance = upperBoundary1 - lowerBoundary2;
4630 }
4631 else
4632 {
4633 // (<-)|------B------|
4634 // |---A---|
4635 boundary1 = lowerBoundary1;
4636 boundary2 = upperBoundary2;
4637 intersectionDistance = upperBoundary2 - lowerBoundary1;
4638 }
4639 }
4640 }
4641 return true;
4642 }
4643 // |---A---| |---B---|
4644 // |---B---| |---A---|
4645 intersectionDistance = Real(0.0f);
4646 return false;
4647 }
4648
4649 template<typename Real>
4650 DYN_FUNC inline bool checkOverlapAxis(
4651 Real& lowerBoundary1,
4652 Real& upperBoundary1,
4653 Real& lowerBoundary2,
4654 Real& upperBoundary2,
4655 Real& intersectionDistance,
4656 Real& boundary1,
4657 Real& boundary2,
4658 const Vector<Real, 3> axisNormal,
4659 Tet3D tet1,
4660 Tet3D tet2)
4661 {
4662
4663 //projection to axis
4664 for (int i = 0; i < 4; i++)
4665 {
4666 if (i == 0)
4667 {
4668 lowerBoundary1 = upperBoundary1 = tet1.v[0].dot(axisNormal);
4669 lowerBoundary2 = upperBoundary2 = tet2.v[0].dot(axisNormal);
4670 }
4671 else
4672 {
4673 lowerBoundary1 = glm::min(lowerBoundary1, tet1.v[i].dot(axisNormal));
4674 lowerBoundary2 = glm::min(lowerBoundary2, tet2.v[i].dot(axisNormal));
4675 upperBoundary1 = glm::max(upperBoundary1, tet1.v[i].dot(axisNormal));
4676 upperBoundary2 = glm::max(upperBoundary2, tet2.v[i].dot(axisNormal));
4677 }
4678 }
4679
4680 /*printf(" axis = %.3lf %.3lf %.3lf\nlb1 = %.3lf lb2 = %.3lf\nub1 = %.3lf ub2 = %.3lf\n",
4681 axisNormal[0], axisNormal[1], axisNormal[2],
4682 lowerBoundary1, lowerBoundary2,
4683 upperBoundary1, upperBoundary2
4684 );*/
4685 return checkOverlap(lowerBoundary1, upperBoundary1, lowerBoundary2, upperBoundary2, intersectionDistance, boundary1, boundary2);
4686 }
4687
4688
4689 template<typename Real>
4690 DYN_FUNC inline bool checkOverlapAxis(
4691 Real& lowerBoundary1,
4692 Real& upperBoundary1,
4693 Real& lowerBoundary2,
4694 Real& upperBoundary2,
4695 Real& intersectionDistance,
4696 Real& boundary1,
4697 Real& boundary2,
4698 const Vector<Real, 3> axisNormal,
4699 Tet3D tet,
4700 Triangle3D tri)
4701 {
4702
4703 //projection to axis
4704 for (int i = 0; i < 4; i++)
4705 {
4706 if (i == 0)
4707 {
4708 lowerBoundary1 = upperBoundary1 = tet.v[0].dot(axisNormal);
4709 }
4710 else
4711 {
4712 lowerBoundary1 = glm::min(lowerBoundary1, tet.v[i].dot(axisNormal));
4713 upperBoundary1 = glm::max(upperBoundary1, tet.v[i].dot(axisNormal));
4714 }
4715 }
4716
4717 for (int i = 0; i < 3; i++)
4718 {
4719 if(i == 0)
4720 lowerBoundary2 = upperBoundary2 = tri.v[i].dot(axisNormal);
4721 else
4722 {
4723 lowerBoundary2 = glm::min(lowerBoundary2, tri.v[i].dot(axisNormal));
4724 upperBoundary2 = glm::max(upperBoundary2, tri.v[i].dot(axisNormal));
4725 }
4726 }
4727
4728 return false;//(lowerBoundary1, upperBoundary1, lowerBoundary2, upperBoundary2, intersectionDistance, boundary1, boundary2);
4729 }
4730
4731
4732 template<typename Real>
4733 DYN_FUNC inline bool checkOverlapAxis(
4734 Real& lowerBoundary1,
4735 Real& upperBoundary1,
4736 Real& lowerBoundary2,
4737 Real& upperBoundary2,
4738 Real& intersectionDistance,
4739 Real& boundary1,
4740 Real& boundary2,
4741 const Vector<Real, 3> axisNormal,
4742 Tet3D tet,
4743 OrientedBox3D box)
4744 {
4745
4746 //projection to axis
4747 for (int i = 0; i < 4; i++)
4748 {
4749 if (i == 0)
4750 lowerBoundary1 = upperBoundary1 = tet.v[0].dot(axisNormal);
4751 else
4752 {
4753 lowerBoundary1 = glm::min(lowerBoundary1, tet.v[i].dot(axisNormal));
4754 upperBoundary1 = glm::max(upperBoundary1, tet.v[i].dot(axisNormal));
4755 }
4756 }
4757
4758 Vector<Real, 3> center = box.center;
4759 Vector<Real, 3> u = box.u;
4760 Vector<Real, 3> v = box.v;
4761 Vector<Real, 3> w = box.w;
4762 Vector<Real, 3> extent = box.extent;
4764 p = (center - u * extent[0] - v * extent[1] - w * extent[2]);
4765 lowerBoundary2 = upperBoundary2 = p.dot(axisNormal);
4766
4767 p = (center - u * extent[0] - v * extent[1] + w * extent[2]);
4768 lowerBoundary2 = glm::min(lowerBoundary2, p.dot(axisNormal));
4769 upperBoundary2 = glm::max(upperBoundary2, p.dot(axisNormal));
4770
4771 p = (center - u * extent[0] + v * extent[1] - w * extent[2]);
4772 lowerBoundary2 = glm::min(lowerBoundary2, p.dot(axisNormal));
4773 upperBoundary2 = glm::max(upperBoundary2, p.dot(axisNormal));
4774
4775 p = (center - u * extent[0] + v * extent[1] + w * extent[2]);
4776 lowerBoundary2 = glm::min(lowerBoundary2, p.dot(axisNormal));
4777 upperBoundary2 = glm::max(upperBoundary2, p.dot(axisNormal));
4778
4779 p = (center + u * extent[0] - v * extent[1] - w * extent[2]);
4780 lowerBoundary2 = glm::min(lowerBoundary2, p.dot(axisNormal));
4781 upperBoundary2 = glm::max(upperBoundary2, p.dot(axisNormal));
4782
4783 p = (center + u * extent[0] - v * extent[1] + w * extent[2]);
4784 lowerBoundary2 = glm::min(lowerBoundary2, p.dot(axisNormal));
4785 upperBoundary2 = glm::max(upperBoundary2, p.dot(axisNormal));
4786
4787 p = (center + u * extent[0] + v * extent[1] - w * extent[2]);
4788 lowerBoundary2 = glm::min(lowerBoundary2, p.dot(axisNormal));
4789 upperBoundary2 = glm::max(upperBoundary2, p.dot(axisNormal));
4790
4791 p = (center + u * extent[0] + v * extent[1] + w * extent[2]);
4792 lowerBoundary2 = glm::min(lowerBoundary2, p.dot(axisNormal));
4793 upperBoundary2 = glm::max(upperBoundary2, p.dot(axisNormal));
4794
4795 return checkOverlap(lowerBoundary1, upperBoundary1, lowerBoundary2, upperBoundary2, intersectionDistance, boundary1, boundary2);
4796 }
4797
4798
4799 template<typename Real>
4800 DYN_FUNC inline void setupContactTets(
4801 Real boundary1,
4802 Real boundary2,
4803 const Vector<Real, 3> axisNormal,
4804 Tet3D tet1,
4805 Tet3D tet2,
4806 Real sMax,
4807 TManifold<Real>& m)
4808 {
4809 int cnt1, cnt2;
4810 unsigned char boundaryPoints1[4], boundaryPoints2[4];
4811 cnt1 = cnt2 = 0;
4812
4813
4814
4815 for (unsigned char i = 0; i < 4; i++)
4816 {
4817 if (abs(tet1.v[i].dot(axisNormal) - boundary1) < abs(sMax))
4818 boundaryPoints1[cnt1 ++] = i;
4819 if (abs(tet2.v[i].dot(axisNormal) - boundary2) < abs(sMax))
4820 boundaryPoints2[cnt2 ++] = i;
4821 }
4822 //printf("cnt1 = %d, cnt2 = %d\n", cnt1, cnt2);
4823 if (cnt1 == 1 || cnt2 == 1)
4824 {
4825
4826 m.normal = (boundary1 > boundary2) ? axisNormal : - axisNormal;
4827 m.contacts[0].penetration = sMax;
4828 m.contacts[0].position = (cnt1 == 1) ? tet1.v[boundaryPoints1[0]] : tet2.v[boundaryPoints2[0]];
4829 m.contactCount = 1;
4830 return;
4831 }
4832 else if (cnt1 == 2)
4833 {
4834 Segment3D s1(tet1.v[boundaryPoints1[0]], tet1.v[boundaryPoints1[1]]);
4835
4836 if (cnt2 == 2)
4837 {
4838 Segment3D s2(tet2.v[boundaryPoints2[0]], tet2.v[boundaryPoints2[1]]);
4839 Segment3D dir = s1.proximity(s2);//v0: self v1: other
4840 m.normal = (boundary1 > boundary2) ? axisNormal : -axisNormal;
4841 m.contacts[0].penetration = sMax;
4842 m.contacts[0].position = dir.v0;
4843 m.contactCount = 1;
4844 return;
4845 }
4846 else //cnt2 == 3
4847 {
4848 m.contactCount = 0;
4849 m.normal = (boundary1 > boundary2) ? axisNormal : -axisNormal;
4850 Triangle3D t2(tet2.v[boundaryPoints2[0]], tet2.v[boundaryPoints2[1]], tet2.v[boundaryPoints2[2]]);
4851 Vector<Real, 3> dirTmp1 = Point3D(s1.v0).project(t2).origin - s1.v0;
4852 Vector<Real, 3> dirTmp2 = Point3D(s1.v1).project(t2).origin - s1.v1;
4853
4854 if (dirTmp1.cross(axisNormal).norm() < 1e-5)
4855 {
4856 m.contacts[m.contactCount].penetration = sMax;
4857 m.contacts[m.contactCount].position = s1.v0;
4858 m.contactCount ++;
4859 }
4860 if (dirTmp2.cross(axisNormal).norm() < 1e-5)
4861 {
4862 m.contacts[m.contactCount].penetration = sMax;
4863 m.contacts[m.contactCount].position = s1.v1;
4864 m.contactCount++;
4865 }
4866
4867 for (int i = 0; i < 3; i++)
4868 {
4869 Segment3D s2(t2.v[(i + 1) % 3], t2.v[(i + 2) % 3]);
4870 Segment3D dir = s1.proximity(s2);
4871 /*printf("dir: %.3lf %.3lf %.3lf\naxisnormal %.3lf %.3lf %.3lf\n%.6lf\n",
4872 dir.direction()[0], dir.direction()[1], dir.direction()[2],
4873 axisNormal[0], axisNormal[1], axisNormal[2],
4874 dir.direction().normalize().cross(axisNormal).norm());*/
4875 if ((!dir.isValid()) ||
4876 (
4877 (dir.direction().dot(s1.direction()) < 1e-5) && (dir.direction().dot(s2.direction()) < 1e-5)
4878 ))
4879 //if(dir.norm() < 1e5)
4880 {
4881 //printf("Yes\n");
4882 if ((dir.v0 - s1.v0).norm() > 1e-5 && (dir.v0 - s1.v1).norm() > 1e-5)
4883 {
4884 m.contacts[m.contactCount].penetration = sMax;
4885 m.contacts[m.contactCount].position = dir.v0;
4886 m.contactCount++;
4887 }
4888 }
4889 }
4890 }
4891 }
4892 else if (cnt1 == 3)
4893 {
4894 Triangle3D t1(tet1.v[boundaryPoints1[0]], tet1.v[boundaryPoints1[1]], tet1.v[boundaryPoints1[2]]);
4895 if (cnt2 == 2)
4896 {
4897
4898 Segment3D s2(tet2.v[boundaryPoints2[0]], tet2.v[boundaryPoints2[1]]);
4899 m.contactCount = 0;
4900 m.normal = (boundary1 > boundary2) ? axisNormal : -axisNormal;
4901
4902 Vector<Real, 3> dirTmp1 = Point3D(s2.v0).project(t1).origin - s2.v0;
4903 Vector<Real, 3> dirTmp2 = Point3D(s2.v1).project(t1).origin - s2.v1;
4904 if (dirTmp1.cross(axisNormal).norm() < 1e-5)
4905
4906 {
4907 m.contacts[m.contactCount].penetration = sMax;
4908 m.contacts[m.contactCount].position = s2.v0;
4909 m.contactCount++;
4910 }
4911 if (dirTmp2.cross(axisNormal).norm() < 1e-5)
4912 {
4913 m.contacts[m.contactCount].penetration = sMax;
4914 m.contacts[m.contactCount].position = s2.v1;
4915 m.contactCount++;
4916 }
4917
4918 for (int i = 0; i < 3; i++)
4919 {
4920 Segment3D s1(t1.v[(i + 1) % 3], t1.v[(i + 2) % 3]);
4921 Segment3D dir = s2.proximity(s1);
4922 if ((!dir.isValid()) ||
4923 (
4924 (dir.direction().dot(s1.direction()) < 1e-5) && (dir.direction().dot(s2.direction()) < 1e-5)
4925 ))
4926 {
4927 if ((dir.v0 - s2.v0).norm() > 1e-5 && (dir.v0 - s2.v1).norm() > 1e-5)
4928 {
4929 m.contacts[m.contactCount].penetration = sMax;
4930 m.contacts[m.contactCount].position = dir.v0;
4931 m.contactCount++;
4932 }
4933 }
4934 }
4935 }
4936 if (cnt2 == 3)
4937 {
4938 Triangle3D t1(tet1.v[boundaryPoints1[0]], tet1.v[boundaryPoints1[1]], tet1.v[boundaryPoints1[2]]);
4939 Triangle3D t2(tet2.v[boundaryPoints2[0]], tet2.v[boundaryPoints2[1]], tet2.v[boundaryPoints2[2]]);
4940
4941 m.contactCount = 0;
4942 m.normal = (boundary1 > boundary2) ? axisNormal : -axisNormal;
4943
4944 for (int i = 0; i < 3; i++)
4945 {
4946 if ((Point3D(t1.v[i]).project(t2).origin - t1.v[i]).cross(t2.normal()).norm() < 1e-5)
4947 {
4948 m.contacts[m.contactCount].penetration = sMax;
4949 m.contacts[m.contactCount].position = t1.v[i];
4950 m.contactCount++;
4951 }
4952 if ((Point3D(t2.v[i]).project(t1).origin - t2.v[i]).cross(t1.normal()).norm() < 1e-5)
4953 {
4954 m.contacts[m.contactCount].penetration = sMax;
4955 m.contacts[m.contactCount].position = t2.v[i];
4956 m.contactCount++;
4957 }
4958
4959 for (int j = 0; j < 3; j++)
4960 {
4961 Segment3D s1(t1.v[(i + 1) % 3], t1.v[(i + 2) % 3]);
4962 Segment3D s2(t2.v[(j + 1) % 3], t2.v[(j + 2) % 3]);
4963 Segment3D dir = s1.proximity(s2);
4964
4965
4966 if ((!dir.isValid()) ||
4967 (
4968 (dir.direction().dot(s1.direction()) < 1e-5) && (dir.direction().dot(s2.direction()) < 1e-5)
4969 )
4970 )
4971 {
4972 if ((dir.v0 - s1.v0).norm() > 1e-5 && (dir.v0 - s1.v1).norm() > 1e-5)
4973 {
4974 m.contacts[m.contactCount].penetration = sMax;
4975 m.contacts[m.contactCount].position = dir.v0;
4976 m.contactCount++;
4977 }
4978 }
4979 }
4980
4981 }
4982
4983 }
4984 }
4985 }
4986
4987
4988 template<typename Real>
4989 DYN_FUNC inline void setupContactTets(
4990 Real boundary1,
4991 Real boundary2,
4992 const Vector<Real, 3> axisNormal,
4993 Tet3D tet,
4995 Real sMax,
4996 TManifold<Real>& m)
4997 {
4998 int cnt1, cnt2;
4999 unsigned char boundaryPoints1[4];
5000 Vector<Real, 3> boundaryPoints2[8];
5001 cnt1 = cnt2 = 0;
5002
5003
5004
5005 for (unsigned char i = 0; i < 4; i++)
5006 {
5007 if (abs(tet.v[i].dot(axisNormal) - boundary1) < abs(sMax))
5008 boundaryPoints1[cnt1++] = i;
5009 }
5010
5011 Vector<Real, 3> center = box.center;
5012 Vector<Real, 3> u = box.u;
5013 Vector<Real, 3> v = box.v;
5014 Vector<Real, 3> w = box.w;
5015 Vector<Real, 3> extent = box.extent;
5017 p = (center - u * extent[0] - v * extent[1] - w * extent[2]);
5018 if (abs(p.dot(axisNormal) - boundary2) < abs(sMax))
5019 boundaryPoints2[cnt2++] = p;
5020
5021 p = (center - u * extent[0] - v * extent[1] + w * extent[2]);
5022 if (abs(p.dot(axisNormal) - boundary2) < abs(sMax))
5023 boundaryPoints2[cnt2++] = p;
5024
5025 p = (center - u * extent[0] + v * extent[1] - w * extent[2]);
5026 if (abs(p.dot(axisNormal) - boundary2) < abs(sMax))
5027 boundaryPoints2[cnt2++] = p;
5028
5029 p = (center - u * extent[0] + v * extent[1] + w * extent[2]);
5030 if (abs(p.dot(axisNormal) - boundary2) < abs(sMax))
5031 boundaryPoints2[cnt2++] = p;
5032
5033 p = (center + u * extent[0] - v * extent[1] - w * extent[2]);
5034 if (abs(p.dot(axisNormal) - boundary2) < abs(sMax))
5035 boundaryPoints2[cnt2++] = p;
5036
5037 p = (center + u * extent[0] - v * extent[1] + w * extent[2]);
5038 if (abs(p.dot(axisNormal) - boundary2) < abs(sMax))
5039 boundaryPoints2[cnt2++] = p;
5040
5041 p = (center + u * extent[0] + v * extent[1] - w * extent[2]);
5042 if (abs(p.dot(axisNormal) - boundary2) < abs(sMax))
5043 boundaryPoints2[cnt2++] = p;
5044
5045 p = (center + u * extent[0] + v * extent[1] + w * extent[2]);
5046 if (abs(p.dot(axisNormal) - boundary2) < abs(sMax))
5047 boundaryPoints2[cnt2++] = p;
5048
5049 //printf("cnt1 = %d, cnt2 = %d %.3lf\n", cnt1, cnt2, sMax);
5050 if (cnt1 == 1 || cnt2 == 1)
5051 {
5052 m.normal = (boundary1 > boundary2) ? axisNormal : -axisNormal;
5053 m.contacts[0].penetration = sMax;
5054 m.contacts[0].position = (cnt1 == 1) ? tet.v[boundaryPoints1[0]] : boundaryPoints2[0];
5055 m.contactCount = 1;
5056 return;
5057 }
5058 else if (cnt1 == 2)
5059 {
5060 Segment3D s1(tet.v[boundaryPoints1[0]], tet.v[boundaryPoints1[1]]);
5061
5062 if (cnt2 == 2)
5063 {
5064 Segment3D s2(boundaryPoints2[0], boundaryPoints2[1]);
5065 Segment3D dir = s1.proximity(s2);//v0: self v1: other
5066 m.normal = (boundary1 > boundary2) ? axisNormal : -axisNormal;
5067 m.contacts[0].penetration = sMax;
5068 m.contacts[0].position = dir.v0;
5069 m.contactCount = 1;
5070 return;
5071 }
5072 else //cnt2 == 4
5073 {
5074 //if (cnt2 != 4)
5075 // printf("?????????\n");
5076
5077
5078 for(int tmp_i = 1; tmp_i < 4; tmp_i ++)
5079 for (int tmp_j = tmp_i + 1; tmp_j < 4; tmp_j++)
5080 {
5081 if ((boundaryPoints2[tmp_i] - boundaryPoints2[0]).dot(boundaryPoints2[tmp_j] - boundaryPoints2[0]) < EPSILON)
5082 {
5083 int tmp_k = 1 + 2 + 3 - tmp_i - tmp_j;
5084 Vector<Real, 3> p2 = boundaryPoints2[tmp_i];
5085 Vector<Real, 3> p3 = boundaryPoints2[tmp_j];
5086 Vector<Real, 3> p4 = boundaryPoints2[tmp_k];
5087 boundaryPoints2[1] = p2;
5088 boundaryPoints2[2] = p3;
5089 boundaryPoints2[3] = p4;
5090 break;
5091 }
5092 }
5093
5094 //printf("%.3lf %.3lf %.3lf\n", boundaryPoints2[0][0], boundaryPoints2[0][1], boundaryPoints2[0][2]);
5095 //printf("%.3lf %.3lf %.3lf\n", boundaryPoints2[1][0], boundaryPoints2[1][1], boundaryPoints2[1][2]);
5096 //printf("%.3lf %.3lf %.3lf\n", boundaryPoints2[2][0], boundaryPoints2[2][1], boundaryPoints2[2][2]);
5097 //printf("%.3lf %.3lf %.3lf\n", boundaryPoints2[3][0], boundaryPoints2[3][1], boundaryPoints2[3][2]);
5098
5099 m.contactCount = 0;
5100 m.normal = (boundary1 > boundary2) ? axisNormal : -axisNormal;
5101 Triangle3D t2(boundaryPoints2[0], boundaryPoints2[1], boundaryPoints2[2]);
5102 Vector<Real, 3> dirTmp1 = Point3D(s1.v0).project(t2).origin - s1.v0;
5103 Vector<Real, 3> dirTmp2 = Point3D(s1.v1).project(t2).origin - s1.v1;
5104
5105 /*printf("%.3lf %.3lf %.3lf\n", axisNormal[0], axisNormal[1], axisNormal[2]);
5106 printf("%.3lf %.3lf %.3lf %.5lf %.5lf %.5lf\n", dirTmp1[0], dirTmp1[1], dirTmp1[2], dirTmp1.cross(axisNormal)[0], dirTmp1.cross(axisNormal)[1], dirTmp1.cross(axisNormal)[2]);
5107 printf("%.3lf %.3lf %.3lf %.5lf %.5lf %.5lf\n", dirTmp2[0], dirTmp2[1], dirTmp2[2], dirTmp2.cross(axisNormal)[0], dirTmp2.cross(axisNormal)[1], dirTmp2.cross(axisNormal)[2]);*/
5108
5109
5110 if (dirTmp1.cross(axisNormal).norm() < 1e-4)
5111 {
5112 m.contacts[m.contactCount].penetration = sMax;
5113 m.contacts[m.contactCount].position = s1.v0;
5114 m.contactCount++;
5115 }
5116 if (dirTmp2.cross(axisNormal).norm() < 1e-4)
5117 {
5118 m.contacts[m.contactCount].penetration = sMax;
5119 m.contacts[m.contactCount].position = s1.v1;
5120 m.contactCount++;
5121 }
5122 t2 = Triangle3D(boundaryPoints2[3], boundaryPoints2[1], boundaryPoints2[2]);
5123 dirTmp1 = Point3D(s1.v0).project(t2).origin - s1.v0;
5124 dirTmp2 = Point3D(s1.v1).project(t2).origin - s1.v1;
5125
5126 /*printf("%.3lf %.3lf %.3lf\n", dirTmp1[0], dirTmp1[1], dirTmp1[2]);
5127 printf("%.3lf %.3lf %.3lf\n", dirTmp2[0], dirTmp2[1], dirTmp2[2]);*/
5128
5129 if (dirTmp1.cross(axisNormal).norm() < 1e-4)
5130 {
5131 m.contacts[m.contactCount].penetration = sMax;
5132 m.contacts[m.contactCount].position = s1.v0;
5133 m.contactCount++;
5134 }
5135 if (dirTmp2.cross(axisNormal).norm() < 1e-4)
5136 {
5137 m.contacts[m.contactCount].penetration = sMax;
5138 m.contacts[m.contactCount].position = s1.v1;
5139 m.contactCount++;
5140 }
5141 for (int i = 0; i < 4; i++)
5142 {
5143 Segment3D s2;
5144 if (i < 2)
5145 s2 = Segment3D(boundaryPoints2[0], boundaryPoints2[i]);
5146 else
5147 s2 = Segment3D(boundaryPoints2[3], boundaryPoints2[i - 2]);
5148 Segment3D dir = s1.proximity(s2);
5149 /*printf("dir: %.3lf %.3lf %.3lf\naxisnormal %.3lf %.3lf %.3lf\n%.6lf\n",
5150 dir.direction()[0], dir.direction()[1], dir.direction()[2],
5151 axisNormal[0], axisNormal[1], axisNormal[2],
5152 dir.direction().normalize().cross(axisNormal).norm());*/
5153 if ((!dir.isValid()) || dir.direction().normalize().cross(axisNormal).norm() < 1e-4)
5154 {
5155 //printf("Yes\n");
5156 if ((dir.v0 - s1.v0).norm() > 1e-4 && (dir.v0 - s1.v1).norm() > 1e-4)
5157 {
5158 m.contacts[m.contactCount].penetration = sMax;
5159 m.contacts[m.contactCount].position = dir.v0;
5160 m.contactCount++;
5161 }
5162 }
5163 }
5164 }
5165 }
5166 else if (cnt1 == 3)
5167 {
5168 Triangle3D t1(tet.v[boundaryPoints1[0]], tet.v[boundaryPoints1[1]], tet.v[boundaryPoints1[2]]);
5169
5170 //printf("%.3lf %.3lf %.3lf\n", axisNormal[0], axisNormal[1], axisNormal[2]);
5171
5172 if (cnt2 == 2)
5173 {
5174
5175 Segment3D s2(boundaryPoints2[0], boundaryPoints2[1]);
5176 m.contactCount = 0;
5177 m.normal = (boundary1 > boundary2) ? axisNormal : -axisNormal;
5178
5179 Vector<Real, 3> dirTmp1 = Point3D(s2.v0).project(t1).origin - s2.v0;
5180 Vector<Real, 3> dirTmp2 = Point3D(s2.v1).project(t1).origin - s2.v1;
5181 if (dirTmp1.cross(axisNormal).norm() < 1e-4)
5182 {
5183 m.contacts[m.contactCount].penetration = sMax;
5184 m.contacts[m.contactCount].position = s2.v0;
5185 m.contactCount++;
5186 }
5187 if (dirTmp2.cross(axisNormal).norm() < 1e-4)
5188 {
5189 m.contacts[m.contactCount].penetration = sMax;
5190 m.contacts[m.contactCount].position = s2.v1;
5191 m.contactCount++;
5192 }
5193 for (int i = 0; i < 3; i++)
5194 {
5195 Segment3D s1(t1.v[(i + 1) % 3], t1.v[(i + 2) % 3]);
5196 Segment3D dir = s2.proximity(s1);
5197 if ((!dir.isValid()) || dir.direction().normalize().cross(axisNormal).norm() < 1e-4)
5198 {
5199 if ((dir.v0 - s2.v0).norm() > 1e-4 && (dir.v0 - s2.v1).norm() > 1e-4)
5200 {
5201 m.contacts[m.contactCount].penetration = sMax;
5202 m.contacts[m.contactCount].position = dir.v0;
5203 m.contactCount++;
5204 }
5205 }
5206 }
5207 }
5208 else
5209 {
5210 Triangle3D t1(tet.v[boundaryPoints1[0]], tet.v[boundaryPoints1[1]], tet.v[boundaryPoints1[2]]);
5211 //Triangle3D t2(tet2.v[boundaryPoints2[0]], tet2.v[boundaryPoints2[1]], tet2.v[boundaryPoints2[2]]);
5212
5213 //if (cnt2 != 4)
5214 // printf("?????????\n");
5215
5216
5217 for (int tmp_i = 1; tmp_i < 4; tmp_i++)
5218 for (int tmp_j = tmp_i + 1; tmp_j < 4; tmp_j++)
5219 {
5220 if ((boundaryPoints2[tmp_i] - boundaryPoints2[0]).dot(boundaryPoints2[tmp_j] - boundaryPoints2[0]) < EPSILON)
5221 {
5222 int tmp_k = 1 + 2 + 3 - tmp_i - tmp_j;
5223 Vector<Real, 3> p2 = boundaryPoints2[tmp_i];
5224 Vector<Real, 3> p3 = boundaryPoints2[tmp_j];
5225 Vector<Real, 3> p4 = boundaryPoints2[tmp_k];
5226 boundaryPoints2[1] = p2;
5227 boundaryPoints2[2] = p3;
5228 boundaryPoints2[3] = p4;
5229 break;
5230 }
5231 }
5232
5233 m.contactCount = 0;
5234 m.normal = (boundary1 > boundary2) ? axisNormal : -axisNormal;
5235
5236 for(int i = 0; i < 4; i ++)
5237 if ((Point3D(boundaryPoints2[i]).project(t1).origin - boundaryPoints2[i]).cross(t1.normal()).norm() < 1e-4)
5238 {
5239 m.contacts[m.contactCount].penetration = sMax;
5240 m.contacts[m.contactCount].position = boundaryPoints2[i];
5241 m.contactCount++;
5242 //printf("b");
5243 }
5244
5245 for (int i = 0; i < 3; i++)
5246 {
5247 Triangle3D t2(boundaryPoints2[0], boundaryPoints2[1], boundaryPoints2[2]);
5248 if ((Point3D(t1.v[i]).project(t2).origin - t1.v[i]).cross(t2.normal()).norm() < 1e-4)
5249 {
5250 m.contacts[m.contactCount].penetration = sMax;
5251 m.contacts[m.contactCount].position = t1.v[i];
5252 m.contactCount++;
5253 //printf("a1");
5254 }
5255 t2 = Triangle3D(boundaryPoints2[3], boundaryPoints2[1], boundaryPoints2[2]);
5256 if ((Point3D(t1.v[i]).project(t2).origin - t1.v[i]).cross(t2.normal()).norm() < 1e-4)
5257 {
5258 m.contacts[m.contactCount].penetration = sMax;
5259 m.contacts[m.contactCount].position = t1.v[i];
5260 m.contactCount++;
5261 //printf("a2");
5262 }
5263
5264
5265 Segment3D s1(t1.v[(i + 1) % 3], t1.v[(i + 2) % 3]);
5266 Segment3D s2(boundaryPoints2[0], boundaryPoints2[1]);
5267 Segment3D dir = s1.proximity(s2);
5268 if ((!dir.isValid()) || dir.direction().cross(axisNormal).norm() < 1e-4)
5269 {
5270 if ((dir.v0 - s1.v0).norm() > 1e-4 && (dir.v0 - s1.v1).norm() > 1e-4)
5271 {
5272 m.contacts[m.contactCount].penetration = sMax;
5273 m.contacts[m.contactCount].position = dir.v0;
5274 m.contactCount++;
5275 //printf("c");
5276 }
5277
5278 }
5279
5280 s2 = Segment3D(boundaryPoints2[0], boundaryPoints2[2]);
5281 dir = s1.proximity(s2);
5282 if ((!dir.isValid()) || dir.direction().cross(axisNormal).norm() < 1e-4)
5283 {
5284 if ((dir.v0 - s1.v0).norm() > 1e-4 && (dir.v0 - s1.v1).norm() > 1e-4)
5285 {
5286 m.contacts[m.contactCount].penetration = sMax;
5287 m.contacts[m.contactCount].position = dir.v0;
5288 m.contactCount++;
5289 //printf("c");
5290 }
5291 }
5292 s2 = Segment3D(boundaryPoints2[3], boundaryPoints2[2]);
5293 dir = s1.proximity(s2);
5294 if ((!dir.isValid()) || dir.direction().cross(axisNormal).norm() < 1e-4)
5295 {
5296 if ((dir.v0 - s1.v0).norm() > 1e-4 && (dir.v0 - s1.v1).norm() > 1e-4)
5297 {
5298 m.contacts[m.contactCount].penetration = sMax;
5299 m.contacts[m.contactCount].position = dir.v0;
5300 m.contactCount++;
5301 //printf("c");
5302 }
5303 }
5304 s2 = Segment3D(boundaryPoints2[3], boundaryPoints2[1]);
5305 dir = s1.proximity(s2);
5306 if ((!dir.isValid()) || dir.direction().cross(axisNormal).norm() < 1e-4)
5307 {
5308 if ((dir.v0 - s1.v0).norm() > 1e-4 && (dir.v0 - s1.v1).norm() > 1e-4)
5309 {
5310 m.contacts[m.contactCount].penetration = sMax;
5311 m.contacts[m.contactCount].position = dir.v0;
5312 m.contactCount++;
5313 //printf("c");
5314 }
5315 }
5316
5317 }
5318
5319 }
5320 }
5321 }
5322
5323 //Separating Axis Theorem for tets
5324 template<typename Real>
5325 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const Tet3D& tet0, const Tet3D& tet1)
5326 {
5327 m.contactCount = 0;
5328
5329 Real sMax = (Real)INT_MAX;
5330 Real sIntersect;
5331 Real lowerBoundary1, upperBoundary1, lowerBoundary2, upperBoundary2;
5332 Real l1, u1, l2, u2;
5333 Vector<Real, 3> axis = Vector<Real, 3>(0, 1, 0);
5334 Vector<Real, 3> axisTmp = axis;
5335
5336 Real boundary1, boundary2, b1, b2;
5337
5338
5339 // no penetration when the tets are illegal
5340 if (abs(tet0.volume()) < EPSILON || abs(tet1.volume()) < EPSILON)
5341 return;
5342
5343 for(int i = 0; i < 4; i ++)
5344 {
5345 //tet0 face axis i
5346 axisTmp = tet0.face(i).normal();
5347 if (checkOverlapAxis(l1, u1, l2, u2, sIntersect, b1, b2, axisTmp, tet0, tet1) == false)
5348 {
5349 m.contactCount = 0;
5350 return;
5351 }
5352 else
5353 {
5354 if (sIntersect < sMax)
5355 {
5356 sMax = sIntersect;
5357 lowerBoundary1 = l1;
5358 lowerBoundary2 = l2;
5359 upperBoundary1 = u1;
5360 upperBoundary2 = u2;
5361 boundary1 = b1;
5362 boundary2 = b2;
5363 axis = axisTmp;
5364 }
5365 }
5366 //tet1 face axis i
5367 axisTmp = tet1.face(i).normal();
5368 if (checkOverlapAxis(l1, u1, l2, u2, sIntersect, b1, b2, axisTmp, tet0, tet1) == false)
5369 {
5370 m.contactCount = 0;
5371 return;
5372 }
5373 else
5374 {
5375 if (sIntersect < sMax)
5376 {
5377 sMax = sIntersect;
5378 lowerBoundary1 = l1;
5379 lowerBoundary2 = l2;
5380 upperBoundary1 = u1;
5381 upperBoundary2 = u2;
5382 boundary1 = b1;
5383 boundary2 = b2;
5384 axis = axisTmp;
5385 }
5386 }
5387 }
5388
5389 const int segmentIndex[6][2] = {
5390 0, 1,
5391 0, 2,
5392 0, 3,
5393 1, 2,
5394 1, 3,
5395 2, 3
5396 };
5397
5398 for(int i = 0; i < 6; i ++)
5399 for (int j = 0; j < 6; j++)
5400 {
5401 Vector<Real, 3> dirTet1 = tet0.v[segmentIndex[i][0]] - tet0.v[segmentIndex[i][1]];
5402 Vector<Real, 3> dirTet2 = tet1.v[segmentIndex[j][0]] - tet1.v[segmentIndex[j][1]];
5403 axisTmp = dirTet1.cross(dirTet2);
5404 if (axisTmp.norm() > EPSILON)
5405 {
5406 axisTmp /= axisTmp.norm();
5407 }
5408 else //parallel, choose an arbitary direction
5409 {
5410 if (abs(dirTet1[0]) > EPSILON)
5411 axisTmp = Vector<Real, 3>(dirTet1[1], -dirTet1[0], 0);
5412 else
5413 axisTmp = Vector<Real, 3>(0, dirTet1[2], -dirTet1[1]);
5414 axisTmp /= axisTmp.norm();
5415 }
5416 if (checkOverlapAxis(l1, u1, l2, u2, sIntersect, b1, b2, axisTmp, tet0, tet1) == false)
5417 {
5418 m.contactCount = 0;
5419 return;
5420 }
5421 else
5422 {
5423 if (sIntersect < sMax)
5424 {
5425 sMax = sIntersect;
5426 lowerBoundary1 = l1;
5427 lowerBoundary2 = l2;
5428 upperBoundary1 = u1;
5429 upperBoundary2 = u2;
5430 boundary1 = b1;
5431 boundary2 = b2;
5432 axis = axisTmp;
5433 }
5434 }
5435 }
5436 //printf("YES YYYYYYYEEES\n!\n");
5437 //set up contacts using axis
5438 setupContactTets(boundary1, boundary2, axis, tet0, tet1, -sMax, m);
5439 }
5440
5441
5442 //Separating Axis Theorem for tet-OBB
5443 template<typename Real>
5444 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const Tet3D& tet, const OBox3D& box)
5445 {
5446 m.contactCount = 0;
5447
5448 Real sMax = (Real)INT_MAX;
5449 Real sIntersect;
5450 Real lowerBoundary1, upperBoundary1, lowerBoundary2, upperBoundary2;
5451 Real l1, u1, l2, u2;
5452 Vector<Real, 3> axis = Vector<Real, 3>(0, 1, 0);
5453 Vector<Real, 3> axisTmp = axis;
5454
5455 Real boundary1, boundary2, b1, b2;
5456
5457 for (int i = 0; i < 4; i++)
5458 {
5459 //tet face axis i
5460 axisTmp = tet.face(i).normal();
5461 if (checkOverlapAxis(l1, u1, l2, u2, sIntersect, b1, b2, axisTmp, tet, box) == false)
5462 {
5463 m.contactCount = 0;
5464 return;
5465 }
5466 else
5467 {
5468 if (sIntersect < sMax)
5469 {
5470 sMax = sIntersect;
5471 lowerBoundary1 = l1;
5472 lowerBoundary2 = l2;
5473 upperBoundary1 = u1;
5474 upperBoundary2 = u2;
5475 boundary1 = b1;
5476 boundary2 = b2;
5477 axis = axisTmp;
5478 }
5479 }
5480 }
5481
5482 //u
5483 axisTmp = box.u / box.u.norm();
5484 if (checkOverlapAxis(l1, u1, l2, u2, sIntersect, b1, b2, axisTmp, tet, box) == false)
5485 {
5486 m.contactCount = 0;
5487 return;
5488 }
5489 else
5490 {
5491 if (sIntersect < sMax)
5492 {
5493 sMax = sIntersect;
5494 lowerBoundary1 = l1;
5495 lowerBoundary2 = l2;
5496 upperBoundary1 = u1;
5497 upperBoundary2 = u2;
5498 boundary1 = b1;
5499 boundary2 = b2;
5500 axis = axisTmp;
5501 }
5502 }
5503
5504
5505 //v
5506 axisTmp = box.v / box.v.norm();
5507 if (checkOverlapAxis(l1, u1, l2, u2, sIntersect, b1, b2, axisTmp, tet, box) == false)
5508 {
5509 m.contactCount = 0;
5510 return;
5511 }
5512 else
5513 {
5514 if (sIntersect < sMax)
5515 {
5516 sMax = sIntersect;
5517 lowerBoundary1 = l1;
5518 lowerBoundary2 = l2;
5519 upperBoundary1 = u1;
5520 upperBoundary2 = u2;
5521 boundary1 = b1;
5522 boundary2 = b2;
5523 axis = axisTmp;
5524 }
5525 }
5526
5527 //w
5528 axisTmp = box.w / box.w.norm();
5529 if (checkOverlapAxis(l1, u1, l2, u2, sIntersect, b1, b2, axisTmp, tet, box) == false)
5530 {
5531 m.contactCount = 0;
5532 return;
5533 }
5534 else
5535 {
5536 if (sIntersect < sMax)
5537 {
5538 sMax = sIntersect;
5539 lowerBoundary1 = l1;
5540 lowerBoundary2 = l2;
5541 upperBoundary1 = u1;
5542 upperBoundary2 = u2;
5543 boundary1 = b1;
5544 boundary2 = b2;
5545 axis = axisTmp;
5546 }
5547 }
5548
5549 const int segmentIndex[6][2] = {
5550 0, 1,
5551 0, 2,
5552 0, 3,
5553 1, 2,
5554 1, 3,
5555 2, 3
5556 };
5557
5558 //dir generated by cross product from tet and box
5559 for (int i = 0; i < 6; i++)
5560 {
5561 Vector<Real, 3> dirTet = tet.v[segmentIndex[i][0]] - tet.v[segmentIndex[i][1]];
5562 for(int j = 0; j < 3; j ++)
5563 {
5564 Vector<Real, 3> boxDir = (j == 0) ? (box.u) : ((j == 1) ? (box.v) : (box.w));
5565 axisTmp = dirTet.cross(boxDir);
5566 if (axisTmp.norm() > EPSILON)
5567 {
5568 axisTmp /= axisTmp.norm();
5569 }
5570 else //parallel, choose an arbitary direction
5571 {
5572 if (abs(dirTet[0]) > EPSILON)
5573 axisTmp = Vector<Real, 3>(dirTet[1], -dirTet[0], 0);
5574 else
5575 axisTmp = Vector<Real, 3>(0, dirTet[2], -dirTet[1]);
5576 axisTmp /= axisTmp.norm();
5577 }
5578 if (checkOverlapAxis(l1, u1, l2, u2, sIntersect, b1, b2, axisTmp, tet, box) == false)
5579 {
5580 m.contactCount = 0;
5581 return;
5582 }
5583 else
5584 {
5585 if (sIntersect < sMax)
5586 {
5587 sMax = sIntersect;
5588 lowerBoundary1 = l1;
5589 lowerBoundary2 = l2;
5590 upperBoundary1 = u1;
5591 upperBoundary2 = u2;
5592 boundary1 = b1;
5593 boundary2 = b2;
5594 axis = axisTmp;
5595 }
5596 }
5597 }
5598 }
5599 setupContactTets(boundary1, boundary2, axis, tet, box, -sMax, m);
5600 }
5601
5602 template<typename Real>
5603 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const OBox3D& box, const Tet3D& tet)
5604 {
5605 request(m, tet, box);
5606
5607 swapContactPair(m);
5608 }
5609
5610 template<typename Real>
5611 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const Sphere3D& sphere, const Tet3D& tet)
5612 {
5613 m.contactCount = 0;
5614
5615 Point3D c0(sphere.center);
5616 Real r0 = sphere.radius;
5617
5618 Point3D vproj = c0.project(tet);
5619 bool bInside = c0.inside(tet);
5620
5621 Segment3D dir = bInside ? c0 - vproj : vproj - c0;
5622 Real sMax = bInside ? -dir.direction().norm() - r0 : dir.direction().norm() - r0;
5623
5624 if (sMax >= 0)
5625 return;
5626
5627 m.normal = dir.direction().normalize();
5628 m.contacts[0].penetration = sMax;
5629 m.contacts[0].position = vproj.origin;
5630 m.contactCount = 1;
5631 }
5632
5633 template<typename Real>
5634 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const Tet3D& tet, const Sphere3D& sphere)
5635 {
5636 request(m, sphere, tet);
5637
5638 swapContactPair(m);
5639 }
5640
5641 template<typename Real>
5642 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const Sphere3D& sphere, const Triangle3D& tri)
5643 {
5644 m.contactCount = 0;
5645
5646 Point3D c0(sphere.center);
5647 Real r0 = sphere.radius;
5648
5649 Point3D vproj = c0.project(tri);
5650
5651
5652 Segment3D dir = vproj - c0;
5653 Real sMax = dir.direction().norm() - r0;
5654
5655 if (sMax >= 0)
5656 return;
5657
5658 /*if (dir.direction().norm() < EPSILON)
5659 return;*/
5660
5661 /*if ((dir.direction().normalize().cross(tri.normal().normalize())).norm() > EPSILON)
5662 return;*/
5663
5664 m.normal = dir.direction().normalize();
5665 m.contacts[0].penetration = sMax;
5666 m.contacts[0].position = vproj.origin;
5667 m.contactCount = 1;
5668 }
5669
5670 template<typename Real>
5671 DYN_FUNC void CollisionDetection<Real>::request(Manifold& m, const Triangle3D& tri, const Sphere3D& sphere)
5672 {
5673 request(m, sphere, tri);
5674 m.normal *= -1;
5675 }
5676}
#define REAL_GREAT(a, b)
#define REAL_infinity
#define REAL_LESS(a, b)
#define InFront(a)
#define Behind(a)
double Real
Definition Typedef.inl:23
@ in
@ out
TSeparationData< Real > SeparationData
static DYN_FUNC void MSDF(SeparationData &sat, const Sphere3D &sphereA, const Sphere3D &sphereB, const Real radiusA, const Real radiusB)
static DYN_FUNC void request(Manifold &m, const Sphere3D &sphereA, const Sphere3D &sphereB, const Real radiusA, const Real radiusB)
DYN_FUNC Interval< Real > intersect(const Interval< Real > &itv) const
Definition Interval.inl:119
DYN_FUNC TSegment3D< Real > centerline() const
Quat< Real > rotation
DYN_FUNC Coord3D endPoint() const
DYN_FUNC Coord3D startPoint() const
1D geometric primitives in three-dimensional space
Coord3D u
three unit vectors u, v and w forming a right-handed orthornormal basis
DYN_FUNC TPoint3D< Real > vertex(const int i) const
DYN_FUNC TSegment3D< Real > edge(const int i) const
DYN_FUNC TRectangle3D< Real > face(const int i) const
Coord3D extent
half the dimension in each of the u, v, and w directions
Coord3D center
centerpoint
0D geometric primitive in three-dimensional space
DYN_FUNC TPoint3D< Real > project(const TLine3D< Real > &line) const
project a point onto linear components – lines, rays and segments
DYN_FUNC bool inside(const TLine3D< Real > &line) const
check whether a point strictly lies inside (excluding boundary) a 1D geometric primitive
Coord3D axis[2]
two orthonormal unit axis
DYN_FUNC TPoint3D< Real > vertex(const int i) const
DYN_FUNC Coord3D normal() const
DYN_FUNC Coord3D & endPoint()
DYN_FUNC Real parameter(const Coord3D &pos) const
DYN_FUNC Coord3D direction() const
DYN_FUNC TSegment3D< Real > proximity(const TSegment3D< Real > &segment) const
return a segment pointing from the input segment to the other primitive
DYN_FUNC bool isValid() const
DYN_FUNC bool intersect(const TPlane3D< Real > &plane, TPoint3D< Real > &interPt) const
DYN_FUNC Coord3D & startPoint()
DYN_FUNC Vector< Real, 3 > pointB()
DYN_FUNC SeparationType face()
DYN_FUNC SeparationType type()
DYN_FUNC void update(SeparationType type, Real BoundaryA, Real BoundaryB, Real Depth, Vec3f N, Vec3f a0, Vec3f a1, Vec3f a2=Vec3f(0.), Vec3f a3=Vec3f(0.))
DYN_FUNC Vector< Real, 3 > normal()
3D geometric primitives in three-dimensional space
vertices are ordered so that the normal vectors for the triangular faces point outwards 3 / | \ 0 - 2...
Coord3D v[4]
DYN_FUNC TSegment3D< Real > edge(const int index) const
DYN_FUNC TTriangle3D< Real > face(const int index) const
DYN_FUNC Real volume() const
DYN_FUNC Coord3D normal() const
#define N(x, y, z)
DYN_FUNC int intrSegWithPlane(Vec3f *q, Vec3f oA, Vec3f nA, Vec3f b0, Vec3f b1)
DYN_FUNC int intrBoxWithPlane(Vec3f *q, Vec3f oA, Vec3f nA, Vec3f center, Vec3f halfU, Vec3f halfV, Vec3f halfW)
DYN_FUNC int intrPolyWithRect(Vec3f *q, int n, Vec3f *p, Vec3f a0, Vec3f a1, Vec3f a2, Vec3f a3)
DYN_FUNC int intrTetWithPlane(Vec3f *q, Vec3f oA, Vec3f nA, Vec3f b0, Vec3f b1, Vec3f b2, Vec3f b3)
DYN_FUNC int intrPolyWithTri(Vec3f *q, int n, Vec3f *p, Vec3f a0, Vec3f a1, Vec3f a2)
DYN_FUNC int intrTriWithPlane(Vec3f *q, Vec3f oA, Vec3f nA, Vec3f b0, Vec3f b1, Vec3f b2)
This is an implementation of AdditiveCCD based on peridyno.
Definition Array.h:25
DYN_FUNC void computeSupportEdge(Vector< Real, 3 > &aOut, Vector< Real, 3 > &bOut, const SquareMatrix< Real, 3 > &rot, const Vector< Real, 3 > &trans, const Vector< Real, 3 > &e, Vector< Real, 3 > n)
DYN_FUNC int sign(T const &a, T const EPS=EPSILON)
Definition SimpleMath.h:39
DYN_FUNC void checkAxisPoint(TSeparationData< Real > &sat, ShapeA &shapeA, ShapeB &shapeB, const Real radiusA, const Real radiusB, Vec3f pA, Vec3f pB, const Real rA=0.f, const Real rB=0.f)
constexpr Real REAL_MAX
Definition Typedef.inl:45
DYN_FUNC void computeReferenceEdgesAndBasis(unsigned char *out, SquareMatrix< Real, 3 > *basis, Vector< Real, 3 > *e, const Vector< Real, 3 > &eR, const Transform< Real, 3 > &rtx, Vector< Real, 3 > n, int axis)
DYN_FUNC void setupContactOnSphere(TManifold< Real > &m, TSeparationData< Real > &sat, const TSphere3D< Real > &sphereB, const Real radiusA, const Real radiusB)
DYN_FUNC void updateSDF(Real &boundaryA, Real &boundaryB, Real &depth, Vec3f &normal, Real currentBoundaryA, Real currentBoundaryB, Real currentDepth, Vec3f currentN)
DYN_FUNC Vector< T, 3 > cross(Vector< T, 3 > const &U, Vector< T, 3 > const &V)
Definition SimpleMath.h:211
DYN_FUNC void setupContactTets(Real boundary1, Real boundary2, const Vector< Real, 3 > axisNormal, Tet3D tet, Capsule3D cap, Real sMax, TManifold< Real > &m)
DYN_FUNC int clipEdgeAgainstRectangle(ClipVertex *outVerts, float *outDepths, const Vector< Real, 3 > &rPos, const Vector< Real, 3 > &e, unsigned char *clipEdges, const SquareMatrix< Real, 3 > &basis, ClipVertex *incident)
DYN_FUNC T dot(Vector< T, 2 > const &U, Vector< T, 2 > const &V)
Definition SimpleMath.h:199
DYN_FUNC void checkAxisRect(TSeparationData< Real > &sat, ShapeA &shapeA, ShapeB &shapeB, const Real radiusA, const Real radiusB, Rectangle3D rect, SeparationType type)
DYN_FUNC void computeIncidentFace(ClipVertex *out, const Transform< Real, 3 > &itx, const Vector< Real, 3 > &e, Vector< Real, 3 > n)
DYN_FUNC void projectOnAxis(Real &lowerBoundary, Real &upperBoundary, const Vec3f axisNormal, Sphere3D sphere, const Real radius)
TRectangle3D< double > Rectangle3D
DYN_FUNC void setupContactOnBox(TManifold< Real > &m, TSeparationData< Real > &sat, const Shape &shapeA, const TOrientedBox3D< Real > &boxB, const Real radiusA, const Real radiusB)
DYN_FUNC T abs(const T &v)
Definition SimpleMath.h:81
TTriangle3D< double > Triangle3D
DYN_FUNC void checkAxisEdge(TSeparationData< Real > &sat, ShapeA &shapeA, ShapeB &shapeB, const Real radiusA, const Real radiusB, Segment3D edgeA, Segment3D edgeB)
DYN_FUNC bool checkPointInBoundary(const Vec3f &p, const Vec3f &N, const Real &b, const Real &r)
DYN_FUNC int ClippingWithRect(Vector< Real, 3 > *q, const TRectangle3D< Real > &rectA, const TSphere3D< Real > &sphereB, const Vector< Real, 3 > &transA, const Vector< Real, 3 > &transB)
DYN_FUNC void setupContactCaps(Real boundary1, Real boundary2, const Vector< Real, 3 > axisNormal, TCapsule3D< Real > cap, TOrientedBox3D< Real > box, Real depth, TManifold< Real > &m)
DYN_FUNC int ClippingWithTri(Vector< Real, 3 > *q, const TTriangle3D< Real > &triA, const TSphere3D< Real > &sphereB, const Vector< Real, 3 > &transA, const Vector< Real, 3 > &transB)
DYN_FUNC void setupContactTetTri(Real boundary1, Real boundary2, const Vector< Real, 3 > axisNormal, Tet3D tet, Triangle3D triangle, Real sMax, TManifold< Real > &m)
constexpr Real EPSILON
Definition Typedef.inl:42
TOrientedBox3D< double > OrientedBox3D
DYN_FUNC void checkSignedDistance(Real lowerBoundaryA, Real upperBoundaryA, Real lowerBoundaryB, Real upperBoundaryB, Real &intersectionDistance, Real &boundaryA, Real &boundaryB)
DYN_FUNC void setupContactOnSeg(TManifold< Real > &m, TSeparationData< Real > &sat, const TSegment3D< Real > &segB, const Real radiusA, const Real radiusB)
DYN_FUNC void swapContactPair(TManifold< Real > &m)
TCapsule3D< double > Capsule3D
DYN_FUNC bool checkOverlapTetTri(Real lowerBoundary1, Real upperBoundary1, Real lowerBoundary2, Real upperBoundary2, Real &intersectionDistance, Real &boundary1, Real &boundary2)
TPoint3D< double > Point3D
DYN_FUNC void setupContactOnTri(TManifold< Real > &m, TSeparationData< Real > &sat, const Shape &shapeA, const TTriangle3D< Real > &triB, const Real radiusA, const Real radiusB)
DYN_FUNC void edgesContact(Vector< Real, 3 > &CA, Vector< Real, 3 > &CB, const Vector< Real, 3 > &PA, const Vector< Real, 3 > &QA, const Vector< Real, 3 > &PB, const Vector< Real, 3 > &QB)
Vector< float, 3 > Vec3f
Definition Vector3D.h:93
DYN_FUNC void checkSignedDistanceAxis(Real &intersectionDistance, Real &BoundaryA, Real &BoundaryB, const Vec3f axisNormal, ShapeA &shapeA, ShapeB &shapeB, const Real radiusA, const Real radiusB)
DYN_FUNC float fsign(Real v)
DYN_FUNC int orthographic(ClipVertex *out, Real sign, Real e, int axis, int clipEdge, ClipVertex *in, int inCount)
unsigned int uint
Definition VkProgram.h:14
DYN_FUNC bool trackFaceAxis(int &axis, Real &sMax, Vector< Real, 3 > &axisNormal, int n, Real s, const Vector< Real, 3 > &normal)
TTet3D< double > Tet3D
DYN_FUNC bool trackEdgeAxis(int &axis, Real &sMax, Vector< Real, 3 > &axisNormal, int n, Real s, const Vector< Real, 3 > &normal)
TSphere3D< double > Sphere3D
DYN_FUNC void setupContactOnTet(TManifold< Real > &m, TSeparationData< Real > &sat, const Shape &shapeA, const TTet3D< Real > &tetB, const Real radiusA, const Real radiusB)
TSegment3D< double > Segment3D
DYN_FUNC void checkAxisTri(TSeparationData< Real > &sat, ShapeA &shapeA, ShapeB &shapeB, const Real radiusA, const Real radiusB, Triangle3D tri, SeparationType type)
DYN_FUNC int clip(ClipVertex *outVerts, float *outDepths, const Vector< Real, 3 > &rPos, const Vector< Real, 3 > &e, unsigned char *clipEdges, const SquareMatrix< Real, 3 > &basis, ClipVertex *incident)
DYN_FUNC bool checkOverlapAxis(Real &lowerBoundary1, Real &upperBoundary1, Real &lowerBoundary2, Real &upperBoundary2, Real &intersectionDistance, Real &boundary1, Real &boundary2, const Vector< Real, 3 > axisNormal, OrientedBox3D box, Capsule3D cap)
DYN_FUNC bool checkOverlap(Real lowerBoundary1, Real upperBoundary1, Real lowerBoundary2, Real upperBoundary2, Real &intersectionDistance, Real &boundary1, Real &boundary2)
DYN_FUNC void pushContact(const Vector< Real, 3 > &pos, const Real &dep)
Vector< Real, 3 > normal
TContact< Real > contacts[8]