1 /*************************************************************************
3 * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. *
4 * All rights reserved. Email: russ@q12.org Web: www.q12.org *
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 *
13 * (2) The BSD-style license that is included with this library in *
14 * the file LICENSE-BSD.TXT. *
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. *
21 *************************************************************************/
23 Code for Convex Collision Detection
26 #include <ode/common.h>
27 #include <ode/collision.h>
28 #include <ode/rotation.h>
32 #include "collision_kernel.h"
33 #include "collision_std.h"
34 #include "collision_util.h"
37 #pragma warning(disable:4291) // for VC++, no complaints about "no matching operator delete found"
41 #define dMIN(A,B) ((A)>(B) ? (B) : (A))
42 #define dMAX(A,B) ((A)>(B) ? (A) : (B))
44 #define dMIN(A,B) std::min(A,B)
45 #define dMAX(A,B) std::max(A,B)
48 //****************************************************************************
50 dxConvex::dxConvex (dSpaceID space
,
52 unsigned int _planecount
,
54 unsigned int _pointcount
,
55 const unsigned int *_polygons
) :
58 dAASSERT (_planes
!= NULL
);
59 dAASSERT (_points
!= NULL
);
60 dAASSERT (_polygons
!= NULL
);
61 //fprintf(stdout,"dxConvex Constructor planes %X\n",_planes);
64 planecount
= _planecount
;
65 // we need points as well
67 pointcount
= _pointcount
;
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 );
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
);
100 void dxConvex::computeAABB()
102 // this can, and should be optimized
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
;
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
]);
139 for(unsigned int k
=0;k
<edgecount
;++k
)
141 if((edges
[k
].first
==e
.first
)&&(edges
[k
].second
==e
.second
))
149 edge
* tmp
= new edge
[edgecount
+1];
152 memcpy(tmp
,edges
,(edgecount
)*sizeof(edge
));
155 tmp
[edgecount
].first
=e
.first
;
156 tmp
[edgecount
].second
=e
.second
;
161 points_in_poly
+=(*points_in_poly
+1);
162 index
=points_in_poly
+1;
166 dxConvex::BSPNode
* dxConvex::CreateNode(std::vector
<Arc
> Arcs
,std::vector
<Polygon
> Polygons
)
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
]
178 void dxConvex::CreateTree()
181 A
.reserve(edgecount
);
182 for(unsigned int i
=0;i
<edgecount
;++i
)
184 this->GetFacesSharedByEdge(i
,A
[i
].normals
);
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
);
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
)
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
,
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
;
229 s
->planecount
= _planecount
;
231 s
->pointcount
= _pointcount
;
232 s
->polygons
=_polygons
;
235 //****************************************************************************
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
245 \param q returns the intersection point
246 \return true if there is an intersection, otherwise false.
248 bool IntersectSegmentPlane(dVector3 a
,
254 // Compute the t value for the directed line ab intersecting the plane
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];
270 // Else no intersection
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
,
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
)
302 t
= ((a
*e
)-(b
*d
))/denominator
;
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
,
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
327 dVector3 d1
= {q1
[0] - p1
[0],
330 dVector3 d2
= {q2
[0] - p2
[0],
333 dVector3 r
= {p1
[0] - p2
[0],
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
350 // First segment degenerates into a point
352 t
= f
/ e
; // s = 0 => t = (b*s + f) / e = f / e
353 t
= dxClamp(t
, 0.0f
, 1.0f
);
357 dReal c
= dCalcVectorDot3(d1
, r
);
360 // Second segment degenerates into a point
362 s
= dxClamp(-c
/ a
, 0.0f
, 1.0f
); // t = 0 => s = (b*t - c) / a = -c / a
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)
374 s
= dxClamp((b
*f
- c
*e
) / denom
, 0.0f
, 1.0f
);
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
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]
387 s
= dxClamp(-c
/ a
, 0.0f
, 1.0f
);
388 } else if (t
> 1.0f
) {
390 s
= dxClamp((b
- c
) / a
, 0.0f
, 1.0f
);
393 dReal tnom
= b
*s
+ f
;
397 s
= dxClamp(-c
/ a
, 0.0f
, 1.0f
);
402 s
= dxClamp((b
- c
) / a
, 0.0f
, 1.0f
);
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
;
421 dReal tnom
= b
*s
+ f
;
424 s
= dxClamp(-c
/ a
, 0.0f
, 1.0f
);
425 } else if (tnom
> e
) {
427 s
= dxClamp((b
- c
) / a
, 0.0f
, 1.0f
);
433 /*! \brief Returns the Ray on which 2 planes intersect if they do.
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;
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
);
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
,
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
)
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]
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
,
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.
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
)
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];
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);
557 else if (s
>= REAL(1.0))
565 out
[0] = a
[0] + ab
[0] * s
;
566 out
[1] = a
[1] + ab
[1] * s
;
567 out
[2] = a
[2] + ab
[2] * s
;
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
;
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
;
616 target
->side1
= -1; // TODO: set plane index?
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
;
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
;
649 // dVector3 contactpoint;
650 dVector3 offsetpos
,out
,temp
;
651 const unsigned int *pPoly
=Convex
->polygons
;
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
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
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
;
695 contact
->side2
= -1; // TODO: set plane index?
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
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
;
728 contact
->side2
= -1; // TODO: set plane index?
737 if(closestdist
>dFabs(dist
))
739 closestdist
=dFabs(dist
);
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
;
759 contact
->side2
= -1; // TODO: set plane index?
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;
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;
793 inline void ComputeInterval(dxConvex
& cvx
,dVector4 axis
,dReal
& min
,dReal
& max
)
795 /* TODO: Use Support points here */
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];//(*)
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
;
832 dVector4 plane
,depthplane
;
834 for(unsigned int i
= 0;i
<cvx1
.edgecount
;++i
)
837 dMultiply0_331(e1
,cvx1
.final_posr
->R
,cvx1
.points
+(cvx1
.edges
[i
].first
*3));
839 e1
[0]+=cvx1
.final_posr
->pos
[0];
840 e1
[1]+=cvx1
.final_posr
->pos
[1];
841 e1
[2]+=cvx1
.final_posr
->pos
[2];
843 dMultiply0_331(e2
,cvx1
.final_posr
->R
,cvx1
.points
+(cvx1
.edges
[i
].second
*3));
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
)
852 dMultiply0_331(plane
,cvx2
.final_posr
->R
,cvx2
.planes
+(j
*4));
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
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
872 dMultiply0_331(depthplane
,cvx2
.final_posr
->R
,cvx2
.planes
+(k
*4));
873 dNormalize3(depthplane
);
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
)))
884 dVector3Copy(depthplane
,target
->normal
);
901 struct ConvexConvexSATOutput
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
,
918 ConvexConvexSATOutput
& ccso
)
920 dReal min
,max
,min1
,max1
,min2
,max2
,depth
;
922 for(unsigned int i
=0;i
<cvx1
.planecount
;++i
)
924 // -- Apply Transforms --
926 dMultiply0_331(plane
,cvx1
.final_posr
->R
,cvx1
.planes
+(i
*4));
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
);
941 Take only into account the faces that penetrate cvx1 to determine
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
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
,
965 ConvexConvexSATOutput
& ccso
)
967 // Test cross products of pairs of edges
968 dReal depth
,min
,max
,min1
,max1
,min2
,max2
;
970 dVector3 e1
,e2
,e1a
,e1b
,e2a
,e2b
;
972 dVector3Copy(ccso
.dist
,dist
);
973 unsigned int s1
= cvx1
.SupportIndex(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));
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));
997 dCalcVectorCross3(plane
,e1
,e2
);
998 if(dCalcVectorDot3(plane
,plane
)<dEpsilon
) /* edges are parallel */ continue;
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
);
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];
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
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));
1061 return incident_side
;
1065 inline unsigned int GetSupportSide(dVector3
& dir
,dxConvex
& cvx
)
1067 dVector3 dics
,tmp
; // Direction in convex space
1070 unsigned int side
=0;
1071 dVector3Copy(dir
,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));
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
;
1094 memset(&ccso
, 0, sizeof(ccso
)); // get rid of 'uninitialized values' warning
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
1104 if(!CheckSATConvexFaces(cvx1
,cvx2
,ccso
))
1109 if(!CheckSATConvexFaces(cvx2
,cvx1
,ccso
))
1113 else if(!CheckSATConvexEdges(cvx1
,cvx2
,ccso
))
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
;
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)
1142 dMultiply0_331(rplane
,cvx1
.final_posr
->R
,cvx1
.planes
+(reference_side
*4));
1143 dNormalize3(rplane
);
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]));
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
);
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]+
1192 d2
= r2
[0]*plane
[0]+
1200 // Edge intersects plane
1201 if (!IntersectSegmentPlane(r1
,r2
,plane
,t
,p
))
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];
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
);
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
);
1238 // get p's distance to reference plane
1245 dContactGeom
*target
= SAFECONTACT(flags
, contact
, contacts
, skip
);
1246 dVector3Copy(p
, target
->pos
);
1247 dVector3Copy(rplane
, target
->normal
);
1252 if (contacts
==maxc
) return contacts
;
1261 if(outside
) continue;
1262 d
= i1
[0]*rplane
[0]+
1268 dContactGeom
*target
= SAFECONTACT(flags
, contact
, contacts
, skip
);
1269 dVector3Copy(i1
, target
->pos
);
1270 dVector3Copy(rplane
, target
->normal
);
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 */
1286 dMultiply0_331(iplane
,cvx2
.final_posr
->R
,cvx2
.planes
+(incident_side
*4));
1287 dNormalize3(iplane
);
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]+
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
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;};
1329 // check that the point is not a duplicate
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]))
1343 d
= i1
[0]*rplane
[0]+
1349 dContactGeom
*target
= SAFECONTACT(flags
, contact
, contacts
, skip
);
1350 dVector3Copy(i1
, target
->pos
);
1351 dVector3Copy(rplane
, target
->normal
);
1356 if (contacts
==maxc
) return contacts
;
1362 else if (ccso
.depth_type
== 2) // edge-edge
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
);
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
1391 dVector3Copy(c1
, target
->pos
);
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
,
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
;
1423 unsigned int *pPoly
=convex
->polygons
;
1424 // Calculate ray origin and destination
1427 destination
[2]= ray
->length
;
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
)
1439 dMultiply0_331(plane
,convex
->final_posr
->R
,convex
->planes
+(i
*4));
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
,
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
;
1462 contact
->g2
= convex
;
1463 contact
->side1
= -1;
1464 contact
->side2
= -1; // TODO: set plane index?
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
;
1486 contact
->g2
= convex
;
1487 contact
->side1
= -1;
1488 contact
->side2
= -1; // TODO: set plane index?
1490 dReal alpha
, beta
, nsign
;
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
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];
1565 // For all _other_ planes.
1566 for (unsigned int j
= 0; j
< convex
->planecount
; ++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
)
1587 // Contact point isn't outside hull's surface? then it's a good contact!
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];
1596 contact
->depth
= alpha
;
1598 if ((flags
& CONTACTS_UNIMPORTANT
) && contact
->depth
<= ray
->length
)
1600 // Break on any contact if contacts are not important
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];
1621 //<-- Convex Collision