collision_util.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604
  1. /*************************************************************************
  2. * *
  3. * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
  4. * All rights reserved. Email: [email protected] 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. *************************************************************************/
  22. /*
  23. some useful collision utility stuff. this includes some API utility
  24. functions that are defined in the public header files.
  25. */
  26. #include <ode/common.h>
  27. #include <ode/collision.h>
  28. #include "config.h"
  29. #include "odemath.h"
  30. #include "collision_util.h"
  31. //****************************************************************************
  32. int dCollideSpheres (dVector3 p1, dReal r1,
  33. dVector3 p2, dReal r2, dContactGeom *c)
  34. {
  35. // printf ("d=%.2f (%.2f %.2f %.2f) (%.2f %.2f %.2f) r1=%.2f r2=%.2f\n",
  36. // d,p1[0],p1[1],p1[2],p2[0],p2[1],p2[2],r1,r2);
  37. dReal d = dCalcPointsDistance3(p1,p2);
  38. if (d > (r1 + r2)) return 0;
  39. if (d <= 0) {
  40. c->pos[0] = p1[0];
  41. c->pos[1] = p1[1];
  42. c->pos[2] = p1[2];
  43. c->normal[0] = 1;
  44. c->normal[1] = 0;
  45. c->normal[2] = 0;
  46. c->depth = r1 + r2;
  47. }
  48. else {
  49. dReal d1 = dRecip (d);
  50. c->normal[0] = (p1[0]-p2[0])*d1;
  51. c->normal[1] = (p1[1]-p2[1])*d1;
  52. c->normal[2] = (p1[2]-p2[2])*d1;
  53. dReal k = REAL(0.5) * (r2 - r1 - d);
  54. c->pos[0] = p1[0] + c->normal[0]*k;
  55. c->pos[1] = p1[1] + c->normal[1]*k;
  56. c->pos[2] = p1[2] + c->normal[2]*k;
  57. c->depth = r1 + r2 - d;
  58. }
  59. return 1;
  60. }
  61. void dLineClosestApproach (const dVector3 pa, const dVector3 ua,
  62. const dVector3 pb, const dVector3 ub,
  63. dReal *alpha, dReal *beta)
  64. {
  65. dVector3 p;
  66. p[0] = pb[0] - pa[0];
  67. p[1] = pb[1] - pa[1];
  68. p[2] = pb[2] - pa[2];
  69. dReal uaub = dCalcVectorDot3(ua,ub);
  70. dReal q1 = dCalcVectorDot3(ua,p);
  71. dReal q2 = -dCalcVectorDot3(ub,p);
  72. dReal d = 1-uaub*uaub;
  73. if (d <= REAL(0.0001)) {
  74. // @@@ this needs to be made more robust
  75. *alpha = 0;
  76. *beta = 0;
  77. }
  78. else {
  79. d = dRecip(d);
  80. *alpha = (q1 + uaub*q2)*d;
  81. *beta = (uaub*q1 + q2)*d;
  82. }
  83. }
  84. // given two line segments A and B with endpoints a1-a2 and b1-b2, return the
  85. // points on A and B that are closest to each other (in cp1 and cp2).
  86. // in the case of parallel lines where there are multiple solutions, a
  87. // solution involving the endpoint of at least one line will be returned.
  88. // this will work correctly for zero length lines, e.g. if a1==a2 and/or
  89. // b1==b2.
  90. //
  91. // the algorithm works by applying the voronoi clipping rule to the features
  92. // of the line segments. the three features of each line segment are the two
  93. // endpoints and the line between them. the voronoi clipping rule states that,
  94. // for feature X on line A and feature Y on line B, the closest points PA and
  95. // PB between X and Y are globally the closest points if PA is in V(Y) and
  96. // PB is in V(X), where V(X) is the voronoi region of X.
  97. void dClosestLineSegmentPoints (const dVector3 a1, const dVector3 a2,
  98. const dVector3 b1, const dVector3 b2,
  99. dVector3 cp1, dVector3 cp2)
  100. {
  101. dVector3 a1a2,b1b2,a1b1,a1b2,a2b1,a2b2,n;
  102. dReal la,lb,k,da1,da2,da3,da4,db1,db2,db3,db4,det;
  103. #define SET2(a,b) a[0]=b[0]; a[1]=b[1]; a[2]=b[2];
  104. #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];
  105. // check vertex-vertex features
  106. SET3 (a1a2,a2,-,a1);
  107. SET3 (b1b2,b2,-,b1);
  108. SET3 (a1b1,b1,-,a1);
  109. da1 = dCalcVectorDot3(a1a2,a1b1);
  110. db1 = dCalcVectorDot3(b1b2,a1b1);
  111. if (da1 <= 0 && db1 >= 0) {
  112. SET2 (cp1,a1);
  113. SET2 (cp2,b1);
  114. return;
  115. }
  116. SET3 (a1b2,b2,-,a1);
  117. da2 = dCalcVectorDot3(a1a2,a1b2);
  118. db2 = dCalcVectorDot3(b1b2,a1b2);
  119. if (da2 <= 0 && db2 <= 0) {
  120. SET2 (cp1,a1);
  121. SET2 (cp2,b2);
  122. return;
  123. }
  124. SET3 (a2b1,b1,-,a2);
  125. da3 = dCalcVectorDot3(a1a2,a2b1);
  126. db3 = dCalcVectorDot3(b1b2,a2b1);
  127. if (da3 >= 0 && db3 >= 0) {
  128. SET2 (cp1,a2);
  129. SET2 (cp2,b1);
  130. return;
  131. }
  132. SET3 (a2b2,b2,-,a2);
  133. da4 = dCalcVectorDot3(a1a2,a2b2);
  134. db4 = dCalcVectorDot3(b1b2,a2b2);
  135. if (da4 >= 0 && db4 <= 0) {
  136. SET2 (cp1,a2);
  137. SET2 (cp2,b2);
  138. return;
  139. }
  140. // check edge-vertex features.
  141. // if one or both of the lines has zero length, we will never get to here,
  142. // so we do not have to worry about the following divisions by zero.
  143. la = dCalcVectorDot3(a1a2,a1a2);
  144. if (da1 >= 0 && da3 <= 0) {
  145. k = da1 / la;
  146. SET3 (n,a1b1,-,k*a1a2);
  147. if (dCalcVectorDot3(b1b2,n) >= 0) {
  148. SET3 (cp1,a1,+,k*a1a2);
  149. SET2 (cp2,b1);
  150. return;
  151. }
  152. }
  153. if (da2 >= 0 && da4 <= 0) {
  154. k = da2 / la;
  155. SET3 (n,a1b2,-,k*a1a2);
  156. if (dCalcVectorDot3(b1b2,n) <= 0) {
  157. SET3 (cp1,a1,+,k*a1a2);
  158. SET2 (cp2,b2);
  159. return;
  160. }
  161. }
  162. lb = dCalcVectorDot3(b1b2,b1b2);
  163. if (db1 <= 0 && db2 >= 0) {
  164. k = -db1 / lb;
  165. SET3 (n,-a1b1,-,k*b1b2);
  166. if (dCalcVectorDot3(a1a2,n) >= 0) {
  167. SET2 (cp1,a1);
  168. SET3 (cp2,b1,+,k*b1b2);
  169. return;
  170. }
  171. }
  172. if (db3 <= 0 && db4 >= 0) {
  173. k = -db3 / lb;
  174. SET3 (n,-a2b1,-,k*b1b2);
  175. if (dCalcVectorDot3(a1a2,n) <= 0) {
  176. SET2 (cp1,a2);
  177. SET3 (cp2,b1,+,k*b1b2);
  178. return;
  179. }
  180. }
  181. // it must be edge-edge
  182. k = dCalcVectorDot3(a1a2,b1b2);
  183. det = la*lb - k*k;
  184. if (det <= 0) {
  185. // this should never happen, but just in case...
  186. SET2(cp1,a1);
  187. SET2(cp2,b1);
  188. return;
  189. }
  190. det = dRecip (det);
  191. dReal alpha = (lb*da1 - k*db1) * det;
  192. dReal beta = ( k*da1 - la*db1) * det;
  193. SET3 (cp1,a1,+,alpha*a1a2);
  194. SET3 (cp2,b1,+,beta*b1b2);
  195. # undef SET2
  196. # undef SET3
  197. }
  198. // a simple root finding algorithm is used to find the value of 't' that
  199. // satisfies:
  200. // d|D(t)|^2/dt = 0
  201. // where:
  202. // |D(t)| = |p(t)-b(t)|
  203. // where p(t) is a point on the line parameterized by t:
  204. // p(t) = p1 + t*(p2-p1)
  205. // and b(t) is that same point clipped to the boundary of the box. in box-
  206. // relative coordinates d|D(t)|^2/dt is the sum of three x,y,z components
  207. // each of which looks like this:
  208. //
  209. // t_lo /
  210. // ______/ -->t
  211. // / t_hi
  212. // /
  213. //
  214. // t_lo and t_hi are the t values where the line passes through the planes
  215. // corresponding to the sides of the box. the algorithm computes d|D(t)|^2/dt
  216. // in a piecewise fashion from t=0 to t=1, stopping at the point where
  217. // d|D(t)|^2/dt crosses from negative to positive.
  218. void dClosestLineBoxPoints (const dVector3 p1, const dVector3 p2,
  219. const dVector3 c, const dMatrix3 R,
  220. const dVector3 side,
  221. dVector3 lret, dVector3 bret)
  222. {
  223. int i;
  224. // compute the start and delta of the line p1-p2 relative to the box.
  225. // we will do all subsequent computations in this box-relative coordinate
  226. // system. we have to do a translation and rotation for each point.
  227. dVector3 tmp,s,v;
  228. tmp[0] = p1[0] - c[0];
  229. tmp[1] = p1[1] - c[1];
  230. tmp[2] = p1[2] - c[2];
  231. dMultiply1_331 (s,R,tmp);
  232. tmp[0] = p2[0] - p1[0];
  233. tmp[1] = p2[1] - p1[1];
  234. tmp[2] = p2[2] - p1[2];
  235. dMultiply1_331 (v,R,tmp);
  236. // mirror the line so that v has all components >= 0
  237. dVector3 sign;
  238. for (i=0; i<3; i++) {
  239. if (v[i] < 0) {
  240. s[i] = -s[i];
  241. v[i] = -v[i];
  242. sign[i] = -1;
  243. }
  244. else sign[i] = 1;
  245. }
  246. // compute v^2
  247. dVector3 v2;
  248. v2[0] = v[0]*v[0];
  249. v2[1] = v[1]*v[1];
  250. v2[2] = v[2]*v[2];
  251. // compute the half-sides of the box
  252. dReal h[3];
  253. h[0] = REAL(0.5) * side[0];
  254. h[1] = REAL(0.5) * side[1];
  255. h[2] = REAL(0.5) * side[2];
  256. // region is -1,0,+1 depending on which side of the box planes each
  257. // coordinate is on. tanchor is the next t value at which there is a
  258. // transition, or the last one if there are no more.
  259. int region[3];
  260. dReal tanchor[3];
  261. // Denormals are a problem, because we divide by v[i], and then
  262. // multiply that by 0. Alas, infinity times 0 is infinity (!)
  263. // We also use v2[i], which is v[i] squared. Here's how the epsilons
  264. // are chosen:
  265. // float epsilon = 1.175494e-038 (smallest non-denormal number)
  266. // double epsilon = 2.225074e-308 (smallest non-denormal number)
  267. // For single precision, choose an epsilon such that v[i] squared is
  268. // not a denormal; this is for performance.
  269. // For double precision, choose an epsilon such that v[i] is not a
  270. // denormal; this is for correctness. (Jon Watte on mailinglist)
  271. #if defined( dSINGLE )
  272. const dReal tanchor_eps = REAL(1e-19);
  273. #else
  274. const dReal tanchor_eps = REAL(1e-307);
  275. #endif
  276. // find the region and tanchor values for p1
  277. for (i=0; i<3; i++) {
  278. if (v[i] > tanchor_eps) {
  279. if (s[i] < -h[i]) {
  280. region[i] = -1;
  281. tanchor[i] = (-h[i]-s[i])/v[i];
  282. }
  283. else {
  284. region[i] = (s[i] > h[i]);
  285. tanchor[i] = (h[i]-s[i])/v[i];
  286. }
  287. }
  288. else {
  289. region[i] = 0;
  290. tanchor[i] = 2; // this will never be a valid tanchor
  291. }
  292. }
  293. // compute d|d|^2/dt for t=0. if it's >= 0 then p1 is the closest point
  294. dReal t=0;
  295. dReal dd2dt = 0;
  296. for (i=0; i<3; i++) dd2dt -= (region[i] ? v2[i] : 0) * tanchor[i];
  297. if (dd2dt >= 0) goto got_answer;
  298. do {
  299. // find the point on the line that is at the next clip plane boundary
  300. dReal next_t = 1;
  301. for (i=0; i<3; i++) {
  302. if (tanchor[i] > t && tanchor[i] < 1 && tanchor[i] < next_t)
  303. next_t = tanchor[i];
  304. }
  305. // compute d|d|^2/dt for the next t
  306. dReal next_dd2dt = 0;
  307. for (i=0; i<3; i++) {
  308. next_dd2dt += (region[i] ? v2[i] : 0) * (next_t - tanchor[i]);
  309. }
  310. // if the sign of d|d|^2/dt has changed, solution = the crossover point
  311. if (next_dd2dt >= 0) {
  312. dReal m = (next_dd2dt-dd2dt)/(next_t - t);
  313. t -= dd2dt/m;
  314. goto got_answer;
  315. }
  316. // advance to the next anchor point / region
  317. for (i=0; i<3; i++) {
  318. if (tanchor[i] == next_t) {
  319. tanchor[i] = (h[i]-s[i])/v[i];
  320. region[i]++;
  321. }
  322. }
  323. t = next_t;
  324. dd2dt = next_dd2dt;
  325. }
  326. while (t < 1);
  327. t = 1;
  328. got_answer:
  329. // compute closest point on the line
  330. for (i=0; i<3; i++) lret[i] = p1[i] + t*tmp[i]; // note: tmp=p2-p1
  331. // compute closest point on the box
  332. for (i=0; i<3; i++) {
  333. tmp[i] = sign[i] * (s[i] + t*v[i]);
  334. if (tmp[i] < -h[i]) tmp[i] = -h[i];
  335. else if (tmp[i] > h[i]) tmp[i] = h[i];
  336. }
  337. dMultiply0_331 (s,R,tmp);
  338. for (i=0; i<3; i++) bret[i] = s[i] + c[i];
  339. }
  340. // given boxes (p1,R1,side1) and (p1,R1,side1), return 1 if they intersect
  341. // or 0 if not.
  342. int dBoxTouchesBox (const dVector3 p1, const dMatrix3 R1,
  343. const dVector3 side1, const dVector3 p2,
  344. const dMatrix3 R2, const dVector3 side2)
  345. {
  346. // two boxes are disjoint if (and only if) there is a separating axis
  347. // perpendicular to a face from one box or perpendicular to an edge from
  348. // either box. the following tests are derived from:
  349. // "OBB Tree: A Hierarchical Structure for Rapid Interference Detection",
  350. // S.Gottschalk, M.C.Lin, D.Manocha., Proc of ACM Siggraph 1996.
  351. // Rij is R1'*R2, i.e. the relative rotation between R1 and R2.
  352. // Qij is abs(Rij)
  353. dVector3 p,pp;
  354. dReal A1,A2,A3,B1,B2,B3,R11,R12,R13,R21,R22,R23,R31,R32,R33,
  355. Q11,Q12,Q13,Q21,Q22,Q23,Q31,Q32,Q33;
  356. // get vector from centers of box 1 to box 2, relative to box 1
  357. p[0] = p2[0] - p1[0];
  358. p[1] = p2[1] - p1[1];
  359. p[2] = p2[2] - p1[2];
  360. dMultiply1_331 (pp,R1,p); // get pp = p relative to body 1
  361. // get side lengths / 2
  362. A1 = side1[0]*REAL(0.5); A2 = side1[1]*REAL(0.5); A3 = side1[2]*REAL(0.5);
  363. B1 = side2[0]*REAL(0.5); B2 = side2[1]*REAL(0.5); B3 = side2[2]*REAL(0.5);
  364. // for the following tests, excluding computation of Rij, in the worst case,
  365. // 15 compares, 60 adds, 81 multiplies, and 24 absolutes.
  366. // notation: R1=[u1 u2 u3], R2=[v1 v2 v3]
  367. // separating axis = u1,u2,u3
  368. R11 = dCalcVectorDot3_44(R1+0,R2+0); R12 = dCalcVectorDot3_44(R1+0,R2+1); R13 = dCalcVectorDot3_44(R1+0,R2+2);
  369. Q11 = dFabs(R11); Q12 = dFabs(R12); Q13 = dFabs(R13);
  370. if (dFabs(pp[0]) > (A1 + B1*Q11 + B2*Q12 + B3*Q13)) return 0;
  371. R21 = dCalcVectorDot3_44(R1+1,R2+0); R22 = dCalcVectorDot3_44(R1+1,R2+1); R23 = dCalcVectorDot3_44(R1+1,R2+2);
  372. Q21 = dFabs(R21); Q22 = dFabs(R22); Q23 = dFabs(R23);
  373. if (dFabs(pp[1]) > (A2 + B1*Q21 + B2*Q22 + B3*Q23)) return 0;
  374. R31 = dCalcVectorDot3_44(R1+2,R2+0); R32 = dCalcVectorDot3_44(R1+2,R2+1); R33 = dCalcVectorDot3_44(R1+2,R2+2);
  375. Q31 = dFabs(R31); Q32 = dFabs(R32); Q33 = dFabs(R33);
  376. if (dFabs(pp[2]) > (A3 + B1*Q31 + B2*Q32 + B3*Q33)) return 0;
  377. // separating axis = v1,v2,v3
  378. if (dFabs(dCalcVectorDot3_41(R2+0,p)) > (A1*Q11 + A2*Q21 + A3*Q31 + B1)) return 0;
  379. if (dFabs(dCalcVectorDot3_41(R2+1,p)) > (A1*Q12 + A2*Q22 + A3*Q32 + B2)) return 0;
  380. if (dFabs(dCalcVectorDot3_41(R2+2,p)) > (A1*Q13 + A2*Q23 + A3*Q33 + B3)) return 0;
  381. // separating axis = u1 x (v1,v2,v3)
  382. if (dFabs(pp[2]*R21-pp[1]*R31) > A2*Q31 + A3*Q21 + B2*Q13 + B3*Q12) return 0;
  383. if (dFabs(pp[2]*R22-pp[1]*R32) > A2*Q32 + A3*Q22 + B1*Q13 + B3*Q11) return 0;
  384. if (dFabs(pp[2]*R23-pp[1]*R33) > A2*Q33 + A3*Q23 + B1*Q12 + B2*Q11) return 0;
  385. // separating axis = u2 x (v1,v2,v3)
  386. if (dFabs(pp[0]*R31-pp[2]*R11) > A1*Q31 + A3*Q11 + B2*Q23 + B3*Q22) return 0;
  387. if (dFabs(pp[0]*R32-pp[2]*R12) > A1*Q32 + A3*Q12 + B1*Q23 + B3*Q21) return 0;
  388. if (dFabs(pp[0]*R33-pp[2]*R13) > A1*Q33 + A3*Q13 + B1*Q22 + B2*Q21) return 0;
  389. // separating axis = u3 x (v1,v2,v3)
  390. if (dFabs(pp[1]*R11-pp[0]*R21) > A1*Q21 + A2*Q11 + B2*Q33 + B3*Q32) return 0;
  391. if (dFabs(pp[1]*R12-pp[0]*R22) > A1*Q22 + A2*Q12 + B1*Q33 + B3*Q31) return 0;
  392. if (dFabs(pp[1]*R13-pp[0]*R23) > A1*Q23 + A2*Q13 + B1*Q32 + B2*Q31) return 0;
  393. return 1;
  394. }
  395. //****************************************************************************
  396. // other utility functions
  397. //****************************************************************************
  398. // Helpers for Croteam's collider - by Nguyen Binh
  399. int dClipEdgeToPlane( dVector3 &vEpnt0, dVector3 &vEpnt1, const dVector4& plPlane)
  400. {
  401. // calculate distance of edge points to plane
  402. dReal fDistance0 = dPointPlaneDistance( vEpnt0 ,plPlane );
  403. dReal fDistance1 = dPointPlaneDistance( vEpnt1 ,plPlane );
  404. // if both points are behind the plane
  405. if ( fDistance0 < 0 && fDistance1 < 0 )
  406. {
  407. // do nothing
  408. return 0;
  409. // if both points in front of the plane
  410. }
  411. else if ( fDistance0 > 0 && fDistance1 > 0 )
  412. {
  413. // accept them
  414. return 1;
  415. // if we have edge/plane intersection
  416. } else if ((fDistance0 > 0 && fDistance1 < 0) || ( fDistance0 < 0 && fDistance1 > 0))
  417. {
  418. // find intersection point of edge and plane
  419. dVector3 vIntersectionPoint;
  420. vIntersectionPoint[0]= vEpnt0[0]-(vEpnt0[0]-vEpnt1[0])*fDistance0/(fDistance0-fDistance1);
  421. vIntersectionPoint[1]= vEpnt0[1]-(vEpnt0[1]-vEpnt1[1])*fDistance0/(fDistance0-fDistance1);
  422. vIntersectionPoint[2]= vEpnt0[2]-(vEpnt0[2]-vEpnt1[2])*fDistance0/(fDistance0-fDistance1);
  423. // clamp correct edge to intersection point
  424. if ( fDistance0 < 0 )
  425. {
  426. dVector3Copy(vIntersectionPoint,vEpnt0);
  427. } else
  428. {
  429. dVector3Copy(vIntersectionPoint,vEpnt1);
  430. }
  431. return 1;
  432. }
  433. return 1;
  434. }
  435. // clip polygon with plane and generate new polygon points
  436. void dClipPolyToPlane( const dVector3 avArrayIn[], const int ctIn,
  437. dVector3 avArrayOut[], int &ctOut,
  438. const dVector4 &plPlane )
  439. {
  440. // start with no output points
  441. ctOut = 0;
  442. int i0 = ctIn-1;
  443. // for each edge in input polygon
  444. for (int i1=0; i1<ctIn; i0=i1, i1++) {
  445. // calculate distance of edge points to plane
  446. dReal fDistance0 = dPointPlaneDistance( avArrayIn[i0],plPlane );
  447. dReal fDistance1 = dPointPlaneDistance( avArrayIn[i1],plPlane );
  448. // if first point is in front of plane
  449. if( fDistance0 >= 0 ) {
  450. // emit point
  451. avArrayOut[ctOut][0] = avArrayIn[i0][0];
  452. avArrayOut[ctOut][1] = avArrayIn[i0][1];
  453. avArrayOut[ctOut][2] = avArrayIn[i0][2];
  454. ctOut++;
  455. }
  456. // if points are on different sides
  457. if( (fDistance0 > 0 && fDistance1 < 0) || ( fDistance0 < 0 && fDistance1 > 0) ) {
  458. // find intersection point of edge and plane
  459. dVector3 vIntersectionPoint;
  460. vIntersectionPoint[0]= avArrayIn[i0][0] -
  461. (avArrayIn[i0][0]-avArrayIn[i1][0])*fDistance0/(fDistance0-fDistance1);
  462. vIntersectionPoint[1]= avArrayIn[i0][1] -
  463. (avArrayIn[i0][1]-avArrayIn[i1][1])*fDistance0/(fDistance0-fDistance1);
  464. vIntersectionPoint[2]= avArrayIn[i0][2] -
  465. (avArrayIn[i0][2]-avArrayIn[i1][2])*fDistance0/(fDistance0-fDistance1);
  466. // emit intersection point
  467. avArrayOut[ctOut][0] = vIntersectionPoint[0];
  468. avArrayOut[ctOut][1] = vIntersectionPoint[1];
  469. avArrayOut[ctOut][2] = vIntersectionPoint[2];
  470. ctOut++;
  471. }
  472. }
  473. }
  474. void dClipPolyToCircle(const dVector3 avArrayIn[], const int ctIn,
  475. dVector3 avArrayOut[], int &ctOut,
  476. const dVector4 &plPlane ,dReal fRadius)
  477. {
  478. // start with no output points
  479. ctOut = 0;
  480. int i0 = ctIn-1;
  481. // for each edge in input polygon
  482. for (int i1=0; i1<ctIn; i0=i1, i1++)
  483. {
  484. // calculate distance of edge points to plane
  485. dReal fDistance0 = dPointPlaneDistance( avArrayIn[i0],plPlane );
  486. dReal fDistance1 = dPointPlaneDistance( avArrayIn[i1],plPlane );
  487. // if first point is in front of plane
  488. if( fDistance0 >= 0 )
  489. {
  490. // emit point
  491. if (dVector3LengthSquare(avArrayIn[i0]) <= fRadius*fRadius)
  492. {
  493. avArrayOut[ctOut][0] = avArrayIn[i0][0];
  494. avArrayOut[ctOut][1] = avArrayIn[i0][1];
  495. avArrayOut[ctOut][2] = avArrayIn[i0][2];
  496. ctOut++;
  497. }
  498. }
  499. // if points are on different sides
  500. if( (fDistance0 > 0 && fDistance1 < 0) || ( fDistance0 < 0 && fDistance1 > 0) )
  501. {
  502. // find intersection point of edge and plane
  503. dVector3 vIntersectionPoint;
  504. vIntersectionPoint[0]= avArrayIn[i0][0] -
  505. (avArrayIn[i0][0]-avArrayIn[i1][0])*fDistance0/(fDistance0-fDistance1);
  506. vIntersectionPoint[1]= avArrayIn[i0][1] -
  507. (avArrayIn[i0][1]-avArrayIn[i1][1])*fDistance0/(fDistance0-fDistance1);
  508. vIntersectionPoint[2]= avArrayIn[i0][2] -
  509. (avArrayIn[i0][2]-avArrayIn[i1][2])*fDistance0/(fDistance0-fDistance1);
  510. // emit intersection point
  511. if (dVector3LengthSquare(avArrayIn[i0]) <= fRadius*fRadius)
  512. {
  513. avArrayOut[ctOut][0] = vIntersectionPoint[0];
  514. avArrayOut[ctOut][1] = vIntersectionPoint[1];
  515. avArrayOut[ctOut][2] = vIntersectionPoint[2];
  516. ctOut++;
  517. }
  518. }
  519. }
  520. }