Changed: Header inclusion order corrected
[ode.git] / ode / src / box.cpp
blob72601b0400ea54bd8e7edadb333ba45136c991dd
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 *************************************************************************/
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>
37 #include "config.h"
38 #include "collision_kernel.h"
39 #include "collision_std.h"
40 #include "collision_util.h"
42 #ifdef _MSC_VER
43 #pragma warning(disable:4291) // for VC++, no complaints about "no matching operator delete found"
44 #endif
46 //****************************************************************************
47 // box public API
49 dxBox::dxBox (dSpaceID space, dReal lx, dReal ly, dReal lz) : dxGeom (space,1)
51 dAASSERT (lx >= 0 && ly >= 0 && lz >= 0);
52 type = dBoxClass;
53 side[0] = lx;
54 side[1] = ly;
55 side[2] = lz;
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;
91 b->side[0] = lx;
92 b->side[1] = ly;
93 b->side[2] = lz;
94 b->updateZeroSizedFlag(!lx || !ly || !lz);
95 dGeomMoved (g);
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");
112 g->recomputePosr();
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)
119 dVector3 p,q;
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
133 dReal dist[6];
134 int i;
136 bool inside = true;
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)) {
145 inside = false;
149 // If point is inside the box, the depth is the smallest positive distance
150 // to any side
152 if (inside) {
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
190 // chopped) polygons
191 int nq=4,nr;
192 dReal buffer[16];
193 dReal *q = p;
194 dReal *r = ret;
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]
199 dReal *pq = q;
200 dReal *pr = r;
201 nr = 0;
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
206 pr[0] = pq[0];
207 pr[1] = pq[1];
208 pr += 2;
209 nr++;
210 if (nr & 8) {
211 q = r;
212 goto done;
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];
221 pr += 2;
222 nr++;
223 if (nr & 8) {
224 q = r;
225 goto done;
228 pq += 2;
230 q = r;
231 r = (q==ret) ? buffer : ret;
232 nq = nr;
235 done:
236 if (q != ret) memcpy (ret,q,nr*2*sizeof(dReal));
237 return nr;
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
252 int i,j;
253 dReal a,cx,cy,q;
254 if (n==1) {
255 cx = p[0];
256 cy = p[1];
258 else if (n==2) {
259 cx = REAL(0.5)*(p[0] + p[2]);
260 cy = REAL(0.5)*(p[1] + p[3]);
262 else {
263 a = 0;
264 cx = 0;
265 cy = 0;
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];
268 a += q;
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
279 dReal A[8];
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).
283 int avail[8];
284 for (i=0; i<n; i++) avail[i] = 1;
285 avail[i0] = 0;
286 iret[0] = i0;
287 iret++;
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;
292 #ifndef dNODEBUG
293 *iret = i0; // iret is not allowed to keep this value
294 #endif
295 for (i=0; i<n; i++) {
296 if (avail[i]) {
297 diff = dFabs (A[i]-a);
298 if (diff > M_PI) diff = (dReal) (2*M_PI - diff);
299 if (diff < maxdiff) {
300 maxdiff = diff;
301 *iret = i;
305 #ifndef dNODEBUG
306 dIASSERT (*iret != i0); // ensure iret got set
307 #endif
308 avail[*iret] = 0;
309 iret++;
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
320 // detected:
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
328 // fields.
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.
377 do {
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; \
382 if (s2 > s) { \
383 s = s2; \
384 normalR = norm; \
385 invert_normal = ((expr1_val) < 0); \
386 code = (cc); \
387 if (flags & CONTACTS_UNIMPORTANT) break; \
390 s = -dInfinity;
391 invert_normal = 0;
392 code = 0;
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.
406 #undef TST
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)); \
412 if (l > 0) { \
413 s2 /= l; \
414 if (s2*fudge_factor > s) { \
415 s = s2; \
416 normalR = 0; \
417 normalC[0] = (n1)/l; normalC[1] = (n2)/l; normalC[2] = (n3)/l; \
418 invert_normal = ((expr1_val) < 0); \
419 code = (cc); \
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);
441 #undef TST
442 } while (0);
444 if (!code) return 0;
446 // if we get to this point, the boxes interpenetrate. compute the normal
447 // in global coordinates.
448 if (normalR) {
449 normal[0] = normalR[0];
450 normal[1] = normalR[4];
451 normal[2] = normalR[8];
453 else {
454 dMultiply0_331 (normal,R1,normalC);
456 if (invert_normal) {
457 normal[0] = -normal[0];
458 normal[1] = -normal[1];
459 normal[2] = -normal[2];
461 *depth = -s;
463 // compute contact point(s)
465 if (code > 6) {
466 // An edge from box 1 touches an edge from box 2.
467 // find a point pa on the intersecting edge of box 1
468 dVector3 pa;
469 dReal sign;
470 // Copy p1 into pa
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
479 dVector3 pb;
480 // Copy p2 into pb
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];
488 dReal alpha,beta;
489 dVector3 ua,ub;
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;
501 *return_code = code;
502 return 1;
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;
535 if (code <= 3) {
536 normal2[0] = normal[0];
537 normal2[1] = normal[1];
538 normal2[2] = normal[2];
540 else {
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.
554 int lanr,a1,a2;
555 if (anr[1] > anr[0]) {
556 if (anr[1] > anr[2]) {
557 a1 = 0;
558 lanr = 1;
559 a2 = 2;
561 else {
562 a1 = 0;
563 a2 = 1;
564 lanr = 2;
567 else {
568 if (anr[0] > anr[2]) {
569 lanr = 0;
570 a1 = 1;
571 a2 = 2;
573 else {
574 a1 = 0;
575 a2 = 1;
576 lanr = 2;
580 // compute center point of incident face, in reference-face coordinates
581 dVector3 center;
582 if (nr[lanr] < 0) {
583 for (i=0; i<3; i++) center[i] = pb[i] - pa[i] + Sb[lanr] * Rb[i*4+lanr];
585 else {
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;
592 if (codeN==0) {
593 code1 = 1;
594 code2 = 2;
596 else if (codeN==1) {
597 code1 = 0;
598 code2 = 2;
600 else {
601 code1 = 0;
602 code2 = 1;
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
633 dReal rect[2];
634 rect[0] = Sa[code1];
635 rect[1] = Sa[code2];
637 // intersect the incident and reference faces
638 dReal ret[16];
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);
649 m11 *= det1;
650 m12 *= det1;
651 m21 *= det1;
652 m22 *= det1;
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];
663 cnum++;
664 if ((cnum | CONTACTS_UNIMPORTANT) == (flags & (NUMC_MASK | CONTACTS_UNIMPORTANT))) {
665 break;
669 if (cnum < 1) {
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
678 if (cnum <= maxc) {
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];
683 con->depth = dep[j];
686 else {
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.
690 int i1 = 0;
691 dReal maxdepth = dep[0];
692 for (i=1; i<cnum; i++) {
693 if (dep[i] > maxdepth) {
694 maxdepth = dep[i];
695 i1 = i;
699 int iret[8];
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]];
707 cnum = maxc;
710 *return_code = code;
711 return cnum;
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);
724 dVector3 normal;
725 dReal depth;
726 int code;
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;
741 return num;
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;
756 contact->g1 = o1;
757 contact->g2 = o2;
758 contact->side1 = -1;
759 contact->side2 = -1;
761 int ret = 0;
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);
778 // early exit test
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
788 dVector3 p;
789 p[0] = o1->final_posr->pos[0];
790 p[1] = o1->final_posr->pos[1];
791 p[2] = o1->final_posr->pos[2];
792 #define FOO(i,op) \
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,+=) }
797 BAR(0,1);
798 BAR(1,2);
799 BAR(2,3);
800 #undef FOO
801 #undef BAR
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; \
826 ret++;
828 CONTACT(contact,skip)->normal[0] = n[0];
829 CONTACT(contact,skip)->normal[1] = n[1];
830 CONTACT(contact,skip)->normal[2] = n[2];
831 if (maxc == 3) {
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];
837 if (B1 < B2) {
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;
844 else {
845 if (B3 < B2) {
846 use_side_3: // use side 3
847 BAR(1,2,3);
848 if (maxc == 2) goto done;
849 if (B1 < B2) goto contact2_1; else goto contact2_2;
851 else {
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;
861 #undef FOO
862 #undef BAR
864 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;
872 return ret;