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 *************************************************************************/
25 standard ODE geometry primitives: public API and pairwise collision functions.
27 the rule is that only the low level primitive collision functions should set
28 dContactGeom::g1 and dContactGeom::g2.
32 #include <ode/common.h>
33 #include <ode/collision.h>
34 #include <ode/matrix.h>
35 #include <ode/rotation.h>
36 #include <ode/odemath.h>
38 #include "collision_kernel.h"
39 #include "collision_std.h"
40 #include "collision_util.h"
43 #pragma warning(disable:4291) // for VC++, no complaints about "no matching operator delete found"
46 //****************************************************************************
49 dxBox::dxBox (dSpaceID space
, dReal lx
, dReal ly
, dReal lz
) : dxGeom (space
,1)
51 dAASSERT (lx
>= 0 && ly
>= 0 && lz
>= 0);
56 updateZeroSizedFlag(!lx
|| !ly
|| !lz
);
60 void dxBox::computeAABB()
62 const dMatrix3
& R
= final_posr
->R
;
63 const dVector3
& pos
= final_posr
->pos
;
65 dReal xrange
= REAL(0.5) * (dFabs (R
[0] * side
[0]) +
66 dFabs (R
[1] * side
[1]) + dFabs (R
[2] * side
[2]));
67 dReal yrange
= REAL(0.5) * (dFabs (R
[4] * side
[0]) +
68 dFabs (R
[5] * side
[1]) + dFabs (R
[6] * side
[2]));
69 dReal zrange
= REAL(0.5) * (dFabs (R
[8] * side
[0]) +
70 dFabs (R
[9] * side
[1]) + dFabs (R
[10] * side
[2]));
71 aabb
[0] = pos
[0] - xrange
;
72 aabb
[1] = pos
[0] + xrange
;
73 aabb
[2] = pos
[1] - yrange
;
74 aabb
[3] = pos
[1] + yrange
;
75 aabb
[4] = pos
[2] - zrange
;
76 aabb
[5] = pos
[2] + zrange
;
80 dGeomID
dCreateBox (dSpaceID space
, dReal lx
, dReal ly
, dReal lz
)
82 return new dxBox (space
,lx
,ly
,lz
);
86 void dGeomBoxSetLengths (dGeomID g
, dReal lx
, dReal ly
, dReal lz
)
88 dUASSERT (g
&& g
->type
== dBoxClass
,"argument not a box");
89 dAASSERT (lx
>= 0 && ly
>= 0 && lz
>= 0);
90 dxBox
*b
= (dxBox
*) g
;
94 b
->updateZeroSizedFlag(!lx
|| !ly
|| !lz
);
99 void dGeomBoxGetLengths (dGeomID g
, dVector3 result
)
101 dUASSERT (g
&& g
->type
== dBoxClass
,"argument not a box");
102 dxBox
*b
= (dxBox
*) g
;
103 result
[0] = b
->side
[0];
104 result
[1] = b
->side
[1];
105 result
[2] = b
->side
[2];
109 dReal
dGeomBoxPointDepth (dGeomID g
, dReal x
, dReal y
, dReal z
)
111 dUASSERT (g
&& g
->type
== dBoxClass
,"argument not a box");
113 dxBox
*b
= (dxBox
*) g
;
115 // Set p = (x,y,z) relative to box center
117 // This will be (0,0,0) if the point is at (side[0]/2,side[1]/2,side[2]/2)
121 p
[0] = x
- b
->final_posr
->pos
[0];
122 p
[1] = y
- b
->final_posr
->pos
[1];
123 p
[2] = z
- b
->final_posr
->pos
[2];
125 // Rotate p into box's coordinate frame, so we can
126 // treat the OBB as an AABB
128 dMultiply1_331 (q
,b
->final_posr
->R
,p
);
130 // Record distance from point to each successive box side, and see
131 // if the point is inside all six sides
138 for (i
=0; i
< 3; i
++) {
139 dReal side
= b
->side
[i
] * REAL(0.5);
141 dist
[i
] = side
- q
[i
];
142 dist
[i
+3] = side
+ q
[i
];
144 if ((dist
[i
] < 0) || (dist
[i
+3] < 0)) {
149 // If point is inside the box, the depth is the smallest positive distance
153 dReal smallest_dist
= (dReal
) (unsigned) -1;
155 for (i
=0; i
< 6; i
++) {
156 if (dist
[i
] < smallest_dist
) smallest_dist
= dist
[i
];
159 return smallest_dist
;
162 // Otherwise, if point is outside the box, the depth is the largest
163 // distance to any side. This is an approximation to the 'proper'
164 // solution (the proper solution may be larger in some cases).
166 dReal largest_dist
= 0;
168 for (i
=0; i
< 6; i
++) {
169 if (dist
[i
] > largest_dist
) largest_dist
= dist
[i
];
172 return -largest_dist
;
175 //****************************************************************************
176 // box-box collision utility
179 // find all the intersection points between the 2D rectangle with vertices
180 // at (+/-h[0],+/-h[1]) and the 2D quadrilateral with vertices (p[0],p[1]),
181 // (p[2],p[3]),(p[4],p[5]),(p[6],p[7]).
183 // the intersection points are returned as x,y pairs in the 'ret' array.
184 // the number of intersection points is returned by the function (this will
185 // be in the range 0 to 8).
187 static int intersectRectQuad (dReal h
[2], dReal p
[8], dReal ret
[16])
189 // q (and r) contain nq (and nr) coordinate points for the current (and
195 for (int dir
=0; dir
<= 1; dir
++) {
196 // direction notation: xy[0] = x axis, xy[1] = y axis
197 for (int sign
=-1; sign
<= 1; sign
+= 2) {
198 // chop q along the line xy[dir] = sign*h[dir]
202 for (int i
=nq
; i
> 0; i
--) {
203 // go through all points in q and all lines between adjacent points
204 if (sign
*pq
[dir
] < h
[dir
]) {
205 // this point is inside the chopping line
215 dReal
*nextq
= (i
> 1) ? pq
+2 : q
;
216 if ((sign
*pq
[dir
] < h
[dir
]) ^ (sign
*nextq
[dir
] < h
[dir
])) {
217 // this line crosses the chopping line
218 pr
[1-dir
] = pq
[1-dir
] + (nextq
[1-dir
]-pq
[1-dir
]) /
219 (nextq
[dir
]-pq
[dir
]) * (sign
*h
[dir
]-pq
[dir
]);
220 pr
[dir
] = sign
*h
[dir
];
231 r
= (q
==ret
) ? buffer
: ret
;
236 if (q
!= ret
) memcpy (ret
,q
,nr
*2*sizeof(dReal
));
241 // given n points in the plane (array p, of size 2*n), generate m points that
242 // best represent the whole set. the definition of 'best' here is not
243 // predetermined - the idea is to select points that give good box-box
244 // collision detection behavior. the chosen point indexes are returned in the
245 // array iret (of size m). 'i0' is always the first entry in the array.
246 // n must be in the range [1..8]. m must be in the range [1..n]. i0 must be
247 // in the range [0..n-1].
249 void cullPoints (int n
, dReal p
[], int m
, int i0
, int iret
[])
251 // compute the centroid of the polygon in cx,cy
259 cx
= REAL(0.5)*(p
[0] + p
[2]);
260 cy
= REAL(0.5)*(p
[1] + p
[3]);
266 for (i
=0; i
<(n
-1); i
++) {
267 q
= p
[i
*2]*p
[i
*2+3] - p
[i
*2+2]*p
[i
*2+1];
269 cx
+= q
*(p
[i
*2]+p
[i
*2+2]);
270 cy
+= q
*(p
[i
*2+1]+p
[i
*2+3]);
272 q
= p
[n
*2-2]*p
[1] - p
[0]*p
[n
*2-1];
273 a
= dRecip(REAL(3.0)*(a
+q
));
274 cx
= a
*(cx
+ q
*(p
[n
*2-2]+p
[0]));
275 cy
= a
*(cy
+ q
*(p
[n
*2-1]+p
[1]));
278 // compute the angle of each point w.r.t. the centroid
280 for (i
=0; i
<n
; i
++) A
[i
] = dAtan2(p
[i
*2+1]-cy
,p
[i
*2]-cx
);
282 // search for points that have angles closest to A[i0] + i*(2*pi/m).
284 for (i
=0; i
<n
; i
++) avail
[i
] = 1;
288 for (j
=1; j
<m
; j
++) {
289 a
= (dReal
)(dReal(j
)*(2*M_PI
/m
) + A
[i0
]);
290 if (a
> M_PI
) a
-= (dReal
)(2*M_PI
);
291 dReal maxdiff
=1e9
,diff
;
293 *iret
= i0
; // iret is not allowed to keep this value
295 for (i
=0; i
<n
; i
++) {
297 diff
= dFabs (A
[i
]-a
);
298 if (diff
> M_PI
) diff
= (dReal
) (2*M_PI
- diff
);
299 if (diff
< maxdiff
) {
306 dIASSERT (*iret
!= i0
); // ensure iret got set
314 // given two boxes (p1,R1,side1) and (p2,R2,side2), collide them together and
315 // generate contact points. this returns 0 if there is no contact otherwise
316 // it returns the number of contacts generated.
317 // `normal' returns the contact normal.
318 // `depth' returns the maximum penetration depth along that normal.
319 // `return_code' returns a number indicating the type of contact that was
321 // 1,2,3 = box 2 intersects with a face of box 1
322 // 4,5,6 = box 1 intersects with a face of box 2
323 // 7..15 = edge-edge contact
324 // `maxc' is the maximum number of contacts allowed to be generated, i.e.
325 // the size of the `contact' array.
326 // `contact' and `skip' are the contact array information provided to the
327 // collision functions. this function only fills in the position and depth
331 int dBoxBox (const dVector3 p1
, const dMatrix3 R1
,
332 const dVector3 side1
, const dVector3 p2
,
333 const dMatrix3 R2
, const dVector3 side2
,
334 dVector3 normal
, dReal
*depth
, int *return_code
,
335 int flags
, dContactGeom
*contact
, int skip
)
337 const dReal fudge_factor
= REAL(1.05);
338 dVector3 p
,pp
,normalC
={0,0,0};
339 const dReal
*normalR
= 0;
340 dReal A
[3],B
[3],R11
,R12
,R13
,R21
,R22
,R23
,R31
,R32
,R33
,
341 Q11
,Q12
,Q13
,Q21
,Q22
,Q23
,Q31
,Q32
,Q33
,s
,s2
,l
,expr1_val
;
342 int i
,j
,invert_normal
,code
;
344 // get vector from centers of box 1 to box 2, relative to box 1
345 p
[0] = p2
[0] - p1
[0];
346 p
[1] = p2
[1] - p1
[1];
347 p
[2] = p2
[2] - p1
[2];
348 dMultiply1_331 (pp
,R1
,p
); // get pp = p relative to body 1
350 // get side lengths / 2
351 A
[0] = side1
[0]*REAL(0.5);
352 A
[1] = side1
[1]*REAL(0.5);
353 A
[2] = side1
[2]*REAL(0.5);
354 B
[0] = side2
[0]*REAL(0.5);
355 B
[1] = side2
[1]*REAL(0.5);
356 B
[2] = side2
[2]*REAL(0.5);
358 // Rij is R1'*R2, i.e. the relative rotation between R1 and R2
359 R11
= dCalcVectorDot3_44(R1
+0,R2
+0); R12
= dCalcVectorDot3_44(R1
+0,R2
+1); R13
= dCalcVectorDot3_44(R1
+0,R2
+2);
360 R21
= dCalcVectorDot3_44(R1
+1,R2
+0); R22
= dCalcVectorDot3_44(R1
+1,R2
+1); R23
= dCalcVectorDot3_44(R1
+1,R2
+2);
361 R31
= dCalcVectorDot3_44(R1
+2,R2
+0); R32
= dCalcVectorDot3_44(R1
+2,R2
+1); R33
= dCalcVectorDot3_44(R1
+2,R2
+2);
363 Q11
= dFabs(R11
); Q12
= dFabs(R12
); Q13
= dFabs(R13
);
364 Q21
= dFabs(R21
); Q22
= dFabs(R22
); Q23
= dFabs(R23
);
365 Q31
= dFabs(R31
); Q32
= dFabs(R32
); Q33
= dFabs(R33
);
367 // for all 15 possible separating axes:
368 // * see if the axis separates the boxes. if so, return 0.
369 // * find the depth of the penetration along the separating axis (s2)
370 // * if this is the largest depth so far, record it.
371 // the normal vector will be set to the separating axis with the smallest
372 // depth. note: normalR is set to point to a column of R1 or R2 if that is
373 // the smallest depth normal so far. otherwise normalR is 0 and normalC is
374 // set to a vector relative to body 1. invert_normal is 1 if the sign of
375 // the normal should be flipped.
378 #define TST(expr1,expr2,norm,cc) \
379 expr1_val = (expr1); /* Avoid duplicate evaluation of expr1 */ \
380 s2 = dFabs(expr1_val) - (expr2); \
381 if (s2 > 0) return 0; \
385 invert_normal = ((expr1_val) < 0); \
387 if (flags & CONTACTS_UNIMPORTANT) break; \
394 // separating axis = u1,u2,u3
395 TST (pp
[0],(A
[0] + B
[0]*Q11
+ B
[1]*Q12
+ B
[2]*Q13
),R1
+0,1);
396 TST (pp
[1],(A
[1] + B
[0]*Q21
+ B
[1]*Q22
+ B
[2]*Q23
),R1
+1,2);
397 TST (pp
[2],(A
[2] + B
[0]*Q31
+ B
[1]*Q32
+ B
[2]*Q33
),R1
+2,3);
399 // separating axis = v1,v2,v3
400 TST (dCalcVectorDot3_41(R2
+0,p
),(A
[0]*Q11
+ A
[1]*Q21
+ A
[2]*Q31
+ B
[0]),R2
+0,4);
401 TST (dCalcVectorDot3_41(R2
+1,p
),(A
[0]*Q12
+ A
[1]*Q22
+ A
[2]*Q32
+ B
[1]),R2
+1,5);
402 TST (dCalcVectorDot3_41(R2
+2,p
),(A
[0]*Q13
+ A
[1]*Q23
+ A
[2]*Q33
+ B
[2]),R2
+2,6);
404 // note: cross product axes need to be scaled when s is computed.
405 // normal (n1,n2,n3) is relative to box 1.
407 #define TST(expr1,expr2,n1,n2,n3,cc) \
408 expr1_val = (expr1); /* Avoid duplicate evaluation of expr1 */ \
409 s2 = dFabs(expr1_val) - (expr2); \
410 if (s2 > 0) return 0; \
411 l = dSqrt ((n1)*(n1) + (n2)*(n2) + (n3)*(n3)); \
414 if (s2*fudge_factor > s) { \
417 normalC[0] = (n1)/l; normalC[1] = (n2)/l; normalC[2] = (n3)/l; \
418 invert_normal = ((expr1_val) < 0); \
420 if (flags & CONTACTS_UNIMPORTANT) break; \
424 // We only need to check 3 edges per box
425 // since parallel edges are equivalent.
427 // separating axis = u1 x (v1,v2,v3)
428 TST(pp
[2]*R21
-pp
[1]*R31
,(A
[1]*Q31
+A
[2]*Q21
+B
[1]*Q13
+B
[2]*Q12
),0,-R31
,R21
,7);
429 TST(pp
[2]*R22
-pp
[1]*R32
,(A
[1]*Q32
+A
[2]*Q22
+B
[0]*Q13
+B
[2]*Q11
),0,-R32
,R22
,8);
430 TST(pp
[2]*R23
-pp
[1]*R33
,(A
[1]*Q33
+A
[2]*Q23
+B
[0]*Q12
+B
[1]*Q11
),0,-R33
,R23
,9);
432 // separating axis = u2 x (v1,v2,v3)
433 TST(pp
[0]*R31
-pp
[2]*R11
,(A
[0]*Q31
+A
[2]*Q11
+B
[1]*Q23
+B
[2]*Q22
),R31
,0,-R11
,10);
434 TST(pp
[0]*R32
-pp
[2]*R12
,(A
[0]*Q32
+A
[2]*Q12
+B
[0]*Q23
+B
[2]*Q21
),R32
,0,-R12
,11);
435 TST(pp
[0]*R33
-pp
[2]*R13
,(A
[0]*Q33
+A
[2]*Q13
+B
[0]*Q22
+B
[1]*Q21
),R33
,0,-R13
,12);
437 // separating axis = u3 x (v1,v2,v3)
438 TST(pp
[1]*R11
-pp
[0]*R21
,(A
[0]*Q21
+A
[1]*Q11
+B
[1]*Q33
+B
[2]*Q32
),-R21
,R11
,0,13);
439 TST(pp
[1]*R12
-pp
[0]*R22
,(A
[0]*Q22
+A
[1]*Q12
+B
[0]*Q33
+B
[2]*Q31
),-R22
,R12
,0,14);
440 TST(pp
[1]*R13
-pp
[0]*R23
,(A
[0]*Q23
+A
[1]*Q13
+B
[0]*Q32
+B
[1]*Q31
),-R23
,R13
,0,15);
446 // if we get to this point, the boxes interpenetrate. compute the normal
447 // in global coordinates.
449 normal
[0] = normalR
[0];
450 normal
[1] = normalR
[4];
451 normal
[2] = normalR
[8];
454 dMultiply0_331 (normal
,R1
,normalC
);
457 normal
[0] = -normal
[0];
458 normal
[1] = -normal
[1];
459 normal
[2] = -normal
[2];
463 // compute contact point(s)
466 // An edge from box 1 touches an edge from box 2.
467 // find a point pa on the intersecting edge of box 1
471 for (i
=0; i
<3; i
++) pa
[i
] = p1
[i
]; // why no memcpy?
472 // Get world position of p2 into pa
473 for (j
=0; j
<3; j
++) {
474 sign
= (dCalcVectorDot3_14(normal
,R1
+j
) > 0) ? REAL(1.0) : REAL(-1.0);
475 for (i
=0; i
<3; i
++) pa
[i
] += sign
* A
[j
] * R1
[i
*4+j
];
478 // find a point pb on the intersecting edge of box 2
481 for (i
=0; i
<3; i
++) pb
[i
] = p2
[i
]; // why no memcpy?
482 // Get world position of p2 into pb
483 for (j
=0; j
<3; j
++) {
484 sign
= (dCalcVectorDot3_14(normal
,R2
+j
) > 0) ? REAL(-1.0) : REAL(1.0);
485 for (i
=0; i
<3; i
++) pb
[i
] += sign
* B
[j
] * R2
[i
*4+j
];
490 // Get direction of first edge
491 for (i
=0; i
<3; i
++) ua
[i
] = R1
[((code
)-7)/3 + i
*4];
492 // Get direction of second edge
493 for (i
=0; i
<3; i
++) ub
[i
] = R2
[((code
)-7)%3 + i
*4];
494 // Get closest points between edges (one at each)
495 dLineClosestApproach (pa
,ua
,pb
,ub
,&alpha
,&beta
);
496 for (i
=0; i
<3; i
++) pa
[i
] += ua
[i
]*alpha
;
497 for (i
=0; i
<3; i
++) pb
[i
] += ub
[i
]*beta
;
498 // Set the contact point as halfway between the 2 closest points
499 for (i
=0; i
<3; i
++) contact
[0].pos
[i
] = REAL(0.5)*(pa
[i
]+pb
[i
]);
500 contact
[0].depth
= *depth
;
505 // okay, we have a face-something intersection (because the separating
506 // axis is perpendicular to a face). define face 'a' to be the reference
507 // face (i.e. the normal vector is perpendicular to this) and face 'b' to be
508 // the incident face (the closest face of the other box).
509 // Note: Unmodified parameter values are being used here
510 const dReal
*Ra
,*Rb
,*pa
,*pb
,*Sa
,*Sb
;
511 if (code
<= 3) { // One of the faces of box 1 is the reference face
512 Ra
= R1
; // Rotation of 'a'
513 Rb
= R2
; // Rotation of 'b'
514 pa
= p1
; // Center (location) of 'a'
515 pb
= p2
; // Center (location) of 'b'
516 Sa
= A
; // Side Lenght of 'a'
517 Sb
= B
; // Side Lenght of 'b'
519 else { // One of the faces of box 2 is the reference face
520 Ra
= R2
; // Rotation of 'a'
521 Rb
= R1
; // Rotation of 'b'
522 pa
= p2
; // Center (location) of 'a'
523 pb
= p1
; // Center (location) of 'b'
524 Sa
= B
; // Side Lenght of 'a'
525 Sb
= A
; // Side Lenght of 'b'
528 // nr = normal vector of reference face dotted with axes of incident box.
529 // anr = absolute values of nr.
531 The normal is flipped if necessary so it always points outward from box 'a',
532 box 'b' is thus always the incident box
534 dVector3 normal2
,nr
,anr
;
536 normal2
[0] = normal
[0];
537 normal2
[1] = normal
[1];
538 normal2
[2] = normal
[2];
541 normal2
[0] = -normal
[0];
542 normal2
[1] = -normal
[1];
543 normal2
[2] = -normal
[2];
545 // Rotate normal2 in incident box opposite direction
546 dMultiply1_331 (nr
,Rb
,normal2
);
547 anr
[0] = dFabs (nr
[0]);
548 anr
[1] = dFabs (nr
[1]);
549 anr
[2] = dFabs (nr
[2]);
551 // find the largest compontent of anr: this corresponds to the normal
552 // for the incident face. the other axis numbers of the incident face
553 // are stored in a1,a2.
555 if (anr
[1] > anr
[0]) {
556 if (anr
[1] > anr
[2]) {
568 if (anr
[0] > anr
[2]) {
580 // compute center point of incident face, in reference-face coordinates
583 for (i
=0; i
<3; i
++) center
[i
] = pb
[i
] - pa
[i
] + Sb
[lanr
] * Rb
[i
*4+lanr
];
586 for (i
=0; i
<3; i
++) center
[i
] = pb
[i
] - pa
[i
] - Sb
[lanr
] * Rb
[i
*4+lanr
];
589 // find the normal and non-normal axis numbers of the reference box
590 int codeN
,code1
,code2
;
591 if (code
<= 3) codeN
= code
-1; else codeN
= code
-4;
605 // find the four corners of the incident face, in reference-face coordinates
606 dReal quad
[8]; // 2D coordinate of incident face (x,y pairs)
607 dReal c1
,c2
,m11
,m12
,m21
,m22
;
608 c1
= dCalcVectorDot3_14 (center
,Ra
+code1
);
609 c2
= dCalcVectorDot3_14 (center
,Ra
+code2
);
610 // optimize this? - we have already computed this data above, but it is not
611 // stored in an easy-to-index format. for now it's quicker just to recompute
612 // the four dot products.
613 m11
= dCalcVectorDot3_44 (Ra
+code1
,Rb
+a1
);
614 m12
= dCalcVectorDot3_44 (Ra
+code1
,Rb
+a2
);
615 m21
= dCalcVectorDot3_44 (Ra
+code2
,Rb
+a1
);
616 m22
= dCalcVectorDot3_44 (Ra
+code2
,Rb
+a2
);
618 dReal k1
= m11
*Sb
[a1
];
619 dReal k2
= m21
*Sb
[a1
];
620 dReal k3
= m12
*Sb
[a2
];
621 dReal k4
= m22
*Sb
[a2
];
622 quad
[0] = c1
- k1
- k3
;
623 quad
[1] = c2
- k2
- k4
;
624 quad
[2] = c1
- k1
+ k3
;
625 quad
[3] = c2
- k2
+ k4
;
626 quad
[4] = c1
+ k1
+ k3
;
627 quad
[5] = c2
+ k2
+ k4
;
628 quad
[6] = c1
+ k1
- k3
;
629 quad
[7] = c2
+ k2
- k4
;
632 // find the size of the reference face
637 // intersect the incident and reference faces
639 int n
= intersectRectQuad (rect
,quad
,ret
);
640 if (n
< 1) return 0; // this should never happen
642 // convert the intersection points into reference-face coordinates,
643 // and compute the contact position and depth for each point. only keep
644 // those points that have a positive (penetrating) depth. delete points in
645 // the 'ret' array as necessary so that 'point' and 'ret' correspond.
646 dReal point
[3*8]; // penetrating contact points
647 dReal dep
[8]; // depths for those points
648 dReal det1
= dRecip(m11
*m22
- m12
*m21
);
653 int cnum
= 0; // number of penetrating contact points found
654 for (j
=0; j
< n
; j
++) {
655 dReal k1
= m22
*(ret
[j
*2]-c1
) - m12
*(ret
[j
*2+1]-c2
);
656 dReal k2
= -m21
*(ret
[j
*2]-c1
) + m11
*(ret
[j
*2+1]-c2
);
657 for (i
=0; i
<3; i
++) point
[cnum
*3+i
] =
658 center
[i
] + k1
*Rb
[i
*4+a1
] + k2
*Rb
[i
*4+a2
];
659 dep
[cnum
] = Sa
[codeN
] - dCalcVectorDot3(normal2
,point
+cnum
*3);
660 if (dep
[cnum
] >= 0) {
661 ret
[cnum
*2] = ret
[j
*2];
662 ret
[cnum
*2+1] = ret
[j
*2+1];
664 if ((cnum
| CONTACTS_UNIMPORTANT
) == (flags
& (NUMC_MASK
| CONTACTS_UNIMPORTANT
))) {
670 return 0; // this should not happen, yet does at times (demo_plane2d single precision).
673 // we can't generate more contacts than we actually have
674 int maxc
= flags
& NUMC_MASK
;
675 if (maxc
> cnum
) maxc
= cnum
;
676 if (maxc
< 1) maxc
= 1; // Even though max count must not be zero this check is kept for backward compatibility as this is a public function
679 // we have less contacts than we need, so we use them all
680 for (j
=0; j
< cnum
; j
++) {
681 dContactGeom
*con
= CONTACT(contact
,skip
*j
);
682 for (i
=0; i
<3; i
++) con
->pos
[i
] = point
[j
*3+i
] + pa
[i
];
687 dIASSERT(!(flags
& CONTACTS_UNIMPORTANT
)); // cnum should be generated not greater than maxc so that "then" clause is executed
688 // we have more contacts than are wanted, some of them must be culled.
689 // find the deepest point, it is always the first contact.
691 dReal maxdepth
= dep
[0];
692 for (i
=1; i
<cnum
; i
++) {
693 if (dep
[i
] > maxdepth
) {
700 cullPoints (cnum
,ret
,maxc
,i1
,iret
);
702 for (j
=0; j
< maxc
; j
++) {
703 dContactGeom
*con
= CONTACT(contact
,skip
*j
);
704 for (i
=0; i
<3; i
++) con
->pos
[i
] = point
[iret
[j
]*3+i
] + pa
[i
];
705 con
->depth
= dep
[iret
[j
]];
716 int dCollideBoxBox (dxGeom
*o1
, dxGeom
*o2
, int flags
,
717 dContactGeom
*contact
, int skip
)
719 dIASSERT (skip
>= (int)sizeof(dContactGeom
));
720 dIASSERT (o1
->type
== dBoxClass
);
721 dIASSERT (o2
->type
== dBoxClass
);
722 dIASSERT ((flags
& NUMC_MASK
) >= 1);
727 dxBox
*b1
= (dxBox
*) o1
;
728 dxBox
*b2
= (dxBox
*) o2
;
729 int num
= dBoxBox (o1
->final_posr
->pos
,o1
->final_posr
->R
,b1
->side
, o2
->final_posr
->pos
,o2
->final_posr
->R
,b2
->side
,
730 normal
,&depth
,&code
,flags
,contact
,skip
);
731 for (int i
=0; i
<num
; i
++) {
732 dContactGeom
*currContact
= CONTACT(contact
,i
*skip
);
733 currContact
->normal
[0] = -normal
[0];
734 currContact
->normal
[1] = -normal
[1];
735 currContact
->normal
[2] = -normal
[2];
736 currContact
->g1
= o1
;
737 currContact
->g2
= o2
;
738 currContact
->side1
= -1;
739 currContact
->side2
= -1;
745 int dCollideBoxPlane (dxGeom
*o1
, dxGeom
*o2
,
746 int flags
, dContactGeom
*contact
, int skip
)
748 dIASSERT (skip
>= (int)sizeof(dContactGeom
));
749 dIASSERT (o1
->type
== dBoxClass
);
750 dIASSERT (o2
->type
== dPlaneClass
);
751 dIASSERT ((flags
& NUMC_MASK
) >= 1);
753 dxBox
*box
= (dxBox
*) o1
;
754 dxPlane
*plane
= (dxPlane
*) o2
;
763 //@@@ problem: using 4-vector (plane->p) as 3-vector (normal).
764 const dReal
*R
= o1
->final_posr
->R
; // rotation of box
765 const dReal
*n
= plane
->p
; // normal vector
767 // project sides lengths along normal vector, get absolute values
768 dReal Q1
= dCalcVectorDot3_14(n
,R
+0);
769 dReal Q2
= dCalcVectorDot3_14(n
,R
+1);
770 dReal Q3
= dCalcVectorDot3_14(n
,R
+2);
771 dReal A1
= box
->side
[0] * Q1
;
772 dReal A2
= box
->side
[1] * Q2
;
773 dReal A3
= box
->side
[2] * Q3
;
774 dReal B1
= dFabs(A1
);
775 dReal B2
= dFabs(A2
);
776 dReal B3
= dFabs(A3
);
779 dReal depth
= plane
->p
[3] + REAL(0.5)*(B1
+B2
+B3
) - dCalcVectorDot3(n
,o1
->final_posr
->pos
);
780 if (depth
< 0) return 0;
782 // find number of contacts requested
783 int maxc
= flags
& NUMC_MASK
;
784 // if (maxc < 1) maxc = 1; // an assertion is made on entry
785 if (maxc
> 3) maxc
= 3; // not more than 3 contacts per box allowed
787 // find deepest point
789 p
[0] = o1
->final_posr
->pos
[0];
790 p
[1] = o1
->final_posr
->pos
[1];
791 p
[2] = o1
->final_posr
->pos
[2];
793 p[0] op REAL(0.5)*box->side[i] * R[0+i]; \
794 p[1] op REAL(0.5)*box->side[i] * R[4+i]; \
795 p[2] op REAL(0.5)*box->side[i] * R[8+i];
796 #define BAR(i,iinc) if (A ## iinc > 0) { FOO(i,-=) } else { FOO(i,+=) }
803 // the deepest point is the first contact point
804 contact
->pos
[0] = p
[0];
805 contact
->pos
[1] = p
[1];
806 contact
->pos
[2] = p
[2];
807 contact
->normal
[0] = n
[0];
808 contact
->normal
[1] = n
[1];
809 contact
->normal
[2] = n
[2];
810 contact
->depth
= depth
;
811 ret
= 1; // ret is number of contact points found so far
812 if (maxc
== 1) goto done
;
814 // get the second and third contact points by starting from `p' and going
815 // along the two sides with the smallest projected length.
817 #define FOO(i,j,op) \
818 CONTACT(contact,i*skip)->pos[0] = p[0] op box->side[j] * R[0+j]; \
819 CONTACT(contact,i*skip)->pos[1] = p[1] op box->side[j] * R[4+j]; \
820 CONTACT(contact,i*skip)->pos[2] = p[2] op box->side[j] * R[8+j];
821 #define BAR(ctact,side,sideinc) \
822 depth -= B ## sideinc; \
823 if (depth < 0) goto done; \
824 if (A ## sideinc > 0) { FOO(ctact,side,+); } else { FOO(ctact,side,-); } \
825 CONTACT(contact,ctact*skip)->depth = depth; \
828 CONTACT(contact
,skip
)->normal
[0] = n
[0];
829 CONTACT(contact
,skip
)->normal
[1] = n
[1];
830 CONTACT(contact
,skip
)->normal
[2] = n
[2];
832 CONTACT(contact
,2*skip
)->normal
[0] = n
[0];
833 CONTACT(contact
,2*skip
)->normal
[1] = n
[1];
834 CONTACT(contact
,2*skip
)->normal
[2] = n
[2];
838 if (B3
< B1
) goto use_side_3
; else {
839 BAR(1,0,1); // use side 1
840 if (maxc
== 2) goto done
;
841 if (B2
< B3
) goto contact2_2
; else goto contact2_3
;
846 use_side_3
: // use side 3
848 if (maxc
== 2) goto done
;
849 if (B1
< B2
) goto contact2_1
; else goto contact2_2
;
852 BAR(1,1,2); // use side 2
853 if (maxc
== 2) goto done
;
854 if (B1
< B3
) goto contact2_1
; else goto contact2_3
;
858 contact2_1
: BAR(2,0,1); goto done
;
859 contact2_2
: BAR(2,1,2); goto done
;
860 contact2_3
: BAR(2,2,3); goto done
;
865 for (int i
=0; i
<ret
; i
++) {
866 dContactGeom
*currContact
= CONTACT(contact
,i
*skip
);
867 currContact
->g1
= o1
;
868 currContact
->g2
= o2
;
869 currContact
->side1
= -1;
870 currContact
->side2
= -1;