1 // =============================================================================
2 // PROJECT CHRONO - http://projectchrono.org
3 //
4 // Copyright (c) 2014 projectchrono.org
5 // All rights reserved.
6 //
7 // Use of this source code is governed by a BSD-style license that can be found
8 // in the LICENSE file at the top level of the distribution and at
9 // http://projectchrono.org/license-chrono.txt.
10 //
11 // =============================================================================
12 // Authors: Alessandro Tasora, Radu Serban
13 // =============================================================================
14 
15 #include "chrono/core/ChMathematics.h"
16 #include "chrono/collision/ChCollisionAlgorithmsBullet.h"
17 #include "chrono/collision/ChCollisionModelBullet.h"
18 #include "chrono/collision/ChCollisionUtils.h"
19 #include "chrono/collision/ChCollisionUtilsBullet.h"
20 
21 #include "chrono/collision/bullet/BulletCollision/CollisionShapes/btSphereShape.h"
22 #include "chrono/collision/bullet/BulletCollision/CollisionShapes/btCylinderShape.h"
23 #include "chrono/collision/bullet/BulletCollision/CollisionShapes/btBoxShape.h"
24 #include "chrono/collision/bullet/BulletCollision/CollisionShapes/btCylindricalShellShape.h"
25 #include "chrono/collision/bullet/BulletCollision/CollisionShapes/btCapsuleShape.h"
26 #include "chrono/collision/bullet/BulletCollision/CollisionShapes/bt2DShape.h"
27 #include "chrono/collision/bullet/BulletCollision/CollisionShapes/btCEtriangleShape.h"
28 
29 namespace chrono {
30 namespace collision {
31 
32 // ================================================================================================
33 
btCapsuleBoxCollisionAlgorithm(btPersistentManifold * mf,const btCollisionAlgorithmConstructionInfo & ci,const btCollisionObjectWrapper * col0,const btCollisionObjectWrapper * col1,bool isSwapped)34 btCapsuleBoxCollisionAlgorithm::btCapsuleBoxCollisionAlgorithm(btPersistentManifold* mf,
35                                                                const btCollisionAlgorithmConstructionInfo& ci,
36                                                                const btCollisionObjectWrapper* col0,
37                                                                const btCollisionObjectWrapper* col1,
38                                                                bool isSwapped)
39     : btActivatingCollisionAlgorithm(ci, col0, col1), m_ownManifold(false), m_manifoldPtr(mf), m_isSwapped(isSwapped) {
40     const btCollisionObjectWrapper* capsuleObjWrap = m_isSwapped ? col1 : col0;
41     const btCollisionObjectWrapper* boxObjWrap = m_isSwapped ? col0 : col1;
42 
43     if (!m_manifoldPtr &&
44         m_dispatcher->needsCollision(capsuleObjWrap->getCollisionObject(), boxObjWrap->getCollisionObject())) {
45         m_manifoldPtr =
46             m_dispatcher->getNewManifold(capsuleObjWrap->getCollisionObject(), boxObjWrap->getCollisionObject());
47         m_ownManifold = true;
48     }
49 }
50 
btCapsuleBoxCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo & ci)51 btCapsuleBoxCollisionAlgorithm::btCapsuleBoxCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo& ci)
52     : btActivatingCollisionAlgorithm(ci) {}
53 
~btCapsuleBoxCollisionAlgorithm()54 btCapsuleBoxCollisionAlgorithm ::~btCapsuleBoxCollisionAlgorithm() {
55     if (m_ownManifold) {
56         if (m_manifoldPtr)
57             m_dispatcher->releaseManifold(m_manifoldPtr);
58     }
59 }
60 
61 // Capsule-box intersection test.
processCollision(const btCollisionObjectWrapper * body0,const btCollisionObjectWrapper * body1,const btDispatcherInfo & dispatchInfo,btManifoldResult * resultOut)62 void btCapsuleBoxCollisionAlgorithm::processCollision(const btCollisionObjectWrapper* body0,
63                                                       const btCollisionObjectWrapper* body1,
64                                                       const btDispatcherInfo& dispatchInfo,
65                                                       btManifoldResult* resultOut) {
66     (void)dispatchInfo;
67     (void)resultOut;
68     if (!m_manifoldPtr)
69         return;
70 
71     const btCollisionObjectWrapper* capObjWrap = m_isSwapped ? body1 : body0;
72     const btCollisionObjectWrapper* boxObjWrap = m_isSwapped ? body0 : body1;
73 
74     resultOut->setPersistentManifold(m_manifoldPtr);
75 
76     const btCapsuleShape* cap = (btCapsuleShape*)capObjWrap->getCollisionShape();
77     const btBoxShape* box = (btBoxShape*)boxObjWrap->getCollisionShape();
78 
79     // Express capsule in the box frame
80     const btTransform& abs_X_cap = capObjWrap->getWorldTransform();
81     const btTransform& abs_X_box = boxObjWrap->getWorldTransform();
82     btTransform box_X_cap = abs_X_box.inverseTimes(abs_X_cap);
83 
84     btVector3 a = box_X_cap.getBasis().getColumn(1);  // capsule axis (expressed in box frame)
85     btVector3 c = box_X_cap.getOrigin();              // capsule center (expressed in box frame)
86 
87     // Box dimensions
88     btVector3 hdims = box->getHalfExtentsWithMargin();
89 
90     // Cylinder dimensions
91     btScalar radius = cap->getRadius();    // capsule radius
92     btScalar hlen = cap->getHalfHeight();  // capsule half-length
93 
94     // Loop over each direction of the box frame (i.e., each of the 3 face normals).
95     // In each case, consider two segments on the cylindrical surface that are on a plane defined by the axis and the
96     // face normal. (Note that, in principle, we could only consider the segment "closest" to the box, but that is not
97     // trivial to define in all configurations). Such segments are parameterized by t in [-H,H].
98     //
99     // Consider (at most) 4 candidate points on each segment: the 2 ends of the segment and the intersections of the
100     // segment with the box (if such an intersection exists).
101     //
102     // For a capsule, projects these points back onto the capsule axis and check intersection between spheres centered
103     // at the points on the axis and the box.  In this case, the projection is done orthogonal to the capsule axis.
104 
105     const btScalar parallel_tol = btScalar(1e-5);           // tolearance for parallelism tests
106     const btScalar near_tol = btScalar(1e-4) * (2 * hlen);  // tolerance for line parameters of near duplicate points
107 
108     std::vector<btScalar> t_points = {-hlen, +hlen};  // initialize list of candidates with segment ends
109 
110     for (int i = 0; i < 3; i++) {
111         // "positive" face normal
112         btVector3 n(0, 0, 0);
113         n[i] = 1;
114 
115         // If the axis is parallel to the face normal, no additional candidate point.
116         btVector3 v = n.cross(a);
117         if (std::abs(a[i] - 1) < parallel_tol)
118             continue;
119 
120         // Direction perpendicular to axis
121         btVector3 r = v.cross(a);
122 
123         // Construct center points of the two segments on cylindrical surface
124         btVector3 c1 = c + radius * r;
125         btVector3 c2 = c - radius * r;
126 
127         // Check if either segment intersects box.
128         // If it does, append line parameters for intersection points (clamped to segment limits).
129         btScalar tMin;
130         btScalar tMax;
131         if (bt_utils::IntersectSegmentBox(hdims, c1, a, hlen, parallel_tol, tMin, tMax)) {
132             t_points.push_back(ChClamp(tMin, -hlen, +hlen));
133             t_points.push_back(ChClamp(tMax, -hlen, +hlen));
134         }
135         if (bt_utils::IntersectSegmentBox(hdims, c2, a, hlen, parallel_tol, tMin, tMax)) {
136             t_points.push_back(ChClamp(tMin, -hlen, +hlen));
137             t_points.push_back(ChClamp(tMax, -hlen, +hlen));
138         }
139     }
140 
141     // Contact distance
142     btScalar contactDist = radius;
143     ////btScalar contactDist = radius + m_manifoldPtr->getContactBreakingThreshold();
144 
145     // Loop over all candidate points (points on the capsule axis) and perform a sphere-box collision test.
146     // In order to eliminate near duplicate points, use a sorted list and keep track of last processed point.
147     std::sort(t_points.begin(), t_points.end());
148     btScalar t_last = -2 * hlen;
149     int n_contacts = 0;
150     for (auto t : t_points) {
151         if (t - t_last < near_tol)
152             continue;
153 
154         // Update last processed point
155         t_last = t;
156 
157         // Calculate sphere center (point on axis, expressed in box frame) and snap it to the surface of the box
158         btVector3 sphPos = c + a * t;
159         btVector3 boxPos = sphPos;
160         bt_utils::SnapPointToBox(hdims, boxPos);
161 
162         // If the distance from the sphere center to the closest point is larger than the radius plus the separation
163         // value, then there is no contact. Also, ignore contact if the sphere center (almost) coincides with the
164         // closest point, in which case we couldn't decide on the proper contact direction.
165         btVector3 delta = sphPos - boxPos;
166         btScalar dist2 = delta.length2();
167         if (dist2 >= contactDist * contactDist || dist2 <= 1e-12)
168             continue;
169 
170         // Generate contact information (transform to absolute frame)
171         btScalar dist = btSqrt(dist2);
172         btScalar penetration = dist - radius;
173         btVector3 normal = abs_X_box.getBasis() * (delta / dist);
174         btVector3 point = abs_X_box(boxPos);
175 
176         // A new contact point must specify:
177         //   normal, pointing from B towards A
178         //   point, located on surface of B
179         //   distance, negative for penetration
180         resultOut->addContactPoint(normal, point, penetration);
181         n_contacts++;
182     }
183 
184     if (m_ownManifold && m_manifoldPtr->getNumContacts()) {
185         resultOut->refreshContactPoints();
186     }
187 }
188 
calculateTimeOfImpact(btCollisionObject * body0,btCollisionObject * body1,const btDispatcherInfo & dispatchInfo,btManifoldResult * resultOut)189 btScalar btCapsuleBoxCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* body0,
190                                                                btCollisionObject* body1,
191                                                                const btDispatcherInfo& dispatchInfo,
192                                                                btManifoldResult* resultOut) {
193     // not yet
194     return btScalar(1.);
195 }
196 
getAllContactManifolds(btManifoldArray & manifoldArray)197 void btCapsuleBoxCollisionAlgorithm::getAllContactManifolds(btManifoldArray& manifoldArray) {
198     if (m_manifoldPtr && m_ownManifold) {
199         manifoldArray.push_back(m_manifoldPtr);
200     }
201 }
202 
CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo & ci,const btCollisionObjectWrapper * body0Wrap,const btCollisionObjectWrapper * body1Wrap)203 btCollisionAlgorithm* btCapsuleBoxCollisionAlgorithm::CreateFunc::CreateCollisionAlgorithm(
204     btCollisionAlgorithmConstructionInfo& ci,
205     const btCollisionObjectWrapper* body0Wrap,
206     const btCollisionObjectWrapper* body1Wrap) {
207     void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btCapsuleBoxCollisionAlgorithm));
208     if (!m_swapped) {
209         return new (mem) btCapsuleBoxCollisionAlgorithm(0, ci, body0Wrap, body1Wrap, false);
210     } else {
211         return new (mem) btCapsuleBoxCollisionAlgorithm(0, ci, body0Wrap, body1Wrap, true);
212     }
213 }
214 
215 // ================================================================================================
216 
btCylshellBoxCollisionAlgorithm(btPersistentManifold * mf,const btCollisionAlgorithmConstructionInfo & ci,const btCollisionObjectWrapper * col0,const btCollisionObjectWrapper * col1,bool isSwapped)217 btCylshellBoxCollisionAlgorithm::btCylshellBoxCollisionAlgorithm(btPersistentManifold* mf,
218                                                                  const btCollisionAlgorithmConstructionInfo& ci,
219                                                                  const btCollisionObjectWrapper* col0,
220                                                                  const btCollisionObjectWrapper* col1,
221                                                                  bool isSwapped)
222     : btActivatingCollisionAlgorithm(ci, col0, col1), m_ownManifold(false), m_manifoldPtr(mf), m_isSwapped(isSwapped) {
223     const btCollisionObjectWrapper* cylshellObjWrap = m_isSwapped ? col1 : col0;
224     const btCollisionObjectWrapper* boxObjWrap = m_isSwapped ? col0 : col1;
225 
226     if (!m_manifoldPtr &&
227         m_dispatcher->needsCollision(cylshellObjWrap->getCollisionObject(), boxObjWrap->getCollisionObject())) {
228         m_manifoldPtr =
229             m_dispatcher->getNewManifold(cylshellObjWrap->getCollisionObject(), boxObjWrap->getCollisionObject());
230         m_ownManifold = true;
231     }
232 }
233 
btCylshellBoxCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo & ci)234 btCylshellBoxCollisionAlgorithm::btCylshellBoxCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo& ci)
235     : btActivatingCollisionAlgorithm(ci) {}
236 
~btCylshellBoxCollisionAlgorithm()237 btCylshellBoxCollisionAlgorithm::~btCylshellBoxCollisionAlgorithm() {
238     if (m_ownManifold) {
239         if (m_manifoldPtr)
240             m_dispatcher->releaseManifold(m_manifoldPtr);
241     }
242 }
243 
244 // Check and add contact between the given cylshell point and the specified box face.
245 // 'iface' is +1, +2, +3 for the "positive" x, y, or z box face, respectively.
246 // 'iface' is -1, -2, -3 for the "negative" x, y, or z box face, respectively.
addContactPoint(const btVector3 & pc,int iface,const btVector3 & hdims,const btTransform & X_box,btManifoldResult * resultOut)247 int addContactPoint(const btVector3& pc,
248                     int iface,
249                     const btVector3& hdims,
250                     const btTransform& X_box,
251                     btManifoldResult* resultOut) {
252     assert(iface >= -3 && iface <= +3 && iface != 0);
253 
254     // No contact if point outside box
255     if (!bt_utils::PointInsideBox(hdims, pc))
256         return 0;  // no contacts added
257 
258     // Find point projection on box face and calculate normal and penetration
259     // (still working in the box frame)
260     btVector3 p = pc;
261     btVector3 n(0, 0, 0);
262     btScalar penetration;
263     if (iface > 0) {
264         // "positive" box face
265         int i = iface - 1;
266         p[i] = hdims[i];
267         n[i] = 1;
268         penetration = pc[i] - hdims[i];
269     } else {
270         // "negative" box face
271         int i = -iface - 1;
272         p[i] = -hdims[i];
273         n[i] = -1;
274         penetration = -pc[i] - hdims[i];
275     }
276 
277     // A new contact point must specify (in absolute frame):
278     //   normal, pointing from B towards A
279     //   point, located on surface of B
280     //   distance, negative for penetration
281     btVector3 normal = X_box.getBasis() * n;
282     btVector3 point = X_box(p);
283     resultOut->addContactPoint(normal, point, penetration);
284 
285     ////std::cout << "add contact     nrm = " << normal.x() << " " << normal.y() << " " << normal.z() << std::endl;
286     ////std::cout << "                pnt = " << point.x() << " " << point.y() << " " << point.z() << std::endl;
287     ////std::cout << "                pen = " << penetration << std::endl;
288 
289     return 1;  // one contact added
290 }
291 
292 // Add contact between the given box point (assumed to be in or on the cylinder) and the cylshell.
293 // All input vectors are assumed to be expressed in the box frame.
addContactPoint(const btVector3 & p,const btVector3 & c,const btVector3 & a,const btScalar h,const btScalar r,const btTransform & X_box,btManifoldResult * resultOut)294 int addContactPoint(const btVector3& p,
295                     const btVector3& c,
296                     const btVector3& a,
297                     const btScalar h,
298                     const btScalar r,
299                     const btTransform& X_box,
300                     btManifoldResult* resultOut) {
301     // Find closest point on cylindrical surface to given location
302     btVector3 q = bt_utils::ProjectPointOnLine(c, a, p);
303     btVector3 v = p - q;
304     btScalar dist = v.length();
305     btVector3 n = v / dist;
306 
307     btVector3 normal = X_box.getBasis() * (-n);
308     btVector3 point = X_box(p);
309 
310     resultOut->addContactPoint(normal, point, dist - r);
311 
312     return 1;
313 }
314 
315 // Cylshell-box intersection test:
316 //   - cylinder caps are ignored
317 //   - the cylshell is replaced with a capsule on the surface of the cylshell
318 //   - capsule-box intersection is then reduced to a segment-box intersection
319 //   - a replacement capsule (one for each direction of the box) may generate 0, 1, or 2 contacts
processCollision(const btCollisionObjectWrapper * body0,const btCollisionObjectWrapper * body1,const btDispatcherInfo & dispatchInfo,btManifoldResult * resultOut)320 void btCylshellBoxCollisionAlgorithm::processCollision(const btCollisionObjectWrapper* body0,
321                                                        const btCollisionObjectWrapper* body1,
322                                                        const btDispatcherInfo& dispatchInfo,
323                                                        btManifoldResult* resultOut) {
324     (void)dispatchInfo;
325     (void)resultOut;
326     if (!m_manifoldPtr)
327         return;
328 
329     const btCollisionObjectWrapper* cylObjWrap = m_isSwapped ? body1 : body0;
330     const btCollisionObjectWrapper* boxObjWrap = m_isSwapped ? body0 : body1;
331 
332     resultOut->setPersistentManifold(m_manifoldPtr);
333 
334     const btCylindricalShellShape* cyl = (btCylindricalShellShape*)cylObjWrap->getCollisionShape();
335     const btBoxShape* box = (btBoxShape*)boxObjWrap->getCollisionShape();
336 
337     // Express cylinder in the box frame
338     const btTransform& abs_X_cyl = cylObjWrap->getWorldTransform();
339     const btTransform& abs_X_box = boxObjWrap->getWorldTransform();
340     btTransform box_X_cyl = abs_X_box.inverseTimes(abs_X_cyl);
341 
342     btVector3 a = box_X_cyl.getBasis().getColumn(1);  // cylinder axis (expressed in box frame)
343     btVector3 c = box_X_cyl.getOrigin();              // cylinder center (expressed in box frame)
344 
345     // Box dimensions
346     btVector3 hdims = box->getHalfExtentsWithMargin();
347 
348     // Cylinder dimensions
349     btScalar radius = cyl->getRadius();    // cylinder radius
350     btScalar hlen = cyl->getHalfLength();  // cylinder half-length
351 
352     const btScalar parallel_tol = btScalar(1e-5);  // tolearance for parallelism tests
353 
354     int num_contacts = 0;
355 
356     // - Loop over each direction of the box frame (i.e., each of the 3 face normals).
357     // - For each direction, consider two segments on the cylindrical surface that are on a plane defined by the axis
358     //   and the face normal. (Note that, in principle, we could only consider the segment "closest" to the box, but
359     //   that is not trivial to define in all configurations). All segments are parameterized by t in [-H,H].
360     // - For each segment, if the segment intersects the box, consider 3 candidate contact points: the 2 intersection
361     //   points and their midpoint. A contact is added if the segment point is inside the box.
362     //   Furthermore, the corresponding box point is located on the box face that is closest to the intersection
363     //   midpoint candidate.
364     for (int idir = 0; idir < 3; idir++) {
365         // current box direction
366         btVector3 ndir(0, 0, 0);
367         ndir[idir] = 1;
368 
369         // If the axis is parallel to the current direction, no contact.
370         if (std::abs(a[idir] - 1) < parallel_tol || std::abs(a[idir] + 1) < parallel_tol)
371             continue;
372 
373         // Direction perpendicular to cylinder axis (in direction opposite to ndir)
374         btVector3 v = ndir.cross(a);
375         btVector3 r = v.cross(a);
376         assert(r.length() > parallel_tol);
377         r.normalize();
378 
379         // Consider segments in both "negative" and "positive" r direction
380         btScalar dir[2] = {-1, 1};
381         for (int jdir = 0; jdir < 2; jdir++) {
382             // Calculate current segment center
383             btVector3 cs = c + dir[jdir] * radius * r;
384             // Check for intersection with box
385             btScalar tMin, tMax;
386             if (bt_utils::IntersectSegmentBox(hdims, cs, a, hlen, parallel_tol, tMin, tMax)) {
387                 // Consider the intersection points and their midpoint as candidates
388                 btVector3 pMin = cs + a * tMin;
389                 btVector3 pMax = cs + a * tMax;
390                 btVector3 pMid = cs + a * ((tMin + tMax) / 2);
391 
392                 // Pick box face that is closest to midpoint
393                 int iface = bt_utils::FindClosestBoxFace(hdims, pMid);
394 
395                 // Add a contact for any of the candidate points that is inside the box
396                 num_contacts += addContactPoint(pMin, iface, hdims, abs_X_box, resultOut);  // 1st segment end
397                 num_contacts += addContactPoint(pMax, iface, hdims, abs_X_box, resultOut);  // 2nd segment end
398                 num_contacts += addContactPoint(pMid, iface, hdims, abs_X_box, resultOut);  // intersection midpoint
399             }
400         }
401     }
402 
403     // If a box face supports the cylinder, do not check box edges.
404     if (num_contacts > 0)
405         return;
406 
407     // - Loop over each direction of the box frame.
408     // - For each direction, check intersection with the cylinder for all 4 edges parallel to that direction.
409     // - If an edge intersects the cylinder, consider 3 candidate contact points: the 2 intersection points
410     //   and their midpoint.
411     for (int idir = 0; idir < 3; idir++) {
412         // current box edge direction and halflength
413         btVector3 eD(0, 0, 0);
414         eD[idir] = 1;
415         btScalar eH = hdims[idir];
416         // The other two box directions
417         int jdir = (idir + 1) % 3;
418         int kdir = (idir + 2) % 3;
419         for (int j = -1; j <= +1; j += 2) {
420             for (int k = -1; k <= +1; k += 2) {
421                 btVector3 eC;
422                 eC[idir] = 0;
423                 eC[jdir] = j * hdims[jdir];
424                 eC[kdir] = k * hdims[kdir];
425                 // Check for edge intersection with cylinder
426                 btScalar tMin, tMax;
427                 if (bt_utils::IntersectSegmentCylinder(eC, eD, eH, c, a, hlen, radius, parallel_tol, tMin, tMax)) {
428                     // Consider the intersection points and their midpoint as candidates
429                     btVector3 pMin = eC + eD * tMin;
430                     btVector3 pMax = eC + eD * tMax;
431                     btVector3 pMid = eC + eD * ((tMin + tMax) / 2);
432 
433                     // Add a contact for any of the candidate points that is inside the cylinder
434                     num_contacts += addContactPoint(pMin, c, a, hlen, radius, abs_X_box, resultOut);
435                     num_contacts += addContactPoint(pMax, c, a, hlen, radius, abs_X_box, resultOut);
436                     num_contacts += addContactPoint(pMid, c, a, hlen, radius, abs_X_box, resultOut);
437                 }
438             }
439         }
440 
441     }
442 
443     ////std::cout << num_contacts << std::endl;
444 
445     if (m_ownManifold && m_manifoldPtr->getNumContacts()) {
446         resultOut->refreshContactPoints();
447     }
448 }
449 
calculateTimeOfImpact(btCollisionObject * body0,btCollisionObject * body1,const btDispatcherInfo & dispatchInfo,btManifoldResult * resultOut)450 btScalar btCylshellBoxCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* body0,
451                                                                 btCollisionObject* body1,
452                                                                 const btDispatcherInfo& dispatchInfo,
453                                                                 btManifoldResult* resultOut) {
454     // not yet
455     return btScalar(1.);
456 }
457 
getAllContactManifolds(btManifoldArray & manifoldArray)458 void btCylshellBoxCollisionAlgorithm::getAllContactManifolds(btManifoldArray& manifoldArray) {
459     if (m_manifoldPtr && m_ownManifold) {
460         manifoldArray.push_back(m_manifoldPtr);
461     }
462 }
463 
CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo & ci,const btCollisionObjectWrapper * body0Wrap,const btCollisionObjectWrapper * body1Wrap)464 btCollisionAlgorithm* btCylshellBoxCollisionAlgorithm::CreateFunc::CreateCollisionAlgorithm(
465     btCollisionAlgorithmConstructionInfo& ci,
466     const btCollisionObjectWrapper* body0Wrap,
467     const btCollisionObjectWrapper* body1Wrap) {
468     void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btCylshellBoxCollisionAlgorithm));
469     if (!m_swapped) {
470         return new (mem) btCylshellBoxCollisionAlgorithm(0, ci, body0Wrap, body1Wrap, false);
471     } else {
472         return new (mem) btCylshellBoxCollisionAlgorithm(0, ci, body0Wrap, body1Wrap, true);
473     }
474 }
475 
476 // ================================================================================================
477 
btSphereCylinderCollisionAlgorithm(btPersistentManifold * mf,const btCollisionAlgorithmConstructionInfo & ci,const btCollisionObjectWrapper * col0,const btCollisionObjectWrapper * col1,bool isSwapped)478 btSphereCylinderCollisionAlgorithm::btSphereCylinderCollisionAlgorithm(btPersistentManifold* mf,
479                                                                        const btCollisionAlgorithmConstructionInfo& ci,
480                                                                        const btCollisionObjectWrapper* col0,
481                                                                        const btCollisionObjectWrapper* col1,
482                                                                        bool isSwapped)
483     : btActivatingCollisionAlgorithm(ci, col0, col1), m_ownManifold(false), m_manifoldPtr(mf), m_isSwapped(isSwapped) {
484     const btCollisionObjectWrapper* sphereObj = m_isSwapped ? col1 : col0;
485     const btCollisionObjectWrapper* cylObj = m_isSwapped ? col0 : col1;
486 
487     if (!m_manifoldPtr && m_dispatcher->needsCollision(sphereObj->getCollisionObject(), cylObj->getCollisionObject())) {
488         m_manifoldPtr = m_dispatcher->getNewManifold(sphereObj->getCollisionObject(), cylObj->getCollisionObject());
489         m_ownManifold = true;
490     }
491 }
492 
btSphereCylinderCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo & ci)493 btSphereCylinderCollisionAlgorithm::btSphereCylinderCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo& ci)
494     : btActivatingCollisionAlgorithm(ci) {}
495 
~btSphereCylinderCollisionAlgorithm()496 btSphereCylinderCollisionAlgorithm ::~btSphereCylinderCollisionAlgorithm() {
497     if (m_ownManifold) {
498         if (m_manifoldPtr)
499             m_dispatcher->releaseManifold(m_manifoldPtr);
500     }
501 }
502 
processCollision(const btCollisionObjectWrapper * body0,const btCollisionObjectWrapper * body1,const btDispatcherInfo & dispatchInfo,btManifoldResult * resultOut)503 void btSphereCylinderCollisionAlgorithm::processCollision(const btCollisionObjectWrapper* body0,
504                                                           const btCollisionObjectWrapper* body1,
505                                                           const btDispatcherInfo& dispatchInfo,
506                                                           btManifoldResult* resultOut) {
507     (void)dispatchInfo;
508     (void)resultOut;
509     if (!m_manifoldPtr)
510         return;
511 
512     const btCollisionObjectWrapper* sphereObjWrap = m_isSwapped ? body1 : body0;
513     const btCollisionObjectWrapper* cylObjWrap = m_isSwapped ? body0 : body1;
514 
515     resultOut->setPersistentManifold(m_manifoldPtr);
516 
517     const btSphereShape* sphere0 = (btSphereShape*)sphereObjWrap->getCollisionShape();
518     const btCylinderShape* cylinder = (btCylinderShape*)cylObjWrap->getCollisionShape();
519 
520     const btTransform& m44T = cylObjWrap->getCollisionObject()->getWorldTransform();
521     btVector3 diff = m44T.invXform(
522         sphereObjWrap->getCollisionObject()
523             ->getWorldTransform()
524             .getOrigin());  // col0->getWorldTransform().getOrigin()-  col1->getWorldTransform().getOrigin();
525     btScalar radius0 = sphere0->getRadius();
526     btScalar radius1 = cylinder->getHalfExtentsWithMargin().getX();  // cylinder->getRadius();
527     btScalar H1 = cylinder->getHalfExtentsWithMargin().getY();
528 
529     btVector3 r1 = diff;
530     r1.setY(0);
531 
532     btScalar y1 = diff.y();
533 
534     btScalar r1_len = r1.length();
535 
536     btVector3 pos1;
537     btVector3 normalOnSurfaceB(1, 0, 0);
538     btScalar dist;
539 
540     // Case A
541     if ((y1 <= H1) && (y1 >= -H1)) {
542         /// iff distance positive, don't generate a new contact
543         if (r1_len > (radius0 + radius1)) {
544             resultOut->refreshContactPoints();
545             return;
546         }
547         /// distance (negative means penetration)
548         dist = r1_len - (radius0 + radius1);
549 
550         btVector3 localnormalOnSurfaceB;
551         if (r1_len > SIMD_EPSILON) {
552             localnormalOnSurfaceB = r1 / r1_len;
553             normalOnSurfaceB = m44T.getBasis() * localnormalOnSurfaceB;
554         }
555         /// point on B (worldspace)
556         pos1 = m44T(btVector3(0, y1, 0)) + radius1 * normalOnSurfaceB;
557     } else {
558         btScalar side = 1;
559         if (y1 < -H1)
560             side = -1;
561 
562         if (r1_len > radius1) {
563             // case B
564             btVector3 pos_loc = r1.normalized() * radius1 + btVector3(0, H1 * side, 0);
565             pos1 = m44T(pos_loc);
566             btVector3 d = sphereObjWrap->getCollisionObject()->getWorldTransform().getOrigin() - pos1;
567             normalOnSurfaceB = d.normalized();
568             dist = d.length() - radius0;
569         } else {
570             // case C
571             normalOnSurfaceB = m44T.getBasis() * btVector3(0, 1 * side, 0);
572             btVector3 pos_loc = r1 + btVector3(0, H1 * side, 0);
573             pos1 = m44T(pos_loc);
574             dist = side * (y1 - H1) - radius0;
575         }
576     }
577     /// report a contact. internally this will be kept persistent, and contact reduction is done
578     resultOut->addContactPoint(normalOnSurfaceB, pos1, dist);
579 
580     resultOut->refreshContactPoints();
581 }
582 
calculateTimeOfImpact(btCollisionObject * body0,btCollisionObject * body1,const btDispatcherInfo & dispatchInfo,btManifoldResult * resultOut)583 btScalar btSphereCylinderCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* body0,
584                                                                    btCollisionObject* body1,
585                                                                    const btDispatcherInfo& dispatchInfo,
586                                                                    btManifoldResult* resultOut) {
587     // not yet
588     return btScalar(1.);
589 }
590 
getAllContactManifolds(btManifoldArray & manifoldArray)591 void btSphereCylinderCollisionAlgorithm::getAllContactManifolds(btManifoldArray& manifoldArray) {
592     if (m_manifoldPtr && m_ownManifold) {
593         manifoldArray.push_back(m_manifoldPtr);
594     }
595 }
596 
CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo & ci,const btCollisionObjectWrapper * body0Wrap,const btCollisionObjectWrapper * body1Wrap)597 btCollisionAlgorithm* btSphereCylinderCollisionAlgorithm::CreateFunc::CreateCollisionAlgorithm(
598     btCollisionAlgorithmConstructionInfo& ci,
599     const btCollisionObjectWrapper* body0Wrap,
600     const btCollisionObjectWrapper* body1Wrap) {
601     void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btSphereCylinderCollisionAlgorithm));
602     if (!m_swapped) {
603         return new (mem) btSphereCylinderCollisionAlgorithm(0, ci, body0Wrap, body1Wrap, false);
604     } else {
605         return new (mem) btSphereCylinderCollisionAlgorithm(0, ci, body0Wrap, body1Wrap, true);
606     }
607 }
608 
609 // ================================================================================================
610 
btArcSegmentCollisionAlgorithm(btPersistentManifold * mf,const btCollisionAlgorithmConstructionInfo & ci,const btCollisionObjectWrapper * col0,const btCollisionObjectWrapper * col1,bool isSwapped)611 btArcSegmentCollisionAlgorithm::btArcSegmentCollisionAlgorithm(btPersistentManifold* mf,
612                                                                const btCollisionAlgorithmConstructionInfo& ci,
613                                                                const btCollisionObjectWrapper* col0,
614                                                                const btCollisionObjectWrapper* col1,
615                                                                bool isSwapped)
616     : btActivatingCollisionAlgorithm(ci, col0, col1), m_ownManifold(false), m_manifoldPtr(mf), m_isSwapped(isSwapped) {
617     const btCollisionObjectWrapper* arcObjWrap = m_isSwapped ? col1 : col0;
618     const btCollisionObjectWrapper* segmentObjWrap = m_isSwapped ? col0 : col1;
619 
620     if (!m_manifoldPtr &&
621         m_dispatcher->needsCollision(arcObjWrap->getCollisionObject(), segmentObjWrap->getCollisionObject())) {
622         m_manifoldPtr =
623             m_dispatcher->getNewManifold(arcObjWrap->getCollisionObject(), segmentObjWrap->getCollisionObject());
624         m_ownManifold = true;
625     }
626 }
627 
btArcSegmentCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo & ci)628 btArcSegmentCollisionAlgorithm::btArcSegmentCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo& ci)
629     : btActivatingCollisionAlgorithm(ci) {}
630 
~btArcSegmentCollisionAlgorithm()631 btArcSegmentCollisionAlgorithm ::~btArcSegmentCollisionAlgorithm() {
632     if (m_ownManifold) {
633         if (m_manifoldPtr)
634             m_dispatcher->releaseManifold(m_manifoldPtr);
635     }
636 }
637 
processCollision(const btCollisionObjectWrapper * body0,const btCollisionObjectWrapper * body1,const btDispatcherInfo & dispatchInfo,btManifoldResult * resultOut)638 void btArcSegmentCollisionAlgorithm::processCollision(const btCollisionObjectWrapper* body0,
639                                                       const btCollisionObjectWrapper* body1,
640                                                       const btDispatcherInfo& dispatchInfo,
641                                                       btManifoldResult* resultOut) {
642     (void)dispatchInfo;
643     (void)resultOut;
644     if (!m_manifoldPtr)
645         return;
646 
647     const btCollisionObjectWrapper* arcObjWrap = m_isSwapped ? body1 : body0;
648     const btCollisionObjectWrapper* segmentObjWrap = m_isSwapped ? body0 : body1;
649 
650     resultOut->setPersistentManifold(m_manifoldPtr);
651 
652     // only 1 contact per pair, avoid persistence
653     resultOut->getPersistentManifold()->clearManifold();
654 
655     const bt2DarcShape* arc = (bt2DarcShape*)arcObjWrap->getCollisionShape();
656     const bt2DsegmentShape* segment = (bt2DsegmentShape*)segmentObjWrap->getCollisionShape();
657 
658     // A concave arc (i.e.with outward volume, counterclockwise abscissa) will never collide with segments
659     if (arc->get_counterclock())
660         return;
661 
662     const btTransform& m44Tarc = arcObjWrap->getCollisionObject()->getWorldTransform();
663     const btTransform& m44Tsegment = segmentObjWrap->getCollisionObject()->getWorldTransform();
664 
665     // Shapes on two planes that are not so parallel? no collisions!
666     btVector3 Zarc = m44Tarc.getBasis().getColumn(2);
667     btVector3 Zsegment = m44Tsegment.getBasis().getColumn(2);
668     if (fabs(Zarc.dot(Zsegment)) < 0.99)  //***TODO*** threshold as setting
669         return;
670 
671     // Shapes on two planes that are too far? no collisions!
672     btVector3 diff = m44Tsegment.invXform(m44Tarc.getOrigin());
673     if (fabs(diff.getZ()) > (arc->get_zthickness() + segment->get_zthickness()))
674         return;
675 
676     // vectors of body 1 in body 2 csys:
677     btVector3 local_arc_center = m44Tsegment.invXform(m44Tarc * btVector3(arc->get_X(), arc->get_Y(), 0));
678     btVector3 local_arc_X = m44Tsegment.getBasis().transpose() * (m44Tarc.getBasis() * btVector3(1, 0, 0));
679     double local_arc_rot = atan2(local_arc_X.getY(), local_arc_X.getX());
680     double arc1_angle1 = local_arc_rot + arc->get_angle1();
681     double arc1_angle2 = local_arc_rot + arc->get_angle2();
682 
683     btVector3 local_CS1 = local_arc_center - segment->get_P1();
684     btVector3 local_seg_S2S1 = (segment->get_P2() - segment->get_P1());
685     btScalar seg_length = local_seg_S2S1.length();
686     if (seg_length < 1e-30)
687         return;
688     btVector3 local_seg_D = local_seg_S2S1 / seg_length;
689     btScalar param = local_CS1.dot(local_seg_D);
690 
691     // contact out of segment extrema?
692     if (param < 0)
693         return;
694     if (param > seg_length)
695         return;
696 
697     btVector3 local_P2 = segment->get_P1() + local_seg_D * param;
698     btVector3 local_CP2 = local_arc_center - local_P2;
699     local_CP2.setZ(0);
700     btVector3 local_R = local_CP2.normalized() * arc->get_radius();
701     btVector3 local_P1;
702     btVector3 local_N2;
703     if (local_seg_S2S1.cross(local_CP2).getZ() > 0) {
704         local_P1 = local_arc_center - local_R;
705         local_N2 = local_CP2.normalized();
706     } else {
707         local_P1 = local_arc_center + local_R;
708         local_N2 = -local_CP2.normalized();
709     }
710 
711     double alpha = atan2(-local_N2.getY(), -local_N2.getX());
712 
713     // Discard points out of min-max angles
714 
715     // to always positive angles:
716     arc1_angle1 = fmod(arc1_angle1 + 1e-30, CH_C_2PI);
717     if (arc1_angle1 < 0)
718         arc1_angle1 += CH_C_2PI;
719     arc1_angle2 = fmod(arc1_angle2 + 1e-30, CH_C_2PI);
720     if (arc1_angle2 < 0)
721         arc1_angle2 += CH_C_2PI;
722     alpha = fmod(alpha, CH_C_2PI);
723     if (alpha < 0)
724         alpha += CH_C_2PI;
725 
726     arc1_angle1 = fmod(arc1_angle1, CH_C_2PI);
727     arc1_angle2 = fmod(arc1_angle2, CH_C_2PI);
728 
729     alpha = fmod(alpha, CH_C_2PI);
730 
731     bool inangle1 = false;
732 
733     if (arc1_angle1 < arc1_angle2) {
734         if (alpha >= arc1_angle2 || alpha <= arc1_angle1)
735             inangle1 = true;
736     } else {
737         if (alpha >= arc1_angle2 && alpha <= arc1_angle1)
738             inangle1 = true;
739     }
740 
741     if (!inangle1)
742         return;
743 
744     // transform in absolute coords:
745     // btVector3 pos1 = m44Tsegment * local_P1; // not needed
746     btVector3 pos2 = m44Tsegment * local_P2;
747     btVector3 normal_on_2 = m44Tsegment.getBasis() * local_N2;
748     btScalar dist = local_N2.dot(local_P1 - local_P2);
749 
750     // too far or too interpenetrate? discard.
751     if (fabs(dist) > (arc->getMargin() + segment->getMargin()))
752         return;
753 
754     /// report a contact. internally this will be kept persistent, and contact reduction is done
755     resultOut->addContactPoint(normal_on_2, pos2, dist);
756 
757     resultOut->refreshContactPoints();
758 }
759 
calculateTimeOfImpact(btCollisionObject * body0,btCollisionObject * body1,const btDispatcherInfo & dispatchInfo,btManifoldResult * resultOut)760 btScalar btArcSegmentCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* body0,
761                                                                btCollisionObject* body1,
762                                                                const btDispatcherInfo& dispatchInfo,
763                                                                btManifoldResult* resultOut) {
764     // not yet
765     return btScalar(1.);
766 }
767 
getAllContactManifolds(btManifoldArray & manifoldArray)768 void btArcSegmentCollisionAlgorithm::getAllContactManifolds(btManifoldArray& manifoldArray) {
769     if (m_manifoldPtr && m_ownManifold) {
770         manifoldArray.push_back(m_manifoldPtr);
771     }
772 }
773 
CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo & ci,const btCollisionObjectWrapper * body0Wrap,const btCollisionObjectWrapper * body1Wrap)774 btCollisionAlgorithm* btArcSegmentCollisionAlgorithm::CreateFunc::CreateCollisionAlgorithm(
775     btCollisionAlgorithmConstructionInfo& ci,
776     const btCollisionObjectWrapper* body0Wrap,
777     const btCollisionObjectWrapper* body1Wrap) {
778     void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btArcSegmentCollisionAlgorithm));
779     if (!m_swapped) {
780         return new (mem) btArcSegmentCollisionAlgorithm(0, ci, body0Wrap, body1Wrap, false);
781     } else {
782         return new (mem) btArcSegmentCollisionAlgorithm(0, ci, body0Wrap, body1Wrap, true);
783     }
784 }
785 
786 // ================================================================================================
787 
btArcArcCollisionAlgorithm(btPersistentManifold * mf,const btCollisionAlgorithmConstructionInfo & ci,const btCollisionObjectWrapper * col0,const btCollisionObjectWrapper * col1,bool isSwapped)788 btArcArcCollisionAlgorithm::btArcArcCollisionAlgorithm(btPersistentManifold* mf,
789                                                        const btCollisionAlgorithmConstructionInfo& ci,
790                                                        const btCollisionObjectWrapper* col0,
791                                                        const btCollisionObjectWrapper* col1,
792                                                        bool isSwapped)
793     : btActivatingCollisionAlgorithm(ci, col0, col1), m_ownManifold(false), m_manifoldPtr(mf), m_isSwapped(isSwapped) {
794     const btCollisionObjectWrapper* arcObj1Wrap = m_isSwapped ? col1 : col0;
795     const btCollisionObjectWrapper* arcObj2Wrap = m_isSwapped ? col0 : col1;
796 
797     if (!m_manifoldPtr &&
798         m_dispatcher->needsCollision(arcObj1Wrap->getCollisionObject(), arcObj2Wrap->getCollisionObject())) {
799         m_manifoldPtr =
800             m_dispatcher->getNewManifold(arcObj1Wrap->getCollisionObject(), arcObj2Wrap->getCollisionObject());
801         m_ownManifold = true;
802     }
803 }
804 
btArcArcCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo & ci)805 btArcArcCollisionAlgorithm::btArcArcCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo& ci)
806     : btActivatingCollisionAlgorithm(ci) {}
807 
~btArcArcCollisionAlgorithm()808 btArcArcCollisionAlgorithm ::~btArcArcCollisionAlgorithm() {
809     if (m_ownManifold) {
810         if (m_manifoldPtr)
811             m_dispatcher->releaseManifold(m_manifoldPtr);
812     }
813 }
814 
processCollision(const btCollisionObjectWrapper * body0,const btCollisionObjectWrapper * body1,const btDispatcherInfo & dispatchInfo,btManifoldResult * resultOut)815 void btArcArcCollisionAlgorithm::processCollision(const btCollisionObjectWrapper* body0,
816                                                   const btCollisionObjectWrapper* body1,
817                                                   const btDispatcherInfo& dispatchInfo,
818                                                   btManifoldResult* resultOut) {
819     (void)dispatchInfo;
820     (void)resultOut;
821     if (!m_manifoldPtr)
822         return;
823 
824     const btCollisionObjectWrapper* arcObj1Wrap = m_isSwapped ? body1 : body0;
825     const btCollisionObjectWrapper* arcObj2Wrap = m_isSwapped ? body0 : body1;
826 
827     resultOut->setPersistentManifold(m_manifoldPtr);
828 
829     // only 1 contact per pair, avoid persistence
830     resultOut->getPersistentManifold()->clearManifold();
831 
832     const bt2DarcShape* arc1 = (bt2DarcShape*)arcObj1Wrap->getCollisionShape();
833     const bt2DarcShape* arc2 = (bt2DarcShape*)arcObj2Wrap->getCollisionShape();
834 
835     const btTransform& m44Tarc1 = arcObj1Wrap->getCollisionObject()->getWorldTransform();
836     const btTransform& m44Tarc2 = arcObj2Wrap->getCollisionObject()->getWorldTransform();
837 
838     // Shapes on two planes that are not so parallel? no collisions!
839     btVector3 Zarc1 = m44Tarc1.getBasis().getColumn(2);
840     btVector3 Zarc2 = m44Tarc2.getBasis().getColumn(2);
841     if (fabs(Zarc1.dot(Zarc2)) < 0.99)  //***TODO*** threshold as setting
842         return;
843 
844     // Shapes on two planes that are too far? no collisions!
845     btVector3 diff = m44Tarc2.invXform(m44Tarc1.getOrigin());
846     if (fabs(diff.getZ()) > (arc1->get_zthickness() + arc2->get_zthickness()))
847         return;
848 
849     // vectors and angles of arc 1 in arc 2 csys:
850     btVector3 local_arc1_center = m44Tarc2.invXform(m44Tarc1 * btVector3(arc1->get_X(), arc1->get_Y(), 0));
851     btVector3 local_arc1_X = m44Tarc2.getBasis().transpose() * (m44Tarc1.getBasis() * btVector3(1, 0, 0));
852     double local_arc1_rot = atan2(local_arc1_X.getY(), local_arc1_X.getX());
853     double arc1_angle1 = local_arc1_rot + arc1->get_angle1();
854     double arc1_angle2 = local_arc1_rot + arc1->get_angle2();
855 
856     btVector3 local_arc2_center = btVector3(arc2->get_X(), arc2->get_Y(), 0);
857     double arc2_angle1 = arc2->get_angle1();
858     double arc2_angle2 = arc2->get_angle2();
859 
860     btVector3 local_C1C2 = local_arc1_center - local_arc2_center;
861     btVector3 local_D12 = local_C1C2.normalized();
862 
863     btVector3 local_P1;
864     btVector3 local_P2;
865     btVector3 local_N2;
866     double dist = 0;
867     bool paired = false;
868     double alpha = atan2(local_C1C2.getY(), local_C1C2.getX());
869     double alpha1 = 0, alpha2 = 0;
870 
871     // convex-convex
872     if (arc1->get_counterclock() == false && arc2->get_counterclock() == false) {
873         local_P1 = local_arc1_center - local_D12 * arc1->get_radius();
874         local_P2 = local_arc2_center + local_D12 * arc2->get_radius();
875         local_N2 = local_D12;
876         dist = local_C1C2.length() - arc1->get_radius() - arc2->get_radius();
877         alpha1 = alpha + CH_C_PI;
878         alpha2 = alpha;
879         paired = true;
880     }
881     // convex-concave
882     if (arc1->get_counterclock() == false && arc2->get_counterclock() == true)
883         if (arc1->get_radius() <= arc2->get_radius()) {
884             local_P1 = local_arc1_center + local_D12 * arc1->get_radius();
885             local_P2 = local_arc2_center + local_D12 * arc2->get_radius();
886             local_N2 = -local_D12;
887             dist = -local_C1C2.length() - arc1->get_radius() + arc2->get_radius();
888             alpha1 = alpha;
889             alpha2 = alpha;
890             paired = true;
891         }
892     // concave-convex
893     if (arc1->get_counterclock() == true && arc2->get_counterclock() == false)
894         if (arc1->get_radius() >= arc2->get_radius()) {
895             local_P1 = local_arc1_center - local_D12 * arc1->get_radius();
896             local_P2 = local_arc2_center - local_D12 * arc2->get_radius();
897             local_N2 = -local_D12;
898             dist = -local_C1C2.length() + arc1->get_radius() - arc2->get_radius();
899             alpha1 = alpha + CH_C_PI;
900             alpha2 = alpha + CH_C_PI;
901             paired = true;
902         }
903 
904     if (!paired)
905         return;
906 
907     // Discard points out of min-max angles
908 
909     // to always positive angles:
910     arc1_angle1 = fmod(arc1_angle1, CH_C_2PI);
911     if (arc1_angle1 < 0)
912         arc1_angle1 += CH_C_2PI;
913     arc1_angle2 = fmod(arc1_angle2, CH_C_2PI);
914     if (arc1_angle2 < 0)
915         arc1_angle2 += CH_C_2PI;
916     arc2_angle1 = fmod(arc2_angle1, CH_C_2PI);
917     if (arc2_angle1 < 0)
918         arc2_angle1 += CH_C_2PI;
919     arc2_angle2 = fmod(arc2_angle2, CH_C_2PI);
920     if (arc2_angle2 < 0)
921         arc2_angle2 += CH_C_2PI;
922     alpha1 = fmod(alpha1, CH_C_2PI);
923     if (alpha1 < 0)
924         alpha1 += CH_C_2PI;
925     alpha2 = fmod(alpha2, CH_C_2PI);
926     if (alpha2 < 0)
927         alpha2 += CH_C_2PI;
928 
929     arc1_angle1 = fmod(arc1_angle1, CH_C_2PI);
930     arc1_angle2 = fmod(arc1_angle2, CH_C_2PI);
931     arc2_angle1 = fmod(arc2_angle1, CH_C_2PI);
932     arc2_angle2 = fmod(arc2_angle2, CH_C_2PI);
933     alpha1 = fmod(alpha1, CH_C_2PI);
934     alpha2 = fmod(alpha2, CH_C_2PI);
935 
936     bool inangle1 = false;
937     bool inangle2 = false;
938 
939     if (arc1->get_counterclock() == true) {
940         if (arc1_angle1 < arc1_angle2) {
941             if (alpha1 >= arc1_angle1 && alpha1 <= arc1_angle2)
942                 inangle1 = true;
943         } else {
944             if (alpha1 >= arc1_angle1 || alpha1 <= arc1_angle2)
945                 inangle1 = true;
946         }
947     } else {
948         if (arc1_angle1 < arc1_angle2) {
949             if (alpha1 >= arc1_angle2 || alpha1 <= arc1_angle1)
950                 inangle1 = true;
951         } else {
952             if (alpha1 >= arc1_angle2 && alpha1 <= arc1_angle1)
953                 inangle1 = true;
954         }
955     }
956 
957     if (arc2->get_counterclock() == true) {
958         if (arc2_angle1 < arc2_angle2) {
959             if (alpha2 >= arc2_angle1 && alpha2 <= arc2_angle2)
960                 inangle2 = true;
961         } else {
962             if (alpha2 >= arc2_angle1 || alpha2 <= arc2_angle2)
963                 inangle2 = true;
964         }
965     } else {
966         if (arc2_angle1 < arc2_angle2) {
967             if (alpha2 >= arc2_angle2 || alpha2 <= arc2_angle1)
968                 inangle2 = true;
969         } else {
970             if (alpha2 >= arc2_angle2 && alpha2 <= arc2_angle1)
971                 inangle2 = true;
972         }
973     }
974 
975     if (!(inangle1 && inangle2))
976         return;
977 
978     // transform in absolute coords:
979     btVector3 pos2 = m44Tarc2 * local_P2;
980     btVector3 normal_on_2 = m44Tarc2.getBasis() * local_N2;
981 
982     // too far or too interpenetrate? discard.
983     if (fabs(dist) > (arc1->getMargin() + arc2->getMargin()))
984         return;
985 
986     /// report a contact.
987     resultOut->addContactPoint(normal_on_2, pos2, (btScalar)dist);
988 
989     resultOut->refreshContactPoints();
990 }
991 
calculateTimeOfImpact(btCollisionObject * body0,btCollisionObject * body1,const btDispatcherInfo & dispatchInfo,btManifoldResult * resultOut)992 btScalar btArcArcCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* body0,
993                                                            btCollisionObject* body1,
994                                                            const btDispatcherInfo& dispatchInfo,
995                                                            btManifoldResult* resultOut) {
996     // not yet
997     return btScalar(1.);
998 }
999 
getAllContactManifolds(btManifoldArray & manifoldArray)1000 void btArcArcCollisionAlgorithm::getAllContactManifolds(btManifoldArray& manifoldArray) {
1001     if (m_manifoldPtr && m_ownManifold) {
1002         manifoldArray.push_back(m_manifoldPtr);
1003     }
1004 }
1005 
CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo & ci,const btCollisionObjectWrapper * body0Wrap,const btCollisionObjectWrapper * body1Wrap)1006 btCollisionAlgorithm* btArcArcCollisionAlgorithm::CreateFunc::CreateCollisionAlgorithm(
1007     btCollisionAlgorithmConstructionInfo& ci,
1008     const btCollisionObjectWrapper* body0Wrap,
1009     const btCollisionObjectWrapper* body1Wrap) {
1010     void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btArcArcCollisionAlgorithm));
1011     if (!m_swapped) {
1012         return new (mem) btArcArcCollisionAlgorithm(0, ci, body0Wrap, body1Wrap, false);
1013     } else {
1014         return new (mem) btArcArcCollisionAlgorithm(0, ci, body0Wrap, body1Wrap, true);
1015     }
1016 }
1017 
1018 // ================================================================================================
1019 
btCEtriangleShapeCollisionAlgorithm(btPersistentManifold * mf,const btCollisionAlgorithmConstructionInfo & ci,const btCollisionObjectWrapper * col0,const btCollisionObjectWrapper * col1,bool isSwapped)1020 btCEtriangleShapeCollisionAlgorithm::btCEtriangleShapeCollisionAlgorithm(btPersistentManifold* mf,
1021                                                                          const btCollisionAlgorithmConstructionInfo& ci,
1022                                                                          const btCollisionObjectWrapper* col0,
1023                                                                          const btCollisionObjectWrapper* col1,
1024                                                                          bool isSwapped)
1025     : btActivatingCollisionAlgorithm(ci, col0, col1), m_ownManifold(false), m_manifoldPtr(mf), m_isSwapped(isSwapped) {
1026     const btCollisionObjectWrapper* triObj1Wrap = m_isSwapped ? col1 : col0;
1027     const btCollisionObjectWrapper* triObj2Wrap = m_isSwapped ? col0 : col1;
1028 
1029     if (!m_manifoldPtr &&
1030         m_dispatcher->needsCollision(triObj1Wrap->getCollisionObject(), triObj2Wrap->getCollisionObject())) {
1031         m_manifoldPtr =
1032             m_dispatcher->getNewManifold(triObj1Wrap->getCollisionObject(), triObj2Wrap->getCollisionObject());
1033         m_ownManifold = true;
1034     }
1035 }
1036 
btCEtriangleShapeCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo & ci)1037 btCEtriangleShapeCollisionAlgorithm::btCEtriangleShapeCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo& ci)
1038     : btActivatingCollisionAlgorithm(ci) {}
1039 
~btCEtriangleShapeCollisionAlgorithm()1040 btCEtriangleShapeCollisionAlgorithm ::~btCEtriangleShapeCollisionAlgorithm() {
1041     if (m_ownManifold) {
1042         if (m_manifoldPtr)
1043             m_dispatcher->releaseManifold(m_manifoldPtr);
1044     }
1045 }
1046 
processCollision(const btCollisionObjectWrapper * body0,const btCollisionObjectWrapper * body1,const btDispatcherInfo & dispatchInfo,btManifoldResult * resultOut)1047 void btCEtriangleShapeCollisionAlgorithm::processCollision(const btCollisionObjectWrapper* body0,
1048                                                            const btCollisionObjectWrapper* body1,
1049                                                            const btDispatcherInfo& dispatchInfo,
1050                                                            btManifoldResult* resultOut) {
1051     (void)dispatchInfo;
1052     (void)resultOut;
1053     if (!m_manifoldPtr)
1054         return;
1055 
1056     const btCollisionObjectWrapper* triObj1Wrap = m_isSwapped ? body1 : body0;
1057     const btCollisionObjectWrapper* triObj2Wrap = m_isSwapped ? body0 : body1;
1058 
1059     resultOut->setPersistentManifold(m_manifoldPtr);
1060 
1061     // avoid persistence of contacts in manifold:
1062     resultOut->getPersistentManifold()->clearManifold();
1063 
1064     const btCEtriangleShape* triA = (btCEtriangleShape*)triObj1Wrap->getCollisionShape();
1065     const btCEtriangleShape* triB = (btCEtriangleShape*)triObj2Wrap->getCollisionShape();
1066     ChCollisionModelBullet* triModelA = (ChCollisionModelBullet*)triA->getUserPointer();
1067     ChCollisionModelBullet* triModelB = (ChCollisionModelBullet*)triB->getUserPointer();
1068 
1069     // brute force discard of connected triangles
1070     // ***TODO*** faster approach based on collision families that can bypass the
1071     // check at the broadphase level?
1072     if (triA->get_p1() == triB->get_p1() || triA->get_p1() == triB->get_p2() || triA->get_p1() == triB->get_p3())
1073         return;
1074     if (triA->get_p2() == triB->get_p1() || triA->get_p2() == triB->get_p2() || triA->get_p2() == triB->get_p3())
1075         return;
1076     if (triA->get_p3() == triB->get_p1() || triA->get_p3() == triB->get_p2() || triA->get_p3() == triB->get_p3())
1077         return;
1078 
1079     double max_allowed_dist =
1080         triModelA->GetEnvelope() + triModelB->GetEnvelope() + triA->sphereswept_r() + triB->sphereswept_r();
1081     double min_allowed_dist = -(triModelA->GetSafeMargin() + triModelB->GetSafeMargin());
1082 
1083     double offset_A = triA->sphereswept_r();
1084     double offset_B = triB->sphereswept_r();
1085 
1086     // Trick!! offset also by outward 'envelope' because during ReportContacts()
1087     // contact points are offset inward by envelope, to cope with GJK method.
1088     offset_A += triModelA->GetEnvelope();
1089     offset_B += triModelB->GetEnvelope();
1090 
1091     const btTransform& m44Ta = triObj1Wrap->getCollisionObject()->getWorldTransform();
1092     const btTransform& m44Tb = triObj2Wrap->getCollisionObject()->getWorldTransform();
1093     const btMatrix3x3& mbtRa = m44Ta.getBasis();
1094     const btMatrix3x3& mbtRb = m44Tb.getBasis();
1095     ChMatrix33<> mRa;
1096     mRa(0, 0) = mbtRa[0][0];
1097     mRa(0, 1) = mbtRa[0][1];
1098     mRa(0, 2) = mbtRa[0][2];
1099     mRa(1, 0) = mbtRa[1][0];
1100     mRa(1, 1) = mbtRa[1][1];
1101     mRa(1, 2) = mbtRa[1][2];
1102     mRa(2, 0) = mbtRa[2][0];
1103     mRa(2, 1) = mbtRa[2][1];
1104     mRa(2, 2) = mbtRa[2][2];
1105     ChVector<> mOa(m44Ta.getOrigin().x(), m44Ta.getOrigin().y(), m44Ta.getOrigin().z());
1106 
1107     ChMatrix33<> mRb;
1108     mRb(0, 0) = mbtRb[0][0];
1109     mRb(0, 1) = mbtRb[0][1];
1110     mRb(0, 2) = mbtRb[0][2];
1111     mRb(1, 0) = mbtRb[1][0];
1112     mRb(1, 1) = mbtRb[1][1];
1113     mRb(1, 2) = mbtRb[1][2];
1114     mRb(2, 0) = mbtRb[2][0];
1115     mRb(2, 1) = mbtRb[2][1];
1116     mRb(2, 2) = mbtRb[2][2];
1117     ChVector<> mOb(m44Tb.getOrigin().x(), m44Tb.getOrigin().y(), m44Tb.getOrigin().z());
1118 
1119     // transform points to absolute coords, since models might be roto-translated
1120     ChVector<> pA1 = mOa + mRa * (*triA->get_p1());
1121     ChVector<> pA2 = mOa + mRa * (*triA->get_p2());
1122     ChVector<> pA3 = mOa + mRa * (*triA->get_p3());
1123     ChVector<> pB1 = mOb + mRb * (*triB->get_p1());
1124     ChVector<> pB2 = mOb + mRb * (*triB->get_p2());
1125     ChVector<> pB3 = mOb + mRb * (*triB->get_p3());
1126 
1127     // edges
1128     ChVector<> eA1 = pA2 - pA1;
1129     ChVector<> eA2 = pA3 - pA2;
1130     ChVector<> eA3 = pA1 - pA3;
1131     ChVector<> eB1 = pB2 - pB1;
1132     ChVector<> eB2 = pB3 - pB2;
1133     ChVector<> eB3 = pB1 - pB3;
1134 
1135     // normals
1136     ChVector<> nA = Vcross(eA1, eA2).GetNormalized();
1137     ChVector<> nB = Vcross(eB1, eB2).GetNormalized();
1138 
1139     double min_dist = 1e20;
1140     ChVector<> candid_pA;
1141     ChVector<> candid_pB;
1142     double dist = 1e20;
1143     bool is_into;
1144     ChVector<> p_projected;
1145     double mu, mv;
1146 
1147     // Shortcut: if two degenerate 'skinny' triangles with points 2&3 coincident (ex. used to
1148     // represent chunks of beams) just do an edge-edge test (as capsule-capsule) and return:
1149     if ((pA2 == pA3) && (pB2 == pB3) && triA->owns_e1() && triB->owns_e1()) {
1150         ChVector<> cA, cB, D;
1151         if (utils::LineLineIntersect(pA1, pA2, pB1, pB2, &cA, &cB, &mu, &mv)) {
1152             D = cB - cA;
1153             dist = D.Length();
1154             if (dist < max_allowed_dist && dist > min_allowed_dist && mu > 0 && mu < 1 && mv > 0 && mv < 1) {
1155                 _add_contact(cA, cB, dist, resultOut, offset_A, offset_B);
1156                 resultOut->refreshContactPoints();
1157                 return;
1158             }
1159         }
1160     }
1161 
1162     // vertex-face tests:
1163 
1164     if (triA->owns_v1()) {
1165         dist = utils::PointTriangleDistance(pA1, pB1, pB2, pB3, mu, mv, is_into, p_projected);
1166         if (is_into) {
1167             if (dist < max_allowed_dist && dist > min_allowed_dist) {
1168                 _add_contact(pA1, p_projected, dist, resultOut, offset_A, offset_B);
1169             }
1170             if (dist < min_dist) {
1171                 min_dist = dist;
1172                 candid_pA = pA1;
1173                 candid_pB = p_projected;
1174             }
1175         }
1176     }
1177     if (triA->owns_v2()) {
1178         dist = utils::PointTriangleDistance(pA2, pB1, pB2, pB3, mu, mv, is_into, p_projected);
1179         if (is_into) {
1180             if (dist < max_allowed_dist && dist > min_allowed_dist) {
1181                 _add_contact(pA2, p_projected, dist, resultOut, offset_A, offset_B);
1182             }
1183             if (dist < min_dist) {
1184                 min_dist = dist;
1185                 candid_pA = pA2;
1186                 candid_pB = p_projected;
1187             }
1188         }
1189     }
1190     if (triA->owns_v3()) {
1191         dist = utils::PointTriangleDistance(pA3, pB1, pB2, pB3, mu, mv, is_into, p_projected);
1192         if (is_into) {
1193             if (dist < max_allowed_dist && dist > min_allowed_dist) {
1194                 _add_contact(pA3, p_projected, dist, resultOut, offset_A, offset_B);
1195             }
1196             if (dist < min_dist) {
1197                 min_dist = dist;
1198                 candid_pA = pA3;
1199                 candid_pB = p_projected;
1200             }
1201         }
1202     }
1203 
1204     if (triB->owns_v1()) {
1205         dist = utils::PointTriangleDistance(pB1, pA1, pA2, pA3, mu, mv, is_into, p_projected);
1206         if (is_into) {
1207             if (dist < max_allowed_dist && dist > min_allowed_dist) {
1208                 _add_contact(p_projected, pB1, dist, resultOut, offset_A, offset_B);
1209             }
1210             if (dist < min_dist) {
1211                 min_dist = dist;
1212                 candid_pB = pB1;
1213                 candid_pA = p_projected;
1214             }
1215         }
1216     }
1217     if (triB->owns_v2()) {
1218         dist = utils::PointTriangleDistance(pB2, pA1, pA2, pA3, mu, mv, is_into, p_projected);
1219         if (is_into) {
1220             if (dist < max_allowed_dist && dist > min_allowed_dist) {
1221                 _add_contact(p_projected, pB2, dist, resultOut, offset_A, offset_B);
1222             }
1223             if (dist < min_dist) {
1224                 min_dist = dist;
1225                 candid_pB = pB2;
1226                 candid_pA = p_projected;
1227             }
1228         }
1229     }
1230     if (triB->owns_v3()) {
1231         dist = utils::PointTriangleDistance(pB3, pA1, pA2, pA3, mu, mv, is_into, p_projected);
1232         if (is_into) {
1233             if (dist < max_allowed_dist && dist > min_allowed_dist) {
1234                 _add_contact(p_projected, pB3, dist, resultOut, offset_A, offset_B);
1235             }
1236             if (dist < min_dist) {
1237                 min_dist = dist;
1238                 candid_pB = pB3;
1239                 candid_pA = p_projected;
1240             }
1241         }
1242     }
1243     double beta_A1 = 0, beta_A2 = 0, beta_A3 = 0, beta_B1 = 0, beta_B2 = 0, beta_B3 = 0;  // defaults for free edge
1244     ChVector<> tA1, tA2, tA3, tB1, tB2, tB3;
1245     ChVector<> lA1, lA2, lA3, lB1, lB2, lB3;
1246 
1247     //  edges-edges tests
1248 
1249     if (triA->owns_e1()) {
1250         tA1 = Vcross(eA1, nA).GetNormalized();
1251         if (triA->get_e1())
1252             lA1 = (mOa + mRa * (*triA->get_e1())) - pA1;
1253         else
1254             lA1 = -tA1;
1255         beta_A1 = atan2(Vdot(lA1, tA1), Vdot(lA1, nA));
1256         if (beta_A1 < 0)
1257             beta_A1 += CH_C_2PI;
1258     }
1259     if (triA->owns_e2()) {
1260         tA2 = Vcross(eA2, nA).GetNormalized();
1261         if (triA->get_e2())
1262             lA2 = (mOa + mRa * (*triA->get_e2())) - pA2;
1263         else
1264             lA2 = -tA2;
1265         beta_A2 = atan2(Vdot(lA2, tA2), Vdot(lA2, nA));
1266         if (beta_A2 < 0)
1267             beta_A2 += CH_C_2PI;
1268     }
1269     if (triA->owns_e3()) {
1270         tA3 = Vcross(eA3, nA).GetNormalized();
1271         if (triA->get_e3())
1272             lA3 = (mOa + mRa * (*triA->get_e3())) - pA3;
1273         else
1274             lA3 = -tA3;
1275         beta_A3 = atan2(Vdot(lA3, tA3), Vdot(lA3, nA));
1276         if (beta_A3 < 0)
1277             beta_A3 += CH_C_2PI;
1278     }
1279     if (triB->owns_e1()) {
1280         tB1 = Vcross(eB1, nB).GetNormalized();
1281         if (triB->get_e1())
1282             lB1 = (mOb + mRb * (*triB->get_e1())) - pB1;
1283         else
1284             lB1 = -tB1;
1285         beta_B1 = atan2(Vdot(lB1, tB1), Vdot(lB1, nB));
1286         if (beta_B1 < 0)
1287             beta_B1 += CH_C_2PI;
1288     }
1289     if (triB->owns_e2()) {
1290         tB2 = Vcross(eB2, nB).GetNormalized();
1291         if (triB->get_e2())
1292             lB2 = (mOb + mRb * (*triB->get_e2())) - pB2;
1293         else
1294             lB2 = -tB2;
1295         beta_B2 = atan2(Vdot(lB2, tB2), Vdot(lB2, nB));
1296         if (beta_B2 < 0)
1297             beta_B2 += CH_C_2PI;
1298     }
1299     if (triB->owns_e3()) {
1300         tB3 = Vcross(eB3, nB).GetNormalized();
1301         if (triB->get_e3())
1302             lB3 = (mOb + mRb * (*triB->get_e3())) - pB3;
1303         else
1304             lB3 = -tB3;
1305         beta_B3 = atan2(Vdot(lB3, tB3), Vdot(lB3, nB));
1306         if (beta_B3 < 0)
1307             beta_B3 += CH_C_2PI;
1308     }
1309 
1310     ChVector<> cA, cB, D;
1311 
1312     double edge_tol = 1e-3;
1313     //  + edge_tol to discard flat edges with some tolerance:
1314     double beta_convex_limit = CH_C_PI_2 + edge_tol;
1315     //  +/- edge_tol to inflate arc of acceptance of edge vs edge, to cope with singular cases (ex. flat cube vs
1316     //  flat cube):
1317     double alpha_lo_limit = -edge_tol;
1318     double CH_C_PI_mtol = CH_C_PI - edge_tol;
1319     double CH_C_PI_2_ptol = CH_C_PI_2 + edge_tol;
1320 
1321     // edge A1 vs edge B1
1322     if (triA->owns_e1() && triB->owns_e1())
1323         if (beta_A1 > beta_convex_limit && beta_B1 > beta_convex_limit) {
1324             if (utils::LineLineIntersect(pA1, pA2, pB1, pB2, &cA, &cB, &mu, &mv)) {
1325                 D = cB - cA;
1326                 dist = D.Length();
1327                 if (dist < max_allowed_dist && dist > min_allowed_dist && mu > 0 && mu < 1 && mv > 0 && mv < 1) {
1328                     double alpha_A = atan2(Vdot(D, tA1), Vdot(D, nA));
1329                     double alpha_B = atan2(Vdot(-D, tB1), Vdot(-D, nB));
1330                     if (alpha_A < alpha_lo_limit)
1331                         alpha_A += CH_C_2PI;
1332                     if (alpha_B < alpha_lo_limit)
1333                         alpha_B += CH_C_2PI;
1334                     if ((alpha_A < beta_A1 - CH_C_PI_2_ptol) && (alpha_B < beta_B1 - CH_C_PI_2_ptol))
1335                         _add_contact(cA, cB, dist, resultOut, offset_A, offset_B);
1336                     else if (alpha_A > CH_C_PI_mtol && (alpha_A < beta_A1 + CH_C_PI_2) && alpha_B > CH_C_PI_mtol &&
1337                              (alpha_B < beta_B1 + CH_C_PI_2_ptol))
1338                         _add_contact(cA, cB, -dist, resultOut, offset_A, offset_B);
1339                 }
1340             }
1341         }
1342     // edge A1 vs edge B2
1343     if (triA->owns_e1() && triB->owns_e2())
1344         if (beta_A1 > beta_convex_limit && beta_B2 > beta_convex_limit) {
1345             if (utils::LineLineIntersect(pA1, pA2, pB2, pB3, &cA, &cB, &mu, &mv)) {
1346                 D = cB - cA;
1347                 dist = D.Length();
1348                 if (dist < max_allowed_dist && dist > min_allowed_dist && mu > 0 && mu < 1 && mv > 0 && mv < 1) {
1349                     D = cB - cA;
1350                     double alpha_A = atan2(Vdot(D, tA1), Vdot(D, nA));
1351                     double alpha_B = atan2(Vdot(-D, tB2), Vdot(-D, nB));
1352                     if (alpha_A < alpha_lo_limit)
1353                         alpha_A += CH_C_2PI;
1354                     if (alpha_B < alpha_lo_limit)
1355                         alpha_B += CH_C_2PI;
1356                     if ((alpha_A < beta_A1 - CH_C_PI_2_ptol) && (alpha_B < beta_B2 - CH_C_PI_2_ptol))
1357                         _add_contact(cA, cB, dist, resultOut, offset_A, offset_B);
1358                     else if (alpha_A > CH_C_PI_mtol && (alpha_A < beta_A1 + CH_C_PI_2) && alpha_B > CH_C_PI_mtol &&
1359                              (alpha_B < beta_B2 + CH_C_PI_2_ptol))
1360                         _add_contact(cA, cB, -dist, resultOut, offset_A, offset_B);
1361                 }
1362             }
1363         }
1364     // edge A1 vs edge B3
1365     if (triA->owns_e1() && triB->owns_e3())
1366         if (beta_A1 > beta_convex_limit && beta_B3 > beta_convex_limit) {
1367             if (utils::LineLineIntersect(pA1, pA2, pB3, pB1, &cA, &cB, &mu, &mv)) {
1368                 D = cB - cA;
1369                 dist = D.Length();
1370                 if (dist < max_allowed_dist && dist > min_allowed_dist && mu > 0 && mu < 1 && mv > 0 && mv < 1) {
1371                     D = cB - cA;
1372                     double alpha_A = atan2(Vdot(D, tA1), Vdot(D, nA));
1373                     double alpha_B = atan2(Vdot(-D, tB3), Vdot(-D, nB));
1374                     if (alpha_A < alpha_lo_limit)
1375                         alpha_A += CH_C_2PI;
1376                     if (alpha_B < alpha_lo_limit)
1377                         alpha_B += CH_C_2PI;
1378                     if ((alpha_A < beta_A1 - CH_C_PI_2_ptol) && (alpha_B < beta_B3 - CH_C_PI_2_ptol))
1379                         _add_contact(cA, cB, dist, resultOut, offset_A, offset_B);
1380                     else if (alpha_A > CH_C_PI_mtol && (alpha_A < beta_A1 + CH_C_PI_2) && alpha_B > CH_C_PI_mtol &&
1381                              (alpha_B < beta_B3 + CH_C_PI_2_ptol))
1382                         _add_contact(cA, cB, -dist, resultOut, offset_A, offset_B);
1383                 }
1384             }
1385         }
1386     // edge A2 vs edge B1
1387     if (triA->owns_e2() && triB->owns_e1())
1388         if (beta_A2 > beta_convex_limit && beta_B1 > beta_convex_limit) {
1389             if (utils::LineLineIntersect(pA2, pA3, pB1, pB2, &cA, &cB, &mu, &mv)) {
1390                 D = cB - cA;
1391                 dist = D.Length();
1392                 if (dist < max_allowed_dist && dist > min_allowed_dist && mu > 0 && mu < 1 && mv > 0 && mv < 1) {
1393                     D = cB - cA;
1394                     double alpha_A = atan2(Vdot(D, tA2), Vdot(D, nA));
1395                     double alpha_B = atan2(Vdot(-D, tB1), Vdot(-D, nB));
1396                     if (alpha_A < alpha_lo_limit)
1397                         alpha_A += CH_C_2PI;
1398                     if (alpha_B < alpha_lo_limit)
1399                         alpha_B += CH_C_2PI;
1400                     if ((alpha_A < beta_A2 - CH_C_PI_2_ptol) && (alpha_B < beta_B1 - CH_C_PI_2_ptol))
1401                         _add_contact(cA, cB, dist, resultOut, offset_A, offset_B);
1402                     else if (alpha_A > CH_C_PI_mtol && (alpha_A < beta_A2 + CH_C_PI_2) && alpha_B > CH_C_PI_mtol &&
1403                              (alpha_B < beta_B1 + CH_C_PI_2_ptol))
1404                         _add_contact(cA, cB, -dist, resultOut, offset_A, offset_B);
1405                 }
1406             }
1407         }
1408     // edge A2 vs edge B2
1409     if (triA->owns_e2() && triB->owns_e2())
1410         if (beta_A2 > beta_convex_limit && beta_B2 > beta_convex_limit) {
1411             if (utils::LineLineIntersect(pA2, pA3, pB2, pB3, &cA, &cB, &mu, &mv)) {
1412                 D = cB - cA;
1413                 dist = D.Length();
1414                 if (dist < max_allowed_dist && dist > min_allowed_dist && mu > 0 && mu < 1 && mv > 0 && mv < 1) {
1415                     D = cB - cA;
1416                     double alpha_A = atan2(Vdot(D, tA2), Vdot(D, nA));
1417                     double alpha_B = atan2(Vdot(-D, tB2), Vdot(-D, nB));
1418                     if (alpha_A < alpha_lo_limit)
1419                         alpha_A += CH_C_2PI;
1420                     if (alpha_B < alpha_lo_limit)
1421                         alpha_B += CH_C_2PI;
1422                     if ((alpha_A < beta_A2 - CH_C_PI_2_ptol) && (alpha_B < beta_B2 - CH_C_PI_2_ptol))
1423                         _add_contact(cA, cB, dist, resultOut, offset_A, offset_B);
1424                     else if (alpha_A > CH_C_PI_mtol && (alpha_A < beta_A2 + CH_C_PI_2) && alpha_B > CH_C_PI_mtol &&
1425                              (alpha_B < beta_B2 + CH_C_PI_2_ptol))
1426                         _add_contact(cA, cB, -dist, resultOut, offset_A, offset_B);
1427                 }
1428             }
1429         }
1430     // edge A2 vs edge B3
1431     if (triA->owns_e2() && triB->owns_e3())
1432         if (beta_A2 > beta_convex_limit && beta_B3 > beta_convex_limit) {
1433             if (utils::LineLineIntersect(pA2, pA3, pB3, pB1, &cA, &cB, &mu, &mv)) {
1434                 D = cB - cA;
1435                 dist = D.Length();
1436                 if (dist < max_allowed_dist && dist > min_allowed_dist && mu > 0 && mu < 1 && mv > 0 && mv < 1) {
1437                     D = cB - cA;
1438                     double alpha_A = atan2(Vdot(D, tA2), Vdot(D, nA));
1439                     double alpha_B = atan2(Vdot(-D, tB3), Vdot(-D, nB));
1440                     if (alpha_A < alpha_lo_limit)
1441                         alpha_A += CH_C_2PI;
1442                     if (alpha_B < alpha_lo_limit)
1443                         alpha_B += CH_C_2PI;
1444                     if ((alpha_A < beta_A2 - CH_C_PI_2_ptol) && (alpha_B < beta_B3 - CH_C_PI_2_ptol))
1445                         _add_contact(cA, cB, dist, resultOut, offset_A, offset_B);
1446                     else if (alpha_A > CH_C_PI_mtol && (alpha_A < beta_A2 + CH_C_PI_2) && alpha_B > CH_C_PI_mtol &&
1447                              (alpha_B < beta_B3 + CH_C_PI_2_ptol))
1448                         _add_contact(cA, cB, -dist, resultOut, offset_A, offset_B);
1449                 }
1450             }
1451         }
1452     // edge A3 vs edge B1
1453     if (triA->owns_e3() && triB->owns_e1())
1454         if (beta_A3 > beta_convex_limit && beta_B1 > beta_convex_limit) {
1455             if (utils::LineLineIntersect(pA3, pA1, pB1, pB2, &cA, &cB, &mu, &mv)) {
1456                 D = cB - cA;
1457                 dist = D.Length();
1458                 if (dist < max_allowed_dist && dist > min_allowed_dist && mu > 0 && mu < 1 && mv > 0 && mv < 1) {
1459                     D = cB - cA;
1460                     double alpha_A = atan2(Vdot(D, tA3), Vdot(D, nA));
1461                     double alpha_B = atan2(Vdot(-D, tB1), Vdot(-D, nB));
1462                     if (alpha_A < alpha_lo_limit)
1463                         alpha_A += CH_C_2PI;
1464                     if (alpha_B < alpha_lo_limit)
1465                         alpha_B += CH_C_2PI;
1466                     if ((alpha_A < beta_A3 - CH_C_PI_2_ptol) && (alpha_B < beta_B1 - CH_C_PI_2_ptol))
1467                         _add_contact(cA, cB, dist, resultOut, offset_A, offset_B);
1468                     else if (alpha_A > CH_C_PI_mtol && (alpha_A < beta_A3 + CH_C_PI_2) && alpha_B > CH_C_PI_mtol &&
1469                              (alpha_B < beta_B1 + CH_C_PI_2_ptol))
1470                         _add_contact(cA, cB, -dist, resultOut, offset_A, offset_B);
1471                 }
1472             }
1473         }
1474     // edge A3 vs edge B2
1475     if (triA->owns_e3() && triB->owns_e2())
1476         if (beta_A3 > beta_convex_limit && beta_B2 > beta_convex_limit) {
1477             if (utils::LineLineIntersect(pA3, pA1, pB2, pB3, &cA, &cB, &mu, &mv)) {
1478                 D = cB - cA;
1479                 dist = D.Length();
1480                 if (dist < max_allowed_dist && dist > min_allowed_dist && mu > 0 && mu < 1 && mv > 0 && mv < 1) {
1481                     D = cB - cA;
1482                     double alpha_A = atan2(Vdot(D, tA3), Vdot(D, nA));
1483                     double alpha_B = atan2(Vdot(-D, tB2), Vdot(-D, nB));
1484                     if (alpha_A < alpha_lo_limit)
1485                         alpha_A += CH_C_2PI;
1486                     if (alpha_B < alpha_lo_limit)
1487                         alpha_B += CH_C_2PI;
1488                     if ((alpha_A < beta_A3 - CH_C_PI_2_ptol) && (alpha_B < beta_B2 - CH_C_PI_2_ptol))
1489                         _add_contact(cA, cB, dist, resultOut, offset_A, offset_B);
1490                     else if (alpha_A > CH_C_PI_mtol && (alpha_A < beta_A3 + CH_C_PI_2) && alpha_B > CH_C_PI_mtol &&
1491                              (alpha_B < beta_B2 + CH_C_PI_2_ptol))
1492                         _add_contact(cA, cB, -dist, resultOut, offset_A, offset_B);
1493                 }
1494             }
1495         }
1496     // edge A3 vs edge B3
1497     if (triA->owns_e3() && triB->owns_e3())
1498         if (beta_A3 > beta_convex_limit && beta_B3 > beta_convex_limit) {
1499             if (utils::LineLineIntersect(pA3, pA1, pB3, pB1, &cA, &cB, &mu, &mv)) {
1500                 D = cB - cA;
1501                 dist = D.Length();
1502                 if (dist < max_allowed_dist && dist > min_allowed_dist && mu > 0 && mu < 1 && mv > 0 && mv < 1) {
1503                     D = cB - cA;
1504                     double alpha_A = atan2(Vdot(D, tA3), Vdot(D, nA));
1505                     double alpha_B = atan2(Vdot(-D, tB3), Vdot(-D, nB));
1506                     if (alpha_A < alpha_lo_limit)
1507                         alpha_A += CH_C_2PI;
1508                     if (alpha_B < alpha_lo_limit)
1509                         alpha_B += CH_C_2PI;
1510                     if ((alpha_A < beta_A3 - CH_C_PI_2_ptol) && (alpha_B < beta_B3 - CH_C_PI_2_ptol))
1511                         _add_contact(cA, cB, dist, resultOut, offset_A, offset_B);
1512                     else if (alpha_A > CH_C_PI_mtol && (alpha_A < beta_A3 + CH_C_PI_2) && alpha_B > CH_C_PI_mtol &&
1513                              (alpha_B < beta_B3 + CH_C_PI_2_ptol))
1514                         _add_contact(cA, cB, -dist, resultOut, offset_A, offset_B);
1515                 }
1516             }
1517         }
1518 
1519     resultOut->refreshContactPoints();
1520 }
1521 
calculateTimeOfImpact(btCollisionObject * body0,btCollisionObject * body1,const btDispatcherInfo & dispatchInfo,btManifoldResult * resultOut)1522 btScalar btCEtriangleShapeCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* body0,
1523                                                                     btCollisionObject* body1,
1524                                                                     const btDispatcherInfo& dispatchInfo,
1525                                                                     btManifoldResult* resultOut) {
1526     // not yet
1527     return btScalar(1.);
1528 }
1529 
getAllContactManifolds(btManifoldArray & manifoldArray)1530 void btCEtriangleShapeCollisionAlgorithm::getAllContactManifolds(btManifoldArray& manifoldArray) {
1531     if (m_manifoldPtr && m_ownManifold) {
1532         manifoldArray.push_back(m_manifoldPtr);
1533     }
1534 }
1535 
_add_contact(const ChVector<> & candid_pA,const ChVector<> & candid_pB,const double dist,btManifoldResult * resultOut,const double offsetA,const double offsetB)1536 void btCEtriangleShapeCollisionAlgorithm::_add_contact(const ChVector<>& candid_pA,
1537                                                        const ChVector<>& candid_pB,
1538                                                        const double dist,
1539                                                        btManifoldResult* resultOut,
1540                                                        const double offsetA,
1541                                                        const double offsetB) {
1542     // convert to Bullet vectors. Note: in absolute csys.
1543     btVector3 absA((btScalar)candid_pA.x(), (btScalar)candid_pA.y(), (btScalar)candid_pA.z());
1544     btVector3 absB((btScalar)candid_pB.x(), (btScalar)candid_pB.y(), (btScalar)candid_pB.z());
1545     ChVector<> dabsN_onB((candid_pA - candid_pB).GetNormalized());
1546     btVector3 absN_onB((btScalar)dabsN_onB.x(), (btScalar)dabsN_onB.y(), (btScalar)dabsN_onB.z());
1547     if (dist < 0)
1548         absN_onB = -absN_onB;  // flip norm to be coherent with dist sign
1549     resultOut->addContactPoint(absN_onB, absB + absN_onB * (btScalar)offsetB, (btScalar)(dist - (offsetA + offsetB)));
1550 }
1551 
CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo & ci,const btCollisionObjectWrapper * body0Wrap,const btCollisionObjectWrapper * body1Wrap)1552 btCollisionAlgorithm* btCEtriangleShapeCollisionAlgorithm::CreateFunc::CreateCollisionAlgorithm(
1553     btCollisionAlgorithmConstructionInfo& ci,
1554     const btCollisionObjectWrapper* body0Wrap,
1555     const btCollisionObjectWrapper* body1Wrap) {
1556     void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btCEtriangleShapeCollisionAlgorithm));
1557     if (!m_swapped) {
1558         return new (mem) btCEtriangleShapeCollisionAlgorithm(0, ci, body0Wrap, body1Wrap, false);
1559     } else {
1560         return new (mem) btCEtriangleShapeCollisionAlgorithm(0, ci, body0Wrap, body1Wrap, true);
1561     }
1562 }
1563 
1564 }  // namespace collision
1565 }  // namespace chrono
1566