Cosmetic: Cosmetic code corrections in QuickStep
[ode.git] / ode / src / convex.cpp
blob7a179412c00b01fb85b285ed7e092d7c0c59c84f
1 /*************************************************************************
2 * *
3 * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. *
4 * All rights reserved. Email: russ@q12.org Web: www.q12.org *
5 * *
6 * This library is free software; you can redistribute it and/or *
7 * modify it under the terms of EITHER: *
8 * (1) The GNU Lesser General Public License as published by the Free *
9 * Software Foundation; either version 2.1 of the License, or (at *
10 * your option) any later version. The text of the GNU Lesser *
11 * General Public License is included with this library in the *
12 * file LICENSE.TXT. *
13 * (2) The BSD-style license that is included with this library in *
14 * the file LICENSE-BSD.TXT. *
15 * *
16 * This library is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
19 * LICENSE.TXT and LICENSE-BSD.TXT for more details. *
20 * *
21 *************************************************************************/
23 Code for Convex Collision Detection
24 By Rodrigo Hernandez
26 #include <ode/common.h>
27 #include <ode/collision.h>
28 #include <ode/rotation.h>
29 #include "config.h"
30 #include "matrix.h"
31 #include "odemath.h"
32 #include "collision_kernel.h"
33 #include "collision_std.h"
34 #include "collision_util.h"
36 #ifdef _MSC_VER
37 #pragma warning(disable:4291) // for VC++, no complaints about "no matching operator delete found"
38 #endif
40 #if 1
41 #define dMIN(A,B) ((A)>(B) ? (B) : (A))
42 #define dMAX(A,B) ((A)>(B) ? (A) : (B))
43 #else
44 #define dMIN(A,B) std::min(A,B)
45 #define dMAX(A,B) std::max(A,B)
46 #endif
48 //****************************************************************************
49 // Convex public API
50 dxConvex::dxConvex (dSpaceID space,
51 const dReal *_planes,
52 unsigned int _planecount,
53 const dReal *_points,
54 unsigned int _pointcount,
55 const unsigned int *_polygons) :
56 dxGeom (space,1)
58 dAASSERT (_planes != NULL);
59 dAASSERT (_points != NULL);
60 dAASSERT (_polygons != NULL);
61 //fprintf(stdout,"dxConvex Constructor planes %X\n",_planes);
62 type = dConvexClass;
63 planes = _planes;
64 planecount = _planecount;
65 // we need points as well
66 points = _points;
67 pointcount = _pointcount;
68 polygons=_polygons;
69 edges = NULL;
70 FillEdges();
71 #ifndef dNODEBUG
72 // Check for properly build polygons by calculating the determinant
73 // of the 3x3 matrix composed of the first 3 points in the polygon.
74 const unsigned int *points_in_poly=polygons;
75 const unsigned int *index=polygons+1;
77 for(unsigned int i=0;i<planecount;++i)
79 dAASSERT (*points_in_poly > 2 );
80 if((
81 points[(index[0]*3)+0]*points[(index[1]*3)+1]*points[(index[2]*3)+2] +
82 points[(index[0]*3)+1]*points[(index[1]*3)+2]*points[(index[2]*3)+0] +
83 points[(index[0]*3)+2]*points[(index[1]*3)+0]*points[(index[2]*3)+1] -
84 points[(index[0]*3)+2]*points[(index[1]*3)+1]*points[(index[2]*3)+0] -
85 points[(index[0]*3)+1]*points[(index[1]*3)+0]*points[(index[2]*3)+2] -
86 points[(index[0]*3)+0]*points[(index[1]*3)+2]*points[(index[2]*3)+1])<0)
88 fprintf(stdout,"WARNING: Polygon %d is not defined counterclockwise\n",i);
90 points_in_poly+=(*points_in_poly+1);
91 index=points_in_poly+1;
92 if(planes[(i*4)+3]<0) fprintf(stdout,"WARNING: Plane %d does not contain the origin\n",i);
94 #endif
96 //CreateTree();
100 void dxConvex::computeAABB()
102 // this can, and should be optimized
103 dVector3 point;
104 dMultiply0_331 (point,final_posr->R,points);
105 aabb[0] = point[0]+final_posr->pos[0];
106 aabb[1] = point[0]+final_posr->pos[0];
107 aabb[2] = point[1]+final_posr->pos[1];
108 aabb[3] = point[1]+final_posr->pos[1];
109 aabb[4] = point[2]+final_posr->pos[2];
110 aabb[5] = point[2]+final_posr->pos[2];
111 for(unsigned int i=3;i<(pointcount*3);i+=3)
113 dMultiply0_331 (point,final_posr->R,&points[i]);
114 aabb[0] = dMIN(aabb[0],point[0]+final_posr->pos[0]);
115 aabb[1] = dMAX(aabb[1],point[0]+final_posr->pos[0]);
116 aabb[2] = dMIN(aabb[2],point[1]+final_posr->pos[1]);
117 aabb[3] = dMAX(aabb[3],point[1]+final_posr->pos[1]);
118 aabb[4] = dMIN(aabb[4],point[2]+final_posr->pos[2]);
119 aabb[5] = dMAX(aabb[5],point[2]+final_posr->pos[2]);
123 /*! \brief Populates the edges set, should be called only once whenever the polygon array gets updated */
124 void dxConvex::FillEdges()
126 const unsigned int *points_in_poly=polygons;
127 const unsigned int *index=polygons+1;
128 if (edges!=NULL) delete[] edges;
129 edgecount = 0;
130 edge e;
131 bool isinset;
132 for(unsigned int i=0;i<planecount;++i)
134 for(unsigned int j=0;j<*points_in_poly;++j)
136 e.first = dMIN(index[j],index[(j+1)%*points_in_poly]);
137 e.second = dMAX(index[j],index[(j+1)%*points_in_poly]);
138 isinset=false;
139 for(unsigned int k=0;k<edgecount;++k)
141 if((edges[k].first==e.first)&&(edges[k].second==e.second))
143 isinset=true;
144 break;
147 if(!isinset)
149 edge* tmp = new edge[edgecount+1];
150 if(edgecount!=0)
152 memcpy(tmp,edges,(edgecount)*sizeof(edge));
153 delete[] edges;
155 tmp[edgecount].first=e.first;
156 tmp[edgecount].second=e.second;
157 edges = tmp;
158 ++edgecount;
161 points_in_poly+=(*points_in_poly+1);
162 index=points_in_poly+1;
165 #if 0
166 dxConvex::BSPNode* dxConvex::CreateNode(std::vector<Arc> Arcs,std::vector<Polygon> Polygons)
168 #if 0
169 dVector3 ea,eb,e;
170 dVector3Copy(points+((edges.begin()+Arcs[0].edge)first*3),ea);
171 dMultiply0_331(e1b,cvx1.final_posr->R,cvx1.points+(i->second*3));
173 dVector3Copy(points[edges[Arcs[0].edge]
174 #endif
175 return NULL;
178 void dxConvex::CreateTree()
180 std::vector<Arc> A;
181 A.reserve(edgecount);
182 for(unsigned int i=0;i<edgecount;++i)
184 this->GetFacesSharedByEdge(i,A[i].normals);
185 A[i].edge = i;
187 std::vector<Polygon> S;
188 S.reserve(pointcount);
189 for(unsigned int i=0;i<pointcount;++i)
191 this->GetFacesSharedByVertex(i,S[i].normals);
192 S[i].vertex=i;
194 this->tree = CreateNode(A,S);
197 void dxConvex::GetFacesSharedByVertex(int i, std::vector<int> f)
200 void dxConvex::GetFacesSharedByEdge(int i, int* f)
203 void dxConvex::GetFaceNormal(int i, dVector3 normal)
206 #endif
208 dGeomID dCreateConvex (dSpaceID space,const dReal *_planes,unsigned int _planecount,
209 const dReal *_points,
210 unsigned int _pointcount,
211 const unsigned int *_polygons)
213 //fprintf(stdout,"dxConvex dCreateConvex\n");
214 return new dxConvex(space,_planes, _planecount,
215 _points,
216 _pointcount,
217 _polygons);
220 void dGeomSetConvex (dGeomID g,const dReal *_planes,unsigned int _planecount,
221 const dReal *_points,
222 unsigned int _pointcount,
223 const unsigned int *_polygons)
225 //fprintf(stdout,"dxConvex dGeomSetConvex\n");
226 dUASSERT (g && g->type == dConvexClass,"argument not a convex shape");
227 dxConvex *s = (dxConvex*) g;
228 s->planes = _planes;
229 s->planecount = _planecount;
230 s->points = _points;
231 s->pointcount = _pointcount;
232 s->polygons=_polygons;
235 //****************************************************************************
236 // Helper Inlines
239 /*! \brief Returns Whether or not the segment ab intersects plane p
240 \param a origin of the segment
241 \param b segment destination
242 \param p plane to test for intersection
243 \param t returns the time "t" in the segment ray that gives us the intersecting
244 point
245 \param q returns the intersection point
246 \return true if there is an intersection, otherwise false.
248 bool IntersectSegmentPlane(dVector3 a,
249 dVector3 b,
250 dVector4 p,
251 dReal &t,
252 dVector3 q)
254 // Compute the t value for the directed line ab intersecting the plane
255 dVector3 ab;
256 ab[0]= b[0] - a[0];
257 ab[1]= b[1] - a[1];
258 ab[2]= b[2] - a[2];
260 t = (p[3] - dCalcVectorDot3(p,a)) / dCalcVectorDot3(p,ab);
262 // If t in [0..1] compute and return intersection point
263 if (t >= 0.0 && t <= 1.0)
265 q[0] = a[0] + t * ab[0];
266 q[1] = a[1] + t * ab[1];
267 q[2] = a[2] + t * ab[2];
268 return true;
270 // Else no intersection
271 return false;
274 /*! \brief Returns the Closest Point in Ray 1 to Ray 2
275 \param Origin1 The origin of Ray 1
276 \param Direction1 The direction of Ray 1
277 \param Origin1 The origin of Ray 2
278 \param Direction1 The direction of Ray 3
279 \param t the time "t" in Ray 1 that gives us the closest point
280 (closest_point=Origin1+(Direction1*t).
281 \return true if there is a closest point, false if the rays are paralell.
283 inline bool ClosestPointInRay(const dVector3 Origin1,
284 const dVector3 Direction1,
285 const dVector3 Origin2,
286 const dVector3 Direction2,
287 dReal& t)
289 dVector3 w = {Origin1[0]-Origin2[0],
290 Origin1[1]-Origin2[1],
291 Origin1[2]-Origin2[2]};
292 dReal a = dCalcVectorDot3(Direction1 , Direction1);
293 dReal b = dCalcVectorDot3(Direction1 , Direction2);
294 dReal c = dCalcVectorDot3(Direction2 , Direction2);
295 dReal d = dCalcVectorDot3(Direction1 , w);
296 dReal e = dCalcVectorDot3(Direction2 , w);
297 dReal denominator = (a*c)-(b*b);
298 if(denominator==0.0f)
300 return false;
302 t = ((a*e)-(b*d))/denominator;
303 return true;
306 /*! \brief Returns the Closest Points from Segment 1 to Segment 2
307 \param p1 start of segment 1
308 \param q1 end of segment 1
309 \param p2 start of segment 2
310 \param q2 end of segment 2
311 \param t the time "t" in Ray 1 that gives us the closest point
312 (closest_point=Origin1+(Direction1*t).
313 \return true if there is a closest point, false if the rays are paralell.
314 \note Adapted from Christer Ericson's Real Time Collision Detection Book.
316 inline void ClosestPointBetweenSegments(dVector3& p1,
317 dVector3& q1,
318 dVector3& p2,
319 dVector3& q2,
320 dVector3& c1,
321 dVector3& c2)
323 // s & t were originaly part of the output args, but since
324 // we don't really need them, we'll just declare them in here
325 dReal s;
326 dReal t;
327 dVector3 d1 = {q1[0] - p1[0],
328 q1[1] - p1[1],
329 q1[2] - p1[2]};
330 dVector3 d2 = {q2[0] - p2[0],
331 q2[1] - p2[1],
332 q2[2] - p2[2]};
333 dVector3 r = {p1[0] - p2[0],
334 p1[1] - p2[1],
335 p1[2] - p2[2]};
336 dReal a = dCalcVectorDot3(d1, d1);
337 dReal e = dCalcVectorDot3(d2, d2);
338 dReal f = dCalcVectorDot3(d2, r);
339 // Check if either or both segments degenerate into points
340 if (a <= dEpsilon && e <= dEpsilon)
342 // Both segments degenerate into points
343 s = t = 0.0f;
344 dVector3Copy(p1,c1);
345 dVector3Copy(p2,c2);
346 return;
348 if (a <= dEpsilon)
350 // First segment degenerates into a point
351 s = 0.0f;
352 t = f / e; // s = 0 => t = (b*s + f) / e = f / e
353 t = dxClamp(t, 0.0f, 1.0f);
355 else
357 dReal c = dCalcVectorDot3(d1, r);
358 if (e <= dEpsilon)
360 // Second segment degenerates into a point
361 t = 0.0f;
362 s = dxClamp(-c / a, 0.0f, 1.0f); // t = 0 => s = (b*t - c) / a = -c / a
364 else
366 // The general non degenerate case starts here
367 dReal b = dCalcVectorDot3(d1, d2);
368 dReal denom = a*e-b*b; // Always nonnegative
370 // If segments not parallel, compute closest point on L1 to L2, and
371 // clamp to segment S1. Else pick arbitrary s (here 0)
372 if (denom != 0.0f)
374 s = dxClamp((b*f - c*e) / denom, 0.0f, 1.0f);
376 else s = 0.0f;
377 #if 0
378 // Compute point on L2 closest to S1(s) using
379 // t = Dot((P1+D1*s)-P2,D2) / Dot(D2,D2) = (b*s + f) / e
380 t = (b*s + f) / e;
382 // If t in [0,1] done. Else clamp t, recompute s for the new value
383 // of t using s = Dot((P2+D2*t)-P1,D1) / Dot(D1,D1)= (t*b - c) / a
384 // and clamp s to [0, 1]
385 if (t < 0.0f) {
386 t = 0.0f;
387 s = dxClamp(-c / a, 0.0f, 1.0f);
388 } else if (t > 1.0f) {
389 t = 1.0f;
390 s = dxClamp((b - c) / a, 0.0f, 1.0f);
392 #else
393 dReal tnom = b*s + f;
394 if (tnom < 0.0f)
396 t = 0.0f;
397 s = dxClamp(-c / a, 0.0f, 1.0f);
399 else if (tnom > e)
401 t = 1.0f;
402 s = dxClamp((b - c) / a, 0.0f, 1.0f);
404 else
406 t = tnom / e;
408 #endif
412 c1[0] = p1[0] + d1[0] * s;
413 c1[1] = p1[1] + d1[1] * s;
414 c1[2] = p1[2] + d1[2] * s;
415 c2[0] = p2[0] + d2[0] * t;
416 c2[1] = p2[1] + d2[1] * t;
417 c2[2] = p2[2] + d2[2] * t;
420 #if 0
421 dReal tnom = b*s + f;
422 if (tnom < 0.0f) {
423 t = 0.0f;
424 s = dxClamp(-c / a, 0.0f, 1.0f);
425 } else if (tnom > e) {
426 t = 1.0f;
427 s = dxClamp((b - c) / a, 0.0f, 1.0f);
428 } else {
429 t = tnom / e;
431 #endif
433 /*! \brief Returns the Ray on which 2 planes intersect if they do.
434 \param p1 Plane 1
435 \param p2 Plane 2
436 \param p Contains the origin of the ray upon returning if planes intersect
437 \param d Contains the direction of the ray upon returning if planes intersect
438 \return true if the planes intersect, false if paralell.
440 inline bool IntersectPlanes(const dVector4 p1, const dVector4 p2, dVector3 p, dVector3 d)
442 // Compute direction of intersection line
443 dCalcVectorCross3(d,p1,p2);
444 // If d is (near) zero, the planes are parallel (and separated)
445 // or coincident, so they're not considered intersecting
446 dReal denom = dCalcVectorDot3(d, d);
447 if (denom < dEpsilon) return false;
448 dVector3 n;
449 n[0]=p1[3]*p2[0] - p2[3]*p1[0];
450 n[1]=p1[3]*p2[1] - p2[3]*p1[1];
451 n[2]=p1[3]*p2[2] - p2[3]*p1[2];
452 // Compute point on intersection line
453 dCalcVectorCross3(p,n,d);
454 p[0]/=denom;
455 p[1]/=denom;
456 p[2]/=denom;
457 return true;
461 #if 0
462 /*! \brief Finds out if a point lies inside a convex
463 \param p Point to test
464 \param convex a pointer to convex to test against
465 \return true if the point lies inside the convex, false if not.
467 inline bool IsPointInConvex(dVector3 p,
468 dxConvex *convex)
470 dVector3 lp,tmp;
471 // move point into convex space to avoid plane local to world calculations
472 tmp[0] = p[0] - convex->final_posr->pos[0];
473 tmp[1] = p[1] - convex->final_posr->pos[1];
474 tmp[2] = p[2] - convex->final_posr->pos[2];
475 dMultiply1_331 (lp,convex->final_posr->R,tmp);
476 for(unsigned int i=0;i<convex->planecount;++i)
478 if((
479 ((convex->planes+(i*4))[0]*lp[0])+
480 ((convex->planes+(i*4))[1]*lp[1])+
481 ((convex->planes+(i*4))[2]*lp[2])+
482 -(convex->planes+(i*4))[3]
483 )>0)
485 return false;
488 return true;
490 #endif
492 /*! \brief Finds out if a point lies inside a 2D polygon
493 \param p Point to test
494 \param polygon a pointer to the start of the convex polygon index buffer
495 \param out the closest point in the polygon if the point is not inside
496 \return true if the point lies inside of the polygon, false if not.
498 inline bool IsPointInPolygon(dVector3 p,
499 const unsigned int *polygon,
500 dReal *plane,
501 dxConvex *convex,
502 dVector3 out)
504 // p is the point we want to check,
505 // polygon is a pointer to the polygon we
506 // are checking against, remember it goes
507 // number of vertices then that many indexes
508 // out returns the closest point on the border of the
509 // polygon if the point is not inside it.
510 dVector3 a;
511 dVector3 b;
512 dVector3 ab;
513 dVector3 ap;
514 dVector3 v;
516 unsigned pointcount=polygon[0];
517 dIASSERT(pointcount != 0);
518 polygon++; // skip past pointcount
520 dMultiply0_331 (b,convex->final_posr->R,
521 &convex->points[(polygon[pointcount-1]*3)]);
522 b[0]=convex->final_posr->pos[0]+b[0];
523 b[1]=convex->final_posr->pos[1]+b[1];
524 b[2]=convex->final_posr->pos[2]+b[2];
526 for(unsigned i=0; i != pointcount; ++i)
528 a[0] = b[0];
529 a[1] = b[1];
530 a[2] = b[2];
532 dMultiply0_331 (b,convex->final_posr->R,&convex->points[(polygon[i]*3)]);
533 b[0]=convex->final_posr->pos[0]+b[0];
534 b[1]=convex->final_posr->pos[1]+b[1];
535 b[2]=convex->final_posr->pos[2]+b[2];
537 ab[0] = b[0] - a[0];
538 ab[1] = b[1] - a[1];
539 ab[2] = b[2] - a[2];
540 ap[0] = p[0] - a[0];
541 ap[1] = p[1] - a[1];
542 ap[2] = p[2] - a[2];
544 dCalcVectorCross3(v, ab, plane);
546 if (dCalcVectorDot3(ap, v) > REAL(0.0))
548 dReal ab_m2 = dCalcVectorDot3(ab, ab);
549 dReal s = ab_m2 != REAL(0.0) ? dCalcVectorDot3(ab, ap) / ab_m2 : REAL(0.0);
551 if (s <= REAL(0.0))
553 out[0] = a[0];
554 out[1] = a[1];
555 out[2] = a[2];
557 else if (s >= REAL(1.0))
559 out[0] = b[0];
560 out[1] = b[1];
561 out[2] = b[2];
563 else
565 out[0] = a[0] + ab[0] * s;
566 out[1] = a[1] + ab[1] * s;
567 out[2] = a[2] + ab[2] * s;
570 return false;
574 return true;
577 int dCollideConvexPlane (dxGeom *o1, dxGeom *o2, int flags,
578 dContactGeom *contact, int skip)
580 dIASSERT (skip >= (int)sizeof(dContactGeom));
581 dIASSERT (o1->type == dConvexClass);
582 dIASSERT (o2->type == dPlaneClass);
583 dIASSERT ((flags & NUMC_MASK) >= 1);
585 dxConvex *Convex = (dxConvex*) o1;
586 dxPlane *Plane = (dxPlane*) o2;
587 unsigned int contacts=0;
588 unsigned int maxc = flags & NUMC_MASK;
589 dVector3 v2;
591 #define LTEQ_ZERO 0x10000000
592 #define GTEQ_ZERO 0x20000000
593 #define BOTH_SIGNS (LTEQ_ZERO | GTEQ_ZERO)
594 dIASSERT((BOTH_SIGNS & NUMC_MASK) == 0); // used in conditional operator later
596 unsigned int totalsign = 0;
597 for(unsigned int i=0;i<Convex->pointcount;++i)
599 dMultiply0_331 (v2,Convex->final_posr->R,&Convex->points[(i*3)]);
600 dVector3Add(Convex->final_posr->pos, v2, v2);
602 unsigned int distance2sign = GTEQ_ZERO;
603 dReal distance2 = dVector3Dot(Plane->p, v2) - Plane->p[3]; // Ax + By + Cz - D
604 if((distance2 <= REAL(0.0)))
606 distance2sign = distance2 != REAL(0.0) ? LTEQ_ZERO : BOTH_SIGNS;
608 if (contacts != maxc)
610 dContactGeom *target = SAFECONTACT(flags, contact, contacts, skip);
611 dVector3Copy(Plane->p, target->normal);
612 dVector3Copy(v2, target->pos);
613 target->depth = -distance2;
614 target->g1 = Convex;
615 target->g2 = Plane;
616 target->side1 = -1; // TODO: set plane index?
617 target->side2 = -1;
618 contacts++;
622 // Take new sign into account
623 totalsign |= distance2sign;
624 // Check if contacts are full and both signs have been already found
625 if (((contacts ^ maxc) | totalsign) == BOTH_SIGNS) // harder to comprehend but requires one register less
627 break; // Nothing can be changed any more
630 if (totalsign == BOTH_SIGNS) return contacts;
631 return 0;
632 #undef BOTH_SIGNS
633 #undef GTEQ_ZERO
634 #undef LTEQ_ZERO
637 int dCollideSphereConvex (dxGeom *o1, dxGeom *o2, int flags,
638 dContactGeom *contact, int skip)
640 dIASSERT (skip >= (int)sizeof(dContactGeom));
641 dIASSERT (o1->type == dSphereClass);
642 dIASSERT (o2->type == dConvexClass);
643 dIASSERT ((flags & NUMC_MASK) >= 1);
645 dxSphere *Sphere = (dxSphere*) o1;
646 dxConvex *Convex = (dxConvex*) o2;
647 dReal dist,closestdist=dInfinity;
648 dVector4 plane;
649 // dVector3 contactpoint;
650 dVector3 offsetpos,out,temp;
651 const unsigned int *pPoly=Convex->polygons;
652 int closestplane=-1;
653 bool sphereinside=true;
655 Do a good old sphere vs plane check first,
656 if a collision is found then check if the contact point
657 is within the polygon
659 // offset the sphere final_posr->position into the convex space
660 offsetpos[0]=Sphere->final_posr->pos[0]-Convex->final_posr->pos[0];
661 offsetpos[1]=Sphere->final_posr->pos[1]-Convex->final_posr->pos[1];
662 offsetpos[2]=Sphere->final_posr->pos[2]-Convex->final_posr->pos[2];
663 for(unsigned int i=0;i<Convex->planecount;++i)
665 // apply rotation to the plane
666 dMultiply0_331(plane,Convex->final_posr->R,&Convex->planes[(i*4)]);
667 plane[3]=(&Convex->planes[(i*4)])[3];
668 // Get the distance from the sphere origin to the plane
669 dist = dVector3Dot(plane, offsetpos) - plane[3]; // Ax + By + Cz - D
670 if(dist>0)
672 // if we get here, we know the center of the sphere is
673 // outside of the convex hull.
674 if(dist<Sphere->radius)
676 // if we get here we know the sphere surface penetrates
677 // the plane
678 if(IsPointInPolygon(Sphere->final_posr->pos,pPoly,plane,Convex,out))
680 // finally if we get here we know that the
681 // sphere is directly touching the inside of the polyhedron
682 contact->normal[0] = plane[0];
683 contact->normal[1] = plane[1];
684 contact->normal[2] = plane[2];
685 contact->pos[0] = Sphere->final_posr->pos[0]+
686 (-contact->normal[0]*Sphere->radius);
687 contact->pos[1] = Sphere->final_posr->pos[1]+
688 (-contact->normal[1]*Sphere->radius);
689 contact->pos[2] = Sphere->final_posr->pos[2]+
690 (-contact->normal[2]*Sphere->radius);
691 contact->depth = Sphere->radius-dist;
692 contact->g1 = Sphere;
693 contact->g2 = Convex;
694 contact->side1 = -1;
695 contact->side2 = -1; // TODO: set plane index?
696 return 1;
698 else
700 // the sphere may not be directly touching
701 // the polyhedron, but it may be touching
702 // a point or an edge, if the distance between
703 // the closest point on the poly (out) and the
704 // center of the sphere is less than the sphere
705 // radius we have a hit.
706 temp[0] = (Sphere->final_posr->pos[0]-out[0]);
707 temp[1] = (Sphere->final_posr->pos[1]-out[1]);
708 temp[2] = (Sphere->final_posr->pos[2]-out[2]);
709 dist=(temp[0]*temp[0])+(temp[1]*temp[1])+(temp[2]*temp[2]);
710 // avoid the sqrt unless really necesary
711 if(dist<(Sphere->radius*Sphere->radius))
713 // We got an indirect hit
714 dist=dSqrt(dist);
715 contact->normal[0] = temp[0]/dist;
716 contact->normal[1] = temp[1]/dist;
717 contact->normal[2] = temp[2]/dist;
718 contact->pos[0] = Sphere->final_posr->pos[0]+
719 (-contact->normal[0]*Sphere->radius);
720 contact->pos[1] = Sphere->final_posr->pos[1]+
721 (-contact->normal[1]*Sphere->radius);
722 contact->pos[2] = Sphere->final_posr->pos[2]+
723 (-contact->normal[2]*Sphere->radius);
724 contact->depth = Sphere->radius-dist;
725 contact->g1 = Sphere;
726 contact->g2 = Convex;
727 contact->side1 = -1;
728 contact->side2 = -1; // TODO: set plane index?
729 return 1;
733 sphereinside=false;
735 if(sphereinside)
737 if(closestdist>dFabs(dist))
739 closestdist=dFabs(dist);
740 closestplane=i;
743 pPoly+=pPoly[0]+1;
745 if(sphereinside)
747 // if the center of the sphere is inside
748 // the Convex, we need to pop it out
749 dMultiply0_331(contact->normal,
750 Convex->final_posr->R,
751 &Convex->planes[(closestplane*4)]);
752 contact->pos[0] = Sphere->final_posr->pos[0];
753 contact->pos[1] = Sphere->final_posr->pos[1];
754 contact->pos[2] = Sphere->final_posr->pos[2];
755 contact->depth = closestdist+Sphere->radius;
756 contact->g1 = Sphere;
757 contact->g2 = Convex;
758 contact->side1 = -1;
759 contact->side2 = -1; // TODO: set plane index?
760 return 1;
762 return 0;
765 int dCollideConvexBox (dxGeom *o1, dxGeom *o2, int flags,
766 dContactGeom * /*contact*/, int skip)
768 dIASSERT (skip >= (int)sizeof(dContactGeom));
769 dIASSERT (o1->type == dConvexClass);
770 dIASSERT (o2->type == dBoxClass);
771 dIASSERT ((flags & NUMC_MASK) >= 1);
773 //dxConvex *Convex = (dxConvex*) o1;
774 //dxBox *Box = (dxBox*) o2;
776 return 0;
779 int dCollideConvexCapsule (dxGeom *o1, dxGeom *o2,
780 int flags, dContactGeom * /*contact*/, int skip)
782 dIASSERT (skip >= (int)sizeof(dContactGeom));
783 dIASSERT (o1->type == dConvexClass);
784 dIASSERT (o2->type == dCapsuleClass);
785 dIASSERT ((flags & NUMC_MASK) >= 1);
787 //dxConvex *Convex = (dxConvex*) o1;
788 //dxCapsule *Capsule = (dxCapsule*) o2;
790 return 0;
793 inline void ComputeInterval(dxConvex& cvx,dVector4 axis,dReal& min,dReal& max)
795 /* TODO: Use Support points here */
796 dVector3 point;
797 dReal value;
798 //fprintf(stdout,"Compute Interval Axis %f,%f,%f\n",axis[0],axis[1],axis[2]);
799 dMultiply0_331(point,cvx.final_posr->R,cvx.points);
800 //fprintf(stdout,"initial point %f,%f,%f\n",point[0],point[1],point[2]);
801 point[0]+=cvx.final_posr->pos[0];
802 point[1]+=cvx.final_posr->pos[1];
803 point[2]+=cvx.final_posr->pos[2];
804 max = min = dCalcVectorDot3(point,axis)-axis[3];//(*)
805 for (unsigned int i = 1; i < cvx.pointcount; ++i)
807 dMultiply0_331(point,cvx.final_posr->R,cvx.points+(i*3));
808 point[0]+=cvx.final_posr->pos[0];
809 point[1]+=cvx.final_posr->pos[1];
810 point[2]+=cvx.final_posr->pos[2];
811 value=dCalcVectorDot3(point,axis)-axis[3];//(*)
812 if(value<min)
814 min=value;
816 else if(value>max)
818 max=value;
821 // *: usually using the distance part of the plane (axis) is
822 // not necesary, however, here we need it here in order to know
823 // which face to pick when there are 2 parallel sides.
826 bool CheckEdgeIntersection(dxConvex& cvx1,dxConvex& cvx2, int flags,int& curc,
827 dContactGeom *contact, int skip)
829 int maxc = flags & NUMC_MASK;
830 dIASSERT(maxc != 0);
831 dVector3 e1,e2,q;
832 dVector4 plane,depthplane;
833 dReal t;
834 for(unsigned int i = 0;i<cvx1.edgecount;++i)
836 // Rotate
837 dMultiply0_331(e1,cvx1.final_posr->R,cvx1.points+(cvx1.edges[i].first*3));
838 // translate
839 e1[0]+=cvx1.final_posr->pos[0];
840 e1[1]+=cvx1.final_posr->pos[1];
841 e1[2]+=cvx1.final_posr->pos[2];
842 // Rotate
843 dMultiply0_331(e2,cvx1.final_posr->R,cvx1.points+(cvx1.edges[i].second*3));
844 // translate
845 e2[0]+=cvx1.final_posr->pos[0];
846 e2[1]+=cvx1.final_posr->pos[1];
847 e2[2]+=cvx1.final_posr->pos[2];
848 const unsigned int* pPoly=cvx2.polygons;
849 for(sizeint j=0;j<cvx2.planecount;++j)
851 // Rotate
852 dMultiply0_331(plane,cvx2.final_posr->R,cvx2.planes+(j*4));
853 dNormalize3(plane);
854 // Translate
855 plane[3]=
856 (cvx2.planes[(j*4)+3])+
857 ((plane[0] * cvx2.final_posr->pos[0]) +
858 (plane[1] * cvx2.final_posr->pos[1]) +
859 (plane[2] * cvx2.final_posr->pos[2]));
860 dContactGeom *target = SAFECONTACT(flags, contact, curc, skip);
861 target->g1=&cvx1; // g1 is the one pushed
862 target->g2=&cvx2;
863 if(IntersectSegmentPlane(e1,e2,plane,t,target->pos))
865 if(IsPointInPolygon(target->pos,pPoly,plane,&cvx2,q))
867 target->depth = dInfinity;
868 for(sizeint k=0;k<cvx2.planecount;++k)
870 if(k==j) continue; // we're already at 0 depth on this plane
871 // Rotate
872 dMultiply0_331(depthplane,cvx2.final_posr->R,cvx2.planes+(k*4));
873 dNormalize3(depthplane);
874 // Translate
875 depthplane[3]=
876 (cvx2.planes[(k*4)+3])+
877 ((plane[0] * cvx2.final_posr->pos[0]) +
878 (plane[1] * cvx2.final_posr->pos[1]) +
879 (plane[2] * cvx2.final_posr->pos[2]));
880 dReal depth = (dVector3Dot(depthplane, target->pos) - depthplane[3]); // Ax + By + Cz - D
881 if((fabs(depth)<fabs(target->depth))&&((depth<-dEpsilon)||(depth>dEpsilon)))
883 target->depth=depth;
884 dVector3Copy(depthplane,target->normal);
887 ++curc;
888 if(curc==maxc)
889 return true;
892 pPoly+=pPoly[0]+1;
895 return false;
899 Helper struct
901 struct ConvexConvexSATOutput
903 dReal min_depth;
904 int depth_type;
905 dVector3 dist; // distance from center to center, from cvx1 to cvx2
906 dVector3 e1a,e1b,e2a,e2b; // e1a to e1b = edge in cvx1,e2a to e2b = edge in cvx2.
909 /*! \brief Does an axis separation test using cvx1 planes on cvx1 and cvx2, returns true for a collision false for no collision
910 \param cvx1 [IN] First Convex object, its planes are used to do the tests
911 \param cvx2 [IN] Second Convex object
912 \param min_depth [IN/OUT] Used to input as well as output the minimum depth so far, must be set to a huge value such as dInfinity for initialization.
913 \param g1 [OUT] Pointer to the convex which should be used in the returned contact as g1
914 \param g2 [OUT] Pointer to the convex which should be used in the returned contact as g2
916 inline bool CheckSATConvexFaces(dxConvex& cvx1,
917 dxConvex& cvx2,
918 ConvexConvexSATOutput& ccso)
920 dReal min,max,min1,max1,min2,max2,depth;
921 dVector4 plane;
922 for(unsigned int i=0;i<cvx1.planecount;++i)
924 // -- Apply Transforms --
925 // Rotate
926 dMultiply0_331(plane,cvx1.final_posr->R,cvx1.planes+(i*4));
927 dNormalize3(plane);
928 // Translate
929 plane[3]=
930 (cvx1.planes[(i*4)+3])+
931 ((plane[0] * cvx1.final_posr->pos[0]) +
932 (plane[1] * cvx1.final_posr->pos[1]) +
933 (plane[2] * cvx1.final_posr->pos[2]));
934 ComputeInterval(cvx1,plane,min1,max1);
935 ComputeInterval(cvx2,plane,min2,max2);
936 if(max2<min1 || max1<min2) return false;
937 min = dMAX(min1, min2);
938 max = dMIN(max1, max2);
939 depth = max-min;
941 Take only into account the faces that penetrate cvx1 to determine
942 minimum depth
943 ((max2*min2)<=0) = different sign, or one is zero and thus
944 cvx2 barelly touches cvx1
946 if (((max2*min2)<=0) && (dFabs(depth)<dFabs(ccso.min_depth)))
948 // Flip plane because the contact normal must point INTO g1,
949 // plus the integrator seems to like positive depths better than negative ones
950 ccso.min_depth=-depth;
951 ccso.depth_type = 1; // 1 = face-something
954 return true;
956 /*! \brief Does an axis separation test using cvx1 and cvx2 edges, returns true for a collision false for no collision
957 \param cvx1 [IN] First Convex object
958 \param cvx2 [IN] Second Convex object
959 \param min_depth [IN/OUT] Used to input as well as output the minimum depth so far, must be set to a huge value such as dInfinity for initialization.
960 \param g1 [OUT] Pointer to the convex which should be used in the returned contact as g1
961 \param g2 [OUT] Pointer to the convex which should be used in the returned contact as g2
963 inline bool CheckSATConvexEdges(dxConvex& cvx1,
964 dxConvex& cvx2,
965 ConvexConvexSATOutput& ccso)
967 // Test cross products of pairs of edges
968 dReal depth,min,max,min1,max1,min2,max2;
969 dVector4 plane;
970 dVector3 e1,e2,e1a,e1b,e2a,e2b;
971 dVector3 dist;
972 dVector3Copy(ccso.dist,dist);
973 unsigned int s1 = cvx1.SupportIndex(dist);
974 // invert direction
975 dVector3Inv(dist);
976 unsigned int s2 = cvx2.SupportIndex(dist);
977 for(unsigned int i = 0;i<cvx1.edgecount;++i)
979 // Skip edge if it doesn't contain the extremal vertex
980 if((cvx1.edges[i].first!=s1)&&(cvx1.edges[i].second!=s1)) continue;
981 // we only need to apply rotation here
982 dMultiply0_331(e1a,cvx1.final_posr->R,cvx1.points+(cvx1.edges[i].first*3));
983 dMultiply0_331(e1b,cvx1.final_posr->R,cvx1.points+(cvx1.edges[i].second*3));
984 e1[0]=e1b[0]-e1a[0];
985 e1[1]=e1b[1]-e1a[1];
986 e1[2]=e1b[2]-e1a[2];
987 for(unsigned int j = 0;j<cvx2.edgecount;++j)
989 // Skip edge if it doesn't contain the extremal vertex
990 if((cvx2.edges[j].first!=s2)&&(cvx2.edges[j].second!=s2)) continue;
991 // we only need to apply rotation here
992 dMultiply0_331 (e2a,cvx2.final_posr->R,cvx2.points+(cvx2.edges[j].first*3));
993 dMultiply0_331 (e2b,cvx2.final_posr->R,cvx2.points+(cvx2.edges[j].second*3));
994 e2[0]=e2b[0]-e2a[0];
995 e2[1]=e2b[1]-e2a[1];
996 e2[2]=e2b[2]-e2a[2];
997 dCalcVectorCross3(plane,e1,e2);
998 if(dCalcVectorDot3(plane,plane)<dEpsilon) /* edges are parallel */ continue;
999 dNormalize3(plane);
1000 plane[3]=0;
1001 ComputeInterval(cvx1,plane,min1,max1);
1002 ComputeInterval(cvx2,plane,min2,max2);
1003 if(max2 < min1 || max1 < min2) return false;
1004 min = dMAX(min1, min2);
1005 max = dMIN(max1, max2);
1006 depth = max-min;
1007 if (((dFabs(depth)+dEpsilon)<dFabs(ccso.min_depth)))
1009 ccso.min_depth=depth;
1010 ccso.depth_type = 2; // 2 means edge-edge
1011 // use cached values, add position
1012 dVector3Copy(e1a,ccso.e1a);
1013 dVector3Copy(e1b,ccso.e1b);
1014 ccso.e1a[0]+=cvx1.final_posr->pos[0];
1015 ccso.e1a[1]+=cvx1.final_posr->pos[1];
1016 ccso.e1a[2]+=cvx1.final_posr->pos[2];
1017 ccso.e1b[0]+=cvx1.final_posr->pos[0];
1018 ccso.e1b[1]+=cvx1.final_posr->pos[1];
1019 ccso.e1b[2]+=cvx1.final_posr->pos[2];
1020 dVector3Copy(e2a,ccso.e2a);
1021 dVector3Copy(e2b,ccso.e2b);
1022 ccso.e2a[0]+=cvx2.final_posr->pos[0];
1023 ccso.e2a[1]+=cvx2.final_posr->pos[1];
1024 ccso.e2a[2]+=cvx2.final_posr->pos[2];
1025 ccso.e2b[0]+=cvx2.final_posr->pos[0];
1026 ccso.e2b[1]+=cvx2.final_posr->pos[1];
1027 ccso.e2b[2]+=cvx2.final_posr->pos[2];
1031 return true;
1034 #if 0
1035 /*! \brief Returns the index of the plane/side of the incident convex (ccso.g2)
1036 * which is closer to the reference convex (ccso.g1) side
1038 * This function just looks for the incident face that is facing the reference face
1039 * and is the closest to being parallel to it, which sometimes is.
1041 inline unsigned int GetIncidentSide(ConvexConvexSATOutput& ccso)
1043 dVector3 nis; // (N)ormal in (I)ncident convex (S)pace
1044 dReal SavedDot;
1045 dReal Dot;
1046 unsigned int incident_side=0;
1047 // Rotate the plane normal into incident convex space
1048 // (things like this should be done all over this file,
1049 // will look into that)
1050 dMultiply1_331(nis,ccso.g2->final_posr->R,ccso.plane);
1051 SavedDot = dCalcVectorDot3(nis,ccso.g2->planes);
1052 for(unsigned int i=1;i<ccso.g2->planecount;++i)
1054 Dot = dCalcVectorDot3(nis,ccso.g2->planes+(i*4));
1055 if(Dot>SavedDot)
1057 SavedDot=Dot;
1058 incident_side=i;
1061 return incident_side;
1063 #endif
1065 inline unsigned int GetSupportSide(dVector3& dir,dxConvex& cvx)
1067 dVector3 dics,tmp; // Direction in convex space
1068 dReal SavedDot;
1069 dReal Dot;
1070 unsigned int side=0;
1071 dVector3Copy(dir,tmp);
1072 dNormalize3(tmp);
1073 dMultiply1_331(dics,cvx.final_posr->R,tmp);
1074 SavedDot = dCalcVectorDot3(dics,cvx.planes);
1075 for(unsigned int i=1;i<cvx.planecount;++i)
1077 Dot = dCalcVectorDot3(dics,cvx.planes+(i*4));
1078 if(Dot>SavedDot)
1080 SavedDot=Dot;
1081 side=i;
1084 return side;
1087 /*! \brief Does an axis separation test between the 2 convex shapes
1088 using faces and edges */
1089 int TestConvexIntersection(dxConvex& cvx1,dxConvex& cvx2, int flags,
1090 dContactGeom *contact, int skip)
1092 ConvexConvexSATOutput ccso;
1093 #ifndef dNDEBUG
1094 memset(&ccso, 0, sizeof(ccso)); // get rid of 'uninitialized values' warning
1095 #endif
1096 ccso.min_depth=dInfinity; // Min not min at all
1097 ccso.depth_type=0; // no type
1098 // precompute distance vector
1099 dSubtractVectors3(ccso.dist, cvx2.final_posr->pos, cvx1.final_posr->pos);
1100 int maxc = flags & NUMC_MASK;
1101 dIASSERT(maxc != 0);
1102 dVector3 i1,i2,r1,r2; // edges of incident and reference faces respectively
1103 int contacts=0;
1104 if(!CheckSATConvexFaces(cvx1,cvx2,ccso))
1106 return 0;
1108 else
1109 if(!CheckSATConvexFaces(cvx2,cvx1,ccso))
1111 return 0;
1113 else if(!CheckSATConvexEdges(cvx1,cvx2,ccso))
1115 return 0;
1117 // If we get here, there was a collision
1118 if(ccso.depth_type==1) // face-face
1120 // cvx1 MUST always be in contact->g1 and cvx2 in contact->g2
1121 // This was learned the hard way :(
1122 unsigned int incident_side;
1123 const unsigned int* pIncidentPoly;
1124 const unsigned int* pIncidentPoints;
1125 unsigned int reference_side;
1126 const unsigned int* pReferencePoly;
1127 const unsigned int* pReferencePoints;
1128 dVector4 plane,rplane,iplane;
1129 dVector3 tmp;
1130 dVector3 dist,p;
1131 dReal t,d,d1,d2;
1132 bool outside,out;
1133 dVector3Copy(ccso.dist,dist);
1134 reference_side = GetSupportSide(dist,cvx1);
1135 dNegateVector3(dist);
1136 incident_side = GetSupportSide(dist,cvx2);
1138 pReferencePoly = cvx1.polygons;
1139 pIncidentPoly = cvx2.polygons;
1140 // Get Reference plane (We may not have to apply transforms Optimization Oportunity)
1141 // Rotate
1142 dMultiply0_331(rplane,cvx1.final_posr->R,cvx1.planes+(reference_side*4));
1143 dNormalize3(rplane);
1144 // Translate
1145 rplane[3]=
1146 (cvx1.planes[(reference_side*4)+3])+
1147 ((rplane[0] * cvx1.final_posr->pos[0]) +
1148 (rplane[1] * cvx1.final_posr->pos[1]) +
1149 (rplane[2] * cvx1.final_posr->pos[2]));
1150 // flip
1151 rplane[0]=-rplane[0];
1152 rplane[1]=-rplane[1];
1153 rplane[2]=-rplane[2];
1154 rplane[3]=-rplane[3];
1155 for(unsigned int i=0;i<incident_side;++i)
1157 pIncidentPoly+=pIncidentPoly[0]+1;
1159 pIncidentPoints = pIncidentPoly+1;
1160 // Get the first point of the incident face
1161 dMultiply0_331(i2,cvx2.final_posr->R,&cvx2.points[(pIncidentPoints[0]*3)]);
1162 dVector3Add(i2,cvx2.final_posr->pos,i2);
1163 // Get the same point in the reference convex space
1164 dVector3Copy(i2,r2);
1165 dVector3Subtract(r2,cvx1.final_posr->pos,r2);
1166 dVector3Copy(r2,tmp);
1167 dMultiply1_331(r2,cvx1.final_posr->R,tmp);
1168 for(unsigned int i=0;i<pIncidentPoly[0];++i)
1170 // Move i2 to i1, r2 to r1
1171 dVector3Copy(i2,i1);
1172 dVector3Copy(r2,r1);
1173 dMultiply0_331(i2,cvx2.final_posr->R,&cvx2.points[(pIncidentPoints[(i+1)%pIncidentPoly[0]]*3)]);
1174 dVector3Add(i2,cvx2.final_posr->pos,i2);
1175 // Get the same point in the reference convex space
1176 dVector3Copy(i2,r2);
1177 dVector3Subtract(r2,cvx1.final_posr->pos,r2);
1178 dVector3Copy(r2,tmp);
1179 dMultiply1_331(r2,cvx1.final_posr->R,tmp);
1180 outside=false;
1181 for(unsigned int j=0;j<cvx1.planecount;++j)
1183 plane[0]=cvx1.planes[(j*4)+0];
1184 plane[1]=cvx1.planes[(j*4)+1];
1185 plane[2]=cvx1.planes[(j*4)+2];
1186 plane[3]=cvx1.planes[(j*4)+3];
1187 // Get the distance from the points to the plane
1188 d1 = r1[0]*plane[0]+
1189 r1[1]*plane[1]+
1190 r1[2]*plane[2]-
1191 plane[3];
1192 d2 = r2[0]*plane[0]+
1193 r2[1]*plane[1]+
1194 r2[2]*plane[2]-
1195 plane[3];
1196 if(d1*d2<0)
1198 out = false;
1200 // Edge intersects plane
1201 if (!IntersectSegmentPlane(r1,r2,plane,t,p))
1203 out = true;
1206 if (!out)
1208 // Check the resulting point again to make sure it is inside the reference convex
1209 for (unsigned int k = 0; k < cvx1.planecount; ++k)
1211 d = p[0]*cvx1.planes[(k*4)+0]+
1212 p[1]*cvx1.planes[(k*4)+1]+
1213 p[2]*cvx1.planes[(k*4)+2]-
1214 cvx1.planes[(k*4)+3];
1215 if(d>0)
1217 out = true;
1218 break;
1223 if(!out)
1225 #if 0
1226 // Use t to move p into global space
1227 p[0] = i1[0]+((i2[0]-i1[0])*t);
1228 p[1] = i1[1]+((i2[1]-i1[1])*t);
1229 p[2] = i1[2]+((i2[2]-i1[2])*t);
1230 #else
1231 // Apply reference convex transformations to p
1232 // The commented out piece of code is likelly to
1233 // produce less operations than this one, but
1234 // this way we know we are getting the right data
1235 dMultiply0_331(tmp,cvx1.final_posr->R,p);
1236 dVector3Add(tmp,cvx1.final_posr->pos,p);
1237 #endif
1238 // get p's distance to reference plane
1239 d = p[0]*rplane[0]+
1240 p[1]*rplane[1]+
1241 p[2]*rplane[2]-
1242 rplane[3];
1243 if(d>0)
1245 dContactGeom *target = SAFECONTACT(flags, contact, contacts, skip);
1246 dVector3Copy(p, target->pos);
1247 dVector3Copy(rplane, target->normal);
1248 target->g1 = &cvx1;
1249 target->g2 = &cvx2;
1250 target->depth = d;
1251 ++contacts;
1252 if (contacts==maxc) return contacts;
1256 if(d1>0)
1258 outside=true;
1261 if(outside) continue;
1262 d = i1[0]*rplane[0]+
1263 i1[1]*rplane[1]+
1264 i1[2]*rplane[2]-
1265 rplane[3];
1266 if(d>0)
1268 dContactGeom *target = SAFECONTACT(flags, contact, contacts, skip);
1269 dVector3Copy(i1, target->pos);
1270 dVector3Copy(rplane, target->normal);
1271 target->g1 = &cvx1;
1272 target->g2 = &cvx2;
1273 target->depth = d;
1274 ++contacts;
1275 if (contacts==maxc) return contacts;
1278 // IF we get here, we got the easiest contacts to calculate,
1279 // but there is still space in the contacts array for more.
1280 // So, project the Reference's face points onto the Incident face
1281 // plane and test them for inclusion in the reference plane as well.
1282 // We already have computed intersections so, skip those.
1284 /* Get Incident plane, we need it for projection */
1285 /* Rotate */
1286 dMultiply0_331(iplane,cvx2.final_posr->R,cvx2.planes+(incident_side*4));
1287 dNormalize3(iplane);
1288 /* Translate */
1289 iplane[3]=
1290 (cvx2.planes[(incident_side*4)+3]) +
1291 ((iplane[0] * cvx2.final_posr->pos[0]) +
1292 (iplane[1] * cvx2.final_posr->pos[1]) +
1293 (iplane[2] * cvx2.final_posr->pos[2]));
1294 // get reference face
1295 for(unsigned int i=0;i<reference_side;++i)
1297 pReferencePoly+=pReferencePoly[0]+1;
1299 pReferencePoints = pReferencePoly+1;
1300 for(unsigned int i=0;i<pReferencePoly[0];++i)
1302 dMultiply0_331(i1,cvx1.final_posr->R,&cvx1.points[(pReferencePoints[i]*3)]);
1303 dVector3Add(cvx1.final_posr->pos,i1,i1);
1304 // Project onto Incident face plane
1305 t = -(i1[0]*iplane[0]+
1306 i1[1]*iplane[1]+
1307 i1[2]*iplane[2]-
1308 iplane[3]);
1309 i1[0]+=iplane[0]*t;
1310 i1[1]+=iplane[1]*t;
1311 i1[2]+=iplane[2]*t;
1312 // Get the same point in the incident convex space
1313 dVector3Copy(i1,r1);
1314 dVector3Subtract(r1,cvx2.final_posr->pos,r1);
1315 dVector3Copy(r1,tmp);
1316 dMultiply1_331(r1,cvx2.final_posr->R,tmp);
1317 // Check if it is outside the incident convex
1318 out = false;
1319 for(unsigned int j=0;j<cvx2.planecount;++j)
1321 d = r1[0]*cvx2.planes[(j*4)+0]+
1322 r1[1]*cvx2.planes[(j*4)+1]+
1323 r1[2]*cvx2.planes[(j*4)+2]-
1324 cvx2.planes[(j*4)+3];
1325 if(d>=0){out = true;break;};
1327 if(!out)
1329 // check that the point is not a duplicate
1330 outside = false;
1331 for(int j=0;j<contacts;++j)
1333 dContactGeom *cur_contact = SAFECONTACT(flags, contact, j, skip);
1334 if((cur_contact->pos[0] == i1[0]) &&
1335 (cur_contact->pos[1] == i1[1]) &&
1336 (cur_contact->pos[2] == i1[2]))
1338 outside=true;
1341 if(!outside)
1343 d = i1[0]*rplane[0]+
1344 i1[1]*rplane[1]+
1345 i1[2]*rplane[2]-
1346 rplane[3];
1347 if(d>0)
1349 dContactGeom *target = SAFECONTACT(flags, contact, contacts, skip);
1350 dVector3Copy(i1, target->pos);
1351 dVector3Copy(rplane, target->normal);
1352 target->g1 = &cvx1;
1353 target->g2 = &cvx2;
1354 target->depth = d;
1355 ++contacts;
1356 if (contacts==maxc) return contacts;
1362 else if (ccso.depth_type == 2) // edge-edge
1364 dVector3 c1, c2;
1365 ClosestPointBetweenSegments(ccso.e1a, ccso.e1b, ccso.e2a, ccso.e2b, c1, c2);
1367 dContactGeom *target = SAFECONTACT(flags, contact, contacts, skip);
1368 dSubtractVectors3(target->normal, c2, c1);
1369 dReal depth_square = dCalcVectorLengthSquare3(target->normal);
1371 if (dxSafeNormalize3(target->normal))
1373 target->depth = dSqrt(depth_square);
1375 else
1377 // If edges coincide return direction from one center to the other as the contact normal
1378 dVector3Copy(ccso.dist, target->normal);
1380 if (!dxSafeNormalize3(target->normal))
1382 // If the both centers coincide as well return an arbitrary vector. The depth is going to be zero anyway.
1383 dAssignVector3(target->normal, 1, 0, 0);
1386 target->depth = 0; // Since the edges coincide, return a contact of zero depth
1389 target->g1 = &cvx1;
1390 target->g2 = &cvx2;
1391 dVector3Copy(c1, target->pos);
1392 contacts++;
1394 return contacts;
1397 int dCollideConvexConvex (dxGeom *o1, dxGeom *o2, int flags,
1398 dContactGeom *contact, int skip)
1400 dIASSERT (skip >= (int)sizeof(dContactGeom));
1401 dIASSERT (o1->type == dConvexClass);
1402 dIASSERT (o2->type == dConvexClass);
1403 dIASSERT ((flags & NUMC_MASK) >= 1);
1404 dxConvex *Convex1 = (dxConvex*) o1;
1405 dxConvex *Convex2 = (dxConvex*) o2;
1406 return TestConvexIntersection(*Convex1,*Convex2,flags,
1407 contact,skip);
1410 #if 0
1411 int dCollideRayConvex (dxGeom *o1, dxGeom *o2, int flags,
1412 dContactGeom *contact, int skip)
1414 dIASSERT (skip >= (int)sizeof(dContactGeom));
1415 dIASSERT( o1->type == dRayClass );
1416 dIASSERT( o2->type == dConvexClass );
1417 dIASSERT ((flags & NUMC_MASK) >= 1);
1418 dxRay* ray = (dxRay*) o1;
1419 dxConvex* convex = (dxConvex*) o2;
1420 dVector3 origin,destination,contactpoint,out;
1421 dReal depth;
1422 dVector4 plane;
1423 unsigned int *pPoly=convex->polygons;
1424 // Calculate ray origin and destination
1425 destination[0]=0;
1426 destination[1]=0;
1427 destination[2]= ray->length;
1428 // -- Rotate --
1429 dMultiply0_331(destination,ray->final_posr->R,destination);
1430 origin[0]=ray->final_posr->pos[0];
1431 origin[1]=ray->final_posr->pos[1];
1432 origin[2]=ray->final_posr->pos[2];
1433 destination[0]+=origin[0];
1434 destination[1]+=origin[1];
1435 destination[2]+=origin[2];
1436 for(int i=0;i<convex->planecount;++i)
1438 // Rotate
1439 dMultiply0_331(plane,convex->final_posr->R,convex->planes+(i*4));
1440 // Translate
1441 plane[3]=
1442 (convex->planes[(i*4)+3])+
1443 ((plane[0] * convex->final_posr->pos[0]) +
1444 (plane[1] * convex->final_posr->pos[1]) +
1445 (plane[2] * convex->final_posr->pos[2]));
1446 if(IntersectSegmentPlane(origin,
1447 destination,
1448 plane,
1449 depth,
1450 contactpoint))
1452 if(IsPointInPolygon(contactpoint,pPoly,plane,convex,out))
1454 contact->pos[0]=contactpoint[0];
1455 contact->pos[1]=contactpoint[1];
1456 contact->pos[2]=contactpoint[2];
1457 contact->normal[0]=plane[0];
1458 contact->normal[1]=plane[1];
1459 contact->normal[2]=plane[2];
1460 contact->depth=depth;
1461 contact->g1 = ray;
1462 contact->g2 = convex;
1463 contact->side1 = -1;
1464 contact->side2 = -1; // TODO: set plane index?
1465 return 1;
1468 pPoly+=pPoly[0]+1;
1470 return 0;
1472 #else
1473 // Ray - Convex collider by David Walters, June 2006
1474 int dCollideRayConvex(dxGeom *o1, dxGeom *o2,
1475 int flags, dContactGeom *contact, int skip)
1477 dIASSERT(skip >= (int)sizeof(dContactGeom));
1478 dIASSERT(o1->type == dRayClass);
1479 dIASSERT(o2->type == dConvexClass);
1480 dIASSERT((flags & NUMC_MASK) >= 1);
1482 dxRay* ray = (dxRay*)o1;
1483 dxConvex* convex = (dxConvex*)o2;
1485 contact->g1 = ray;
1486 contact->g2 = convex;
1487 contact->side1 = -1;
1488 contact->side2 = -1; // TODO: set plane index?
1490 dReal alpha, beta, nsign;
1491 int flag = 0;
1494 // Compute some useful info
1497 dVector3 ray_pos = {
1498 ray->final_posr->pos[0] - convex->final_posr->pos[0],
1499 ray->final_posr->pos[1] - convex->final_posr->pos[1],
1500 ray->final_posr->pos[2] - convex->final_posr->pos[2]
1503 dVector3 ray_dir = {
1504 ray->final_posr->R[0 * 4 + 2],
1505 ray->final_posr->R[1 * 4 + 2],
1506 ray->final_posr->R[2 * 4 + 2]
1509 dMultiply1_331(ray_pos, convex->final_posr->R, ray_pos);
1510 dMultiply1_331(ray_dir, convex->final_posr->R, ray_dir);
1512 for (unsigned int i = 0; i < convex->planecount; ++i)
1514 // Alias this plane.
1515 const dReal* plane = convex->planes + (i * 4);
1517 // If alpha >= 0 then start point is outside of plane.
1518 alpha = dCalcVectorDot3(plane, ray_pos) - plane[3];
1520 // If any alpha is positive, then
1521 // the ray start is _outside_ of the hull
1522 if (alpha >= 0)
1524 flag = 1;
1525 break;
1529 // If the ray starts inside the convex hull, then everything is flipped.
1530 nsign = (flag) ? REAL(1.0) : REAL(-1.0);
1534 // Find closest contact point
1537 // Assume no contacts.
1538 contact->depth = dInfinity;
1540 for (unsigned int i = 0; i < convex->planecount; ++i)
1542 // Alias this plane.
1543 const dReal* plane = convex->planes + (i * 4);
1545 // If alpha >= 0 then point is outside of plane.
1546 alpha = nsign * (dCalcVectorDot3(plane, ray_pos) - plane[3]);
1548 // Compute [ plane-normal DOT ray-normal ], (/flip)
1549 beta = dCalcVectorDot3(plane, ray_dir) * nsign;
1551 // Ray is pointing at the plane? ( beta < 0 )
1552 // Ray start to plane is within maximum ray length?
1553 // Ray start to plane is closer than the current best distance?
1554 if (beta < -dEpsilon &&
1555 alpha >= 0 && alpha <= ray->length &&
1556 alpha < contact->depth)
1558 // Compute contact point on convex hull surface.
1559 contact->pos[0] = ray_pos[0] + alpha * ray_dir[0];
1560 contact->pos[1] = ray_pos[1] + alpha * ray_dir[1];
1561 contact->pos[2] = ray_pos[2] + alpha * ray_dir[2];
1563 flag = 0;
1565 // For all _other_ planes.
1566 for (unsigned int j = 0; j < convex->planecount; ++j)
1568 if (i == j)
1569 continue; // Skip self.
1571 // Alias this plane.
1572 const dReal* planej = convex->planes + (j * 4);
1574 // If beta >= 0 then start is outside of plane.
1575 beta = dCalcVectorDot3(planej, contact->pos) - planej[3];
1577 // If any beta is positive, then the contact point
1578 // is not on the surface of the convex hull - it's just
1579 // intersecting some part of its infinite extent.
1580 if (beta > dEpsilon)
1582 flag = 1;
1583 break;
1587 // Contact point isn't outside hull's surface? then it's a good contact!
1588 if (flag == 0)
1590 // Store the contact normal, possibly flipped.
1591 contact->normal[0] = nsign * plane[0];
1592 contact->normal[1] = nsign * plane[1];
1593 contact->normal[2] = nsign * plane[2];
1595 // Store depth
1596 contact->depth = alpha;
1598 if ((flags & CONTACTS_UNIMPORTANT) && contact->depth <= ray->length)
1600 // Break on any contact if contacts are not important
1601 break;
1606 // Contact?
1607 if (contact->depth <= ray->length)
1609 // Adjust contact position and normal back to global space
1610 dMultiply0_331(contact->pos, convex->final_posr->R, contact->pos);
1611 dMultiply0_331(contact->normal, convex->final_posr->R, contact->normal);
1612 contact->pos[0] += convex->final_posr->pos[0];
1613 contact->pos[1] += convex->final_posr->pos[1];
1614 contact->pos[2] += convex->final_posr->pos[2];
1615 return true;
1617 return false;
1620 #endif
1621 //<-- Convex Collision