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