Changed: Header inclusion order corrected
[ode.git] / ode / src / collision_util.cpp
blobbf8da01634acec4b8d46801049e2fc86cf988108
1 /*************************************************************************
2 * *
3 * Open Dynamics Engine, Copyright (C) 2001,2002 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 some useful collision utility stuff. this includes some API utility
26 functions that are defined in the public header files.
30 #include <ode/common.h>
31 #include <ode/collision.h>
32 #include <ode/odemath.h>
33 #include "config.h"
34 #include "collision_util.h"
36 //****************************************************************************
38 int dCollideSpheres (dVector3 p1, dReal r1,
39 dVector3 p2, dReal r2, dContactGeom *c)
41 // printf ("d=%.2f (%.2f %.2f %.2f) (%.2f %.2f %.2f) r1=%.2f r2=%.2f\n",
42 // d,p1[0],p1[1],p1[2],p2[0],p2[1],p2[2],r1,r2);
44 dReal d = dCalcPointsDistance3(p1,p2);
45 if (d > (r1 + r2)) return 0;
46 if (d <= 0) {
47 c->pos[0] = p1[0];
48 c->pos[1] = p1[1];
49 c->pos[2] = p1[2];
50 c->normal[0] = 1;
51 c->normal[1] = 0;
52 c->normal[2] = 0;
53 c->depth = r1 + r2;
55 else {
56 dReal d1 = dRecip (d);
57 c->normal[0] = (p1[0]-p2[0])*d1;
58 c->normal[1] = (p1[1]-p2[1])*d1;
59 c->normal[2] = (p1[2]-p2[2])*d1;
60 dReal k = REAL(0.5) * (r2 - r1 - d);
61 c->pos[0] = p1[0] + c->normal[0]*k;
62 c->pos[1] = p1[1] + c->normal[1]*k;
63 c->pos[2] = p1[2] + c->normal[2]*k;
64 c->depth = r1 + r2 - d;
66 return 1;
70 void dLineClosestApproach (const dVector3 pa, const dVector3 ua,
71 const dVector3 pb, const dVector3 ub,
72 dReal *alpha, dReal *beta)
74 dVector3 p;
75 p[0] = pb[0] - pa[0];
76 p[1] = pb[1] - pa[1];
77 p[2] = pb[2] - pa[2];
78 dReal uaub = dCalcVectorDot3(ua,ub);
79 dReal q1 = dCalcVectorDot3(ua,p);
80 dReal q2 = -dCalcVectorDot3(ub,p);
81 dReal d = 1-uaub*uaub;
82 if (d <= REAL(0.0001)) {
83 // @@@ this needs to be made more robust
84 *alpha = 0;
85 *beta = 0;
87 else {
88 d = dRecip(d);
89 *alpha = (q1 + uaub*q2)*d;
90 *beta = (uaub*q1 + q2)*d;
95 // given two line segments A and B with endpoints a1-a2 and b1-b2, return the
96 // points on A and B that are closest to each other (in cp1 and cp2).
97 // in the case of parallel lines where there are multiple solutions, a
98 // solution involving the endpoint of at least one line will be returned.
99 // this will work correctly for zero length lines, e.g. if a1==a2 and/or
100 // b1==b2.
102 // the algorithm works by applying the voronoi clipping rule to the features
103 // of the line segments. the three features of each line segment are the two
104 // endpoints and the line between them. the voronoi clipping rule states that,
105 // for feature X on line A and feature Y on line B, the closest points PA and
106 // PB between X and Y are globally the closest points if PA is in V(Y) and
107 // PB is in V(X), where V(X) is the voronoi region of X.
109 void dClosestLineSegmentPoints (const dVector3 a1, const dVector3 a2,
110 const dVector3 b1, const dVector3 b2,
111 dVector3 cp1, dVector3 cp2)
113 dVector3 a1a2,b1b2,a1b1,a1b2,a2b1,a2b2,n;
114 dReal la,lb,k,da1,da2,da3,da4,db1,db2,db3,db4,det;
116 #define SET2(a,b) a[0]=b[0]; a[1]=b[1]; a[2]=b[2];
117 #define SET3(a,b,op,c) a[0]=b[0] op c[0]; a[1]=b[1] op c[1]; a[2]=b[2] op c[2];
119 // check vertex-vertex features
121 SET3 (a1a2,a2,-,a1);
122 SET3 (b1b2,b2,-,b1);
123 SET3 (a1b1,b1,-,a1);
124 da1 = dCalcVectorDot3(a1a2,a1b1);
125 db1 = dCalcVectorDot3(b1b2,a1b1);
126 if (da1 <= 0 && db1 >= 0) {
127 SET2 (cp1,a1);
128 SET2 (cp2,b1);
129 return;
132 SET3 (a1b2,b2,-,a1);
133 da2 = dCalcVectorDot3(a1a2,a1b2);
134 db2 = dCalcVectorDot3(b1b2,a1b2);
135 if (da2 <= 0 && db2 <= 0) {
136 SET2 (cp1,a1);
137 SET2 (cp2,b2);
138 return;
141 SET3 (a2b1,b1,-,a2);
142 da3 = dCalcVectorDot3(a1a2,a2b1);
143 db3 = dCalcVectorDot3(b1b2,a2b1);
144 if (da3 >= 0 && db3 >= 0) {
145 SET2 (cp1,a2);
146 SET2 (cp2,b1);
147 return;
150 SET3 (a2b2,b2,-,a2);
151 da4 = dCalcVectorDot3(a1a2,a2b2);
152 db4 = dCalcVectorDot3(b1b2,a2b2);
153 if (da4 >= 0 && db4 <= 0) {
154 SET2 (cp1,a2);
155 SET2 (cp2,b2);
156 return;
159 // check edge-vertex features.
160 // if one or both of the lines has zero length, we will never get to here,
161 // so we do not have to worry about the following divisions by zero.
163 la = dCalcVectorDot3(a1a2,a1a2);
164 if (da1 >= 0 && da3 <= 0) {
165 k = da1 / la;
166 SET3 (n,a1b1,-,k*a1a2);
167 if (dCalcVectorDot3(b1b2,n) >= 0) {
168 SET3 (cp1,a1,+,k*a1a2);
169 SET2 (cp2,b1);
170 return;
174 if (da2 >= 0 && da4 <= 0) {
175 k = da2 / la;
176 SET3 (n,a1b2,-,k*a1a2);
177 if (dCalcVectorDot3(b1b2,n) <= 0) {
178 SET3 (cp1,a1,+,k*a1a2);
179 SET2 (cp2,b2);
180 return;
184 lb = dCalcVectorDot3(b1b2,b1b2);
185 if (db1 <= 0 && db2 >= 0) {
186 k = -db1 / lb;
187 SET3 (n,-a1b1,-,k*b1b2);
188 if (dCalcVectorDot3(a1a2,n) >= 0) {
189 SET2 (cp1,a1);
190 SET3 (cp2,b1,+,k*b1b2);
191 return;
195 if (db3 <= 0 && db4 >= 0) {
196 k = -db3 / lb;
197 SET3 (n,-a2b1,-,k*b1b2);
198 if (dCalcVectorDot3(a1a2,n) <= 0) {
199 SET2 (cp1,a2);
200 SET3 (cp2,b1,+,k*b1b2);
201 return;
205 // it must be edge-edge
207 k = dCalcVectorDot3(a1a2,b1b2);
208 det = la*lb - k*k;
209 if (det <= 0) {
210 // this should never happen, but just in case...
211 SET2(cp1,a1);
212 SET2(cp2,b1);
213 return;
215 det = dRecip (det);
216 dReal alpha = (lb*da1 - k*db1) * det;
217 dReal beta = ( k*da1 - la*db1) * det;
218 SET3 (cp1,a1,+,alpha*a1a2);
219 SET3 (cp2,b1,+,beta*b1b2);
221 # undef SET2
222 # undef SET3
226 // a simple root finding algorithm is used to find the value of 't' that
227 // satisfies:
228 // d|D(t)|^2/dt = 0
229 // where:
230 // |D(t)| = |p(t)-b(t)|
231 // where p(t) is a point on the line parameterized by t:
232 // p(t) = p1 + t*(p2-p1)
233 // and b(t) is that same point clipped to the boundary of the box. in box-
234 // relative coordinates d|D(t)|^2/dt is the sum of three x,y,z components
235 // each of which looks like this:
237 // t_lo /
238 // ______/ -->t
239 // / t_hi
240 // /
242 // t_lo and t_hi are the t values where the line passes through the planes
243 // corresponding to the sides of the box. the algorithm computes d|D(t)|^2/dt
244 // in a piecewise fashion from t=0 to t=1, stopping at the point where
245 // d|D(t)|^2/dt crosses from negative to positive.
247 void dClosestLineBoxPoints (const dVector3 p1, const dVector3 p2,
248 const dVector3 c, const dMatrix3 R,
249 const dVector3 side,
250 dVector3 lret, dVector3 bret)
252 int i;
254 // compute the start and delta of the line p1-p2 relative to the box.
255 // we will do all subsequent computations in this box-relative coordinate
256 // system. we have to do a translation and rotation for each point.
257 dVector3 tmp,s,v;
258 tmp[0] = p1[0] - c[0];
259 tmp[1] = p1[1] - c[1];
260 tmp[2] = p1[2] - c[2];
261 dMultiply1_331 (s,R,tmp);
262 tmp[0] = p2[0] - p1[0];
263 tmp[1] = p2[1] - p1[1];
264 tmp[2] = p2[2] - p1[2];
265 dMultiply1_331 (v,R,tmp);
267 // mirror the line so that v has all components >= 0
268 dVector3 sign;
269 for (i=0; i<3; i++) {
270 if (v[i] < 0) {
271 s[i] = -s[i];
272 v[i] = -v[i];
273 sign[i] = -1;
275 else sign[i] = 1;
278 // compute v^2
279 dVector3 v2;
280 v2[0] = v[0]*v[0];
281 v2[1] = v[1]*v[1];
282 v2[2] = v[2]*v[2];
284 // compute the half-sides of the box
285 dReal h[3];
286 h[0] = REAL(0.5) * side[0];
287 h[1] = REAL(0.5) * side[1];
288 h[2] = REAL(0.5) * side[2];
290 // region is -1,0,+1 depending on which side of the box planes each
291 // coordinate is on. tanchor is the next t value at which there is a
292 // transition, or the last one if there are no more.
293 int region[3];
294 dReal tanchor[3];
296 // Denormals are a problem, because we divide by v[i], and then
297 // multiply that by 0. Alas, infinity times 0 is infinity (!)
298 // We also use v2[i], which is v[i] squared. Here's how the epsilons
299 // are chosen:
300 // float epsilon = 1.175494e-038 (smallest non-denormal number)
301 // double epsilon = 2.225074e-308 (smallest non-denormal number)
302 // For single precision, choose an epsilon such that v[i] squared is
303 // not a denormal; this is for performance.
304 // For double precision, choose an epsilon such that v[i] is not a
305 // denormal; this is for correctness. (Jon Watte on mailinglist)
307 #if defined( dSINGLE )
308 const dReal tanchor_eps = REAL(1e-19);
309 #else
310 const dReal tanchor_eps = REAL(1e-307);
311 #endif
313 // find the region and tanchor values for p1
314 for (i=0; i<3; i++) {
315 if (v[i] > tanchor_eps) {
316 if (s[i] < -h[i]) {
317 region[i] = -1;
318 tanchor[i] = (-h[i]-s[i])/v[i];
320 else {
321 region[i] = (s[i] > h[i]);
322 tanchor[i] = (h[i]-s[i])/v[i];
325 else {
326 region[i] = 0;
327 tanchor[i] = 2; // this will never be a valid tanchor
331 // compute d|d|^2/dt for t=0. if it's >= 0 then p1 is the closest point
332 dReal t=0;
333 dReal dd2dt = 0;
334 for (i=0; i<3; i++) dd2dt -= (region[i] ? v2[i] : 0) * tanchor[i];
335 if (dd2dt >= 0) goto got_answer;
337 do {
338 // find the point on the line that is at the next clip plane boundary
339 dReal next_t = 1;
340 for (i=0; i<3; i++) {
341 if (tanchor[i] > t && tanchor[i] < 1 && tanchor[i] < next_t)
342 next_t = tanchor[i];
345 // compute d|d|^2/dt for the next t
346 dReal next_dd2dt = 0;
347 for (i=0; i<3; i++) {
348 next_dd2dt += (region[i] ? v2[i] : 0) * (next_t - tanchor[i]);
351 // if the sign of d|d|^2/dt has changed, solution = the crossover point
352 if (next_dd2dt >= 0) {
353 dReal m = (next_dd2dt-dd2dt)/(next_t - t);
354 t -= dd2dt/m;
355 goto got_answer;
358 // advance to the next anchor point / region
359 for (i=0; i<3; i++) {
360 if (tanchor[i] == next_t) {
361 tanchor[i] = (h[i]-s[i])/v[i];
362 region[i]++;
365 t = next_t;
366 dd2dt = next_dd2dt;
368 while (t < 1);
369 t = 1;
371 got_answer:
373 // compute closest point on the line
374 for (i=0; i<3; i++) lret[i] = p1[i] + t*tmp[i]; // note: tmp=p2-p1
376 // compute closest point on the box
377 for (i=0; i<3; i++) {
378 tmp[i] = sign[i] * (s[i] + t*v[i]);
379 if (tmp[i] < -h[i]) tmp[i] = -h[i];
380 else if (tmp[i] > h[i]) tmp[i] = h[i];
382 dMultiply0_331 (s,R,tmp);
383 for (i=0; i<3; i++) bret[i] = s[i] + c[i];
387 // given boxes (p1,R1,side1) and (p1,R1,side1), return 1 if they intersect
388 // or 0 if not.
390 int dBoxTouchesBox (const dVector3 p1, const dMatrix3 R1,
391 const dVector3 side1, const dVector3 p2,
392 const dMatrix3 R2, const dVector3 side2)
394 // two boxes are disjoint if (and only if) there is a separating axis
395 // perpendicular to a face from one box or perpendicular to an edge from
396 // either box. the following tests are derived from:
397 // "OBB Tree: A Hierarchical Structure for Rapid Interference Detection",
398 // S.Gottschalk, M.C.Lin, D.Manocha., Proc of ACM Siggraph 1996.
400 // Rij is R1'*R2, i.e. the relative rotation between R1 and R2.
401 // Qij is abs(Rij)
402 dVector3 p,pp;
403 dReal A1,A2,A3,B1,B2,B3,R11,R12,R13,R21,R22,R23,R31,R32,R33,
404 Q11,Q12,Q13,Q21,Q22,Q23,Q31,Q32,Q33;
406 // get vector from centers of box 1 to box 2, relative to box 1
407 p[0] = p2[0] - p1[0];
408 p[1] = p2[1] - p1[1];
409 p[2] = p2[2] - p1[2];
410 dMultiply1_331 (pp,R1,p); // get pp = p relative to body 1
412 // get side lengths / 2
413 A1 = side1[0]*REAL(0.5); A2 = side1[1]*REAL(0.5); A3 = side1[2]*REAL(0.5);
414 B1 = side2[0]*REAL(0.5); B2 = side2[1]*REAL(0.5); B3 = side2[2]*REAL(0.5);
416 // for the following tests, excluding computation of Rij, in the worst case,
417 // 15 compares, 60 adds, 81 multiplies, and 24 absolutes.
418 // notation: R1=[u1 u2 u3], R2=[v1 v2 v3]
420 // separating axis = u1,u2,u3
421 R11 = dCalcVectorDot3_44(R1+0,R2+0); R12 = dCalcVectorDot3_44(R1+0,R2+1); R13 = dCalcVectorDot3_44(R1+0,R2+2);
422 Q11 = dFabs(R11); Q12 = dFabs(R12); Q13 = dFabs(R13);
423 if (dFabs(pp[0]) > (A1 + B1*Q11 + B2*Q12 + B3*Q13)) return 0;
424 R21 = dCalcVectorDot3_44(R1+1,R2+0); R22 = dCalcVectorDot3_44(R1+1,R2+1); R23 = dCalcVectorDot3_44(R1+1,R2+2);
425 Q21 = dFabs(R21); Q22 = dFabs(R22); Q23 = dFabs(R23);
426 if (dFabs(pp[1]) > (A2 + B1*Q21 + B2*Q22 + B3*Q23)) return 0;
427 R31 = dCalcVectorDot3_44(R1+2,R2+0); R32 = dCalcVectorDot3_44(R1+2,R2+1); R33 = dCalcVectorDot3_44(R1+2,R2+2);
428 Q31 = dFabs(R31); Q32 = dFabs(R32); Q33 = dFabs(R33);
429 if (dFabs(pp[2]) > (A3 + B1*Q31 + B2*Q32 + B3*Q33)) return 0;
431 // separating axis = v1,v2,v3
432 if (dFabs(dCalcVectorDot3_41(R2+0,p)) > (A1*Q11 + A2*Q21 + A3*Q31 + B1)) return 0;
433 if (dFabs(dCalcVectorDot3_41(R2+1,p)) > (A1*Q12 + A2*Q22 + A3*Q32 + B2)) return 0;
434 if (dFabs(dCalcVectorDot3_41(R2+2,p)) > (A1*Q13 + A2*Q23 + A3*Q33 + B3)) return 0;
436 // separating axis = u1 x (v1,v2,v3)
437 if (dFabs(pp[2]*R21-pp[1]*R31) > A2*Q31 + A3*Q21 + B2*Q13 + B3*Q12) return 0;
438 if (dFabs(pp[2]*R22-pp[1]*R32) > A2*Q32 + A3*Q22 + B1*Q13 + B3*Q11) return 0;
439 if (dFabs(pp[2]*R23-pp[1]*R33) > A2*Q33 + A3*Q23 + B1*Q12 + B2*Q11) return 0;
441 // separating axis = u2 x (v1,v2,v3)
442 if (dFabs(pp[0]*R31-pp[2]*R11) > A1*Q31 + A3*Q11 + B2*Q23 + B3*Q22) return 0;
443 if (dFabs(pp[0]*R32-pp[2]*R12) > A1*Q32 + A3*Q12 + B1*Q23 + B3*Q21) return 0;
444 if (dFabs(pp[0]*R33-pp[2]*R13) > A1*Q33 + A3*Q13 + B1*Q22 + B2*Q21) return 0;
446 // separating axis = u3 x (v1,v2,v3)
447 if (dFabs(pp[1]*R11-pp[0]*R21) > A1*Q21 + A2*Q11 + B2*Q33 + B3*Q32) return 0;
448 if (dFabs(pp[1]*R12-pp[0]*R22) > A1*Q22 + A2*Q12 + B1*Q33 + B3*Q31) return 0;
449 if (dFabs(pp[1]*R13-pp[0]*R23) > A1*Q23 + A2*Q13 + B1*Q32 + B2*Q31) return 0;
451 return 1;
454 //****************************************************************************
455 // other utility functions
457 void dInfiniteAABB (dxGeom *geom, dReal aabb[6])
459 aabb[0] = -dInfinity;
460 aabb[1] = dInfinity;
461 aabb[2] = -dInfinity;
462 aabb[3] = dInfinity;
463 aabb[4] = -dInfinity;
464 aabb[5] = dInfinity;
468 //****************************************************************************
469 // Helpers for Croteam's collider - by Nguyen Binh
471 int dClipEdgeToPlane( dVector3 &vEpnt0, dVector3 &vEpnt1, const dVector4& plPlane)
473 // calculate distance of edge points to plane
474 dReal fDistance0 = dPointPlaneDistance( vEpnt0 ,plPlane );
475 dReal fDistance1 = dPointPlaneDistance( vEpnt1 ,plPlane );
477 // if both points are behind the plane
478 if ( fDistance0 < 0 && fDistance1 < 0 )
480 // do nothing
481 return 0;
482 // if both points in front of the plane
484 else if ( fDistance0 > 0 && fDistance1 > 0 )
486 // accept them
487 return 1;
488 // if we have edge/plane intersection
489 } else if ((fDistance0 > 0 && fDistance1 < 0) || ( fDistance0 < 0 && fDistance1 > 0))
492 // find intersection point of edge and plane
493 dVector3 vIntersectionPoint;
494 vIntersectionPoint[0]= vEpnt0[0]-(vEpnt0[0]-vEpnt1[0])*fDistance0/(fDistance0-fDistance1);
495 vIntersectionPoint[1]= vEpnt0[1]-(vEpnt0[1]-vEpnt1[1])*fDistance0/(fDistance0-fDistance1);
496 vIntersectionPoint[2]= vEpnt0[2]-(vEpnt0[2]-vEpnt1[2])*fDistance0/(fDistance0-fDistance1);
498 // clamp correct edge to intersection point
499 if ( fDistance0 < 0 )
501 dVector3Copy(vIntersectionPoint,vEpnt0);
502 } else
504 dVector3Copy(vIntersectionPoint,vEpnt1);
506 return 1;
508 return 1;
511 // clip polygon with plane and generate new polygon points
512 void dClipPolyToPlane( const dVector3 avArrayIn[], const int ctIn,
513 dVector3 avArrayOut[], int &ctOut,
514 const dVector4 &plPlane )
516 // start with no output points
517 ctOut = 0;
519 int i0 = ctIn-1;
521 // for each edge in input polygon
522 for (int i1=0; i1<ctIn; i0=i1, i1++) {
525 // calculate distance of edge points to plane
526 dReal fDistance0 = dPointPlaneDistance( avArrayIn[i0],plPlane );
527 dReal fDistance1 = dPointPlaneDistance( avArrayIn[i1],plPlane );
529 // if first point is in front of plane
530 if( fDistance0 >= 0 ) {
531 // emit point
532 avArrayOut[ctOut][0] = avArrayIn[i0][0];
533 avArrayOut[ctOut][1] = avArrayIn[i0][1];
534 avArrayOut[ctOut][2] = avArrayIn[i0][2];
535 ctOut++;
538 // if points are on different sides
539 if( (fDistance0 > 0 && fDistance1 < 0) || ( fDistance0 < 0 && fDistance1 > 0) ) {
541 // find intersection point of edge and plane
542 dVector3 vIntersectionPoint;
543 vIntersectionPoint[0]= avArrayIn[i0][0] -
544 (avArrayIn[i0][0]-avArrayIn[i1][0])*fDistance0/(fDistance0-fDistance1);
545 vIntersectionPoint[1]= avArrayIn[i0][1] -
546 (avArrayIn[i0][1]-avArrayIn[i1][1])*fDistance0/(fDistance0-fDistance1);
547 vIntersectionPoint[2]= avArrayIn[i0][2] -
548 (avArrayIn[i0][2]-avArrayIn[i1][2])*fDistance0/(fDistance0-fDistance1);
550 // emit intersection point
551 avArrayOut[ctOut][0] = vIntersectionPoint[0];
552 avArrayOut[ctOut][1] = vIntersectionPoint[1];
553 avArrayOut[ctOut][2] = vIntersectionPoint[2];
554 ctOut++;
560 void dClipPolyToCircle(const dVector3 avArrayIn[], const int ctIn,
561 dVector3 avArrayOut[], int &ctOut,
562 const dVector4 &plPlane ,dReal fRadius)
564 // start with no output points
565 ctOut = 0;
567 int i0 = ctIn-1;
569 // for each edge in input polygon
570 for (int i1=0; i1<ctIn; i0=i1, i1++)
572 // calculate distance of edge points to plane
573 dReal fDistance0 = dPointPlaneDistance( avArrayIn[i0],plPlane );
574 dReal fDistance1 = dPointPlaneDistance( avArrayIn[i1],plPlane );
576 // if first point is in front of plane
577 if( fDistance0 >= 0 )
579 // emit point
580 if (dVector3LengthSquare(avArrayIn[i0]) <= fRadius*fRadius)
582 avArrayOut[ctOut][0] = avArrayIn[i0][0];
583 avArrayOut[ctOut][1] = avArrayIn[i0][1];
584 avArrayOut[ctOut][2] = avArrayIn[i0][2];
585 ctOut++;
589 // if points are on different sides
590 if( (fDistance0 > 0 && fDistance1 < 0) || ( fDistance0 < 0 && fDistance1 > 0) )
593 // find intersection point of edge and plane
594 dVector3 vIntersectionPoint;
595 vIntersectionPoint[0]= avArrayIn[i0][0] -
596 (avArrayIn[i0][0]-avArrayIn[i1][0])*fDistance0/(fDistance0-fDistance1);
597 vIntersectionPoint[1]= avArrayIn[i0][1] -
598 (avArrayIn[i0][1]-avArrayIn[i1][1])*fDistance0/(fDistance0-fDistance1);
599 vIntersectionPoint[2]= avArrayIn[i0][2] -
600 (avArrayIn[i0][2]-avArrayIn[i1][2])*fDistance0/(fDistance0-fDistance1);
602 // emit intersection point
603 if (dVector3LengthSquare(avArrayIn[i0]) <= fRadius*fRadius)
605 avArrayOut[ctOut][0] = vIntersectionPoint[0];
606 avArrayOut[ctOut][1] = vIntersectionPoint[1];
607 avArrayOut[ctOut][2] = vIntersectionPoint[2];
608 ctOut++;