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