diff options
author | dan miller | 2007-10-21 08:36:32 +0000 |
---|---|---|
committer | dan miller | 2007-10-21 08:36:32 +0000 |
commit | 2f8d7092bc2c9609fa98d6888106b96f38b22828 (patch) | |
tree | da6c37579258cc965b52a75aee6135fe44237698 /libraries/ode-0.9/ode/src/collision_cylinder_trimesh.cpp | |
parent | * Committing new PolicyManager based on an ACL system. (diff) | |
download | opensim-SC-2f8d7092bc2c9609fa98d6888106b96f38b22828.zip opensim-SC-2f8d7092bc2c9609fa98d6888106b96f38b22828.tar.gz opensim-SC-2f8d7092bc2c9609fa98d6888106b96f38b22828.tar.bz2 opensim-SC-2f8d7092bc2c9609fa98d6888106b96f38b22828.tar.xz |
libraries moved to opensim-libs, a new repository
Diffstat (limited to 'libraries/ode-0.9/ode/src/collision_cylinder_trimesh.cpp')
-rw-r--r-- | libraries/ode-0.9/ode/src/collision_cylinder_trimesh.cpp | 1145 |
1 files changed, 0 insertions, 1145 deletions
diff --git a/libraries/ode-0.9/ode/src/collision_cylinder_trimesh.cpp b/libraries/ode-0.9/ode/src/collision_cylinder_trimesh.cpp deleted file mode 100644 index 342be04..0000000 --- a/libraries/ode-0.9/ode/src/collision_cylinder_trimesh.cpp +++ /dev/null | |||
@@ -1,1145 +0,0 @@ | |||
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 | *************************************************************************/ | ||
22 | |||
23 | /* | ||
24 | * Cylinder-trimesh collider by Alen Ladavac | ||
25 | * Ported to ODE by Nguyen Binh | ||
26 | */ | ||
27 | |||
28 | |||
29 | #include <ode/collision.h> | ||
30 | #include <ode/matrix.h> | ||
31 | #include <ode/rotation.h> | ||
32 | #include <ode/odemath.h> | ||
33 | #include "collision_util.h" | ||
34 | |||
35 | #define TRIMESH_INTERNAL | ||
36 | #include "collision_trimesh_internal.h" | ||
37 | |||
38 | #define MAX_REAL dInfinity | ||
39 | static const int nCYLINDER_AXIS = 2; | ||
40 | static const int nCYLINDER_CIRCLE_SEGMENTS = 8; | ||
41 | static const int nMAX_CYLINDER_TRIANGLE_CLIP_POINTS = 12; | ||
42 | |||
43 | #define OPTIMIZE_CONTACTS 1 | ||
44 | |||
45 | // Local contacts data | ||
46 | typedef struct _sLocalContactData | ||
47 | { | ||
48 | dVector3 vPos; | ||
49 | dVector3 vNormal; | ||
50 | dReal fDepth; | ||
51 | int triIndex; | ||
52 | int nFlags; // 0 = filtered out, 1 = OK | ||
53 | }sLocalContactData; | ||
54 | |||
55 | typedef struct _sCylinderTrimeshColliderData | ||
56 | { | ||
57 | // cylinder data | ||
58 | dMatrix3 mCylinderRot; | ||
59 | dQuaternion qCylinderRot; | ||
60 | dQuaternion qInvCylinderRot; | ||
61 | dVector3 vCylinderPos; | ||
62 | dVector3 vCylinderAxis; | ||
63 | dReal fCylinderRadius; | ||
64 | dReal fCylinderSize; | ||
65 | dVector3 avCylinderNormals[nCYLINDER_CIRCLE_SEGMENTS]; | ||
66 | |||
67 | // mesh data | ||
68 | dQuaternion qTrimeshRot; | ||
69 | dQuaternion qInvTrimeshRot; | ||
70 | dMatrix3 mTrimeshRot; | ||
71 | dVector3 vTrimeshPos; | ||
72 | |||
73 | // global collider data | ||
74 | dVector3 vBestPoint; | ||
75 | dReal fBestDepth; | ||
76 | dReal fBestCenter; | ||
77 | dReal fBestrt; | ||
78 | int iBestAxis; | ||
79 | dVector3 vContactNormal; | ||
80 | dVector3 vNormal; | ||
81 | dVector3 vE0; | ||
82 | dVector3 vE1; | ||
83 | dVector3 vE2; | ||
84 | |||
85 | // ODE stuff | ||
86 | dGeomID gCylinder; | ||
87 | dxTriMesh* gTrimesh; | ||
88 | dContactGeom* gContact; | ||
89 | int iFlags; | ||
90 | int iSkip; | ||
91 | int nContacts;// = 0; | ||
92 | sLocalContactData* gLocalContacts; | ||
93 | } sCylinderTrimeshColliderData; | ||
94 | |||
95 | // Short type name | ||
96 | typedef sCylinderTrimeshColliderData sData; | ||
97 | |||
98 | // Use to classify contacts to be "near" in position | ||
99 | static const dReal fSameContactPositionEpsilon = REAL(0.0001); // 1e-4 | ||
100 | // Use to classify contacts to be "near" in normal direction | ||
101 | static const dReal fSameContactNormalEpsilon = REAL(0.0001); // 1e-4 | ||
102 | |||
103 | // If this two contact can be classified as "near" | ||
104 | inline int _IsNearContacts(sLocalContactData& c1,sLocalContactData& c2) | ||
105 | { | ||
106 | int bPosNear = 0; | ||
107 | int bSameDir = 0; | ||
108 | dVector3 vDiff; | ||
109 | |||
110 | // First check if they are "near" in position | ||
111 | dVector3Subtract(c1.vPos,c2.vPos,vDiff); | ||
112 | if ( (dFabs(vDiff[0]) < fSameContactPositionEpsilon) | ||
113 | &&(dFabs(vDiff[1]) < fSameContactPositionEpsilon) | ||
114 | &&(dFabs(vDiff[2]) < fSameContactPositionEpsilon)) | ||
115 | { | ||
116 | bPosNear = 1; | ||
117 | } | ||
118 | |||
119 | // Second check if they are "near" in normal direction | ||
120 | dVector3Subtract(c1.vNormal,c2.vNormal,vDiff); | ||
121 | if ( (dFabs(vDiff[0]) < fSameContactNormalEpsilon) | ||
122 | &&(dFabs(vDiff[1]) < fSameContactNormalEpsilon) | ||
123 | &&(dFabs(vDiff[2]) < fSameContactNormalEpsilon) ) | ||
124 | { | ||
125 | bSameDir = 1; | ||
126 | } | ||
127 | |||
128 | // Will be "near" if position and normal direction are "near" | ||
129 | return (bPosNear && bSameDir); | ||
130 | } | ||
131 | |||
132 | inline int _IsBetter(sLocalContactData& c1,sLocalContactData& c2) | ||
133 | { | ||
134 | // The not better will be throw away | ||
135 | // You can change the selection criteria here | ||
136 | return (c1.fDepth > c2.fDepth); | ||
137 | } | ||
138 | |||
139 | // iterate through gLocalContacts and filtered out "near contact" | ||
140 | inline void _OptimizeLocalContacts(sData& cData) | ||
141 | { | ||
142 | int nContacts = cData.nContacts; | ||
143 | |||
144 | for (int i = 0; i < nContacts-1; i++) | ||
145 | { | ||
146 | for (int j = i+1; j < nContacts; j++) | ||
147 | { | ||
148 | if (_IsNearContacts(cData.gLocalContacts[i],cData.gLocalContacts[j])) | ||
149 | { | ||
150 | // If they are seem to be the same then filtered | ||
151 | // out the least penetrate one | ||
152 | if (_IsBetter(cData.gLocalContacts[j],cData.gLocalContacts[i])) | ||
153 | { | ||
154 | cData.gLocalContacts[i].nFlags = 0; // filtered 1st contact | ||
155 | } | ||
156 | else | ||
157 | { | ||
158 | cData.gLocalContacts[j].nFlags = 0; // filtered 2nd contact | ||
159 | } | ||
160 | |||
161 | // NOTE | ||
162 | // There is other way is to add two depth together but | ||
163 | // it not work so well. Why??? | ||
164 | } | ||
165 | } | ||
166 | } | ||
167 | } | ||
168 | |||
169 | inline int _ProcessLocalContacts(sData& cData) | ||
170 | { | ||
171 | if (cData.nContacts == 0) | ||
172 | { | ||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | #ifdef OPTIMIZE_CONTACTS | ||
177 | if (cData.nContacts > 1 && !(cData.iFlags & CONTACTS_UNIMPORTANT)) | ||
178 | { | ||
179 | // Can be optimized... | ||
180 | _OptimizeLocalContacts(cData); | ||
181 | } | ||
182 | #endif | ||
183 | |||
184 | int iContact = 0; | ||
185 | dContactGeom* Contact = 0; | ||
186 | |||
187 | int nFinalContact = 0; | ||
188 | |||
189 | for (iContact = 0; iContact < cData.nContacts; iContact ++) | ||
190 | { | ||
191 | if (1 == cData.gLocalContacts[iContact].nFlags) | ||
192 | { | ||
193 | Contact = SAFECONTACT(cData.iFlags, cData.gContact, nFinalContact, cData.iSkip); | ||
194 | Contact->depth = cData.gLocalContacts[iContact].fDepth; | ||
195 | dVector3Copy(cData.gLocalContacts[iContact].vNormal,Contact->normal); | ||
196 | dVector3Copy(cData.gLocalContacts[iContact].vPos,Contact->pos); | ||
197 | Contact->g1 = cData.gCylinder; | ||
198 | Contact->g2 = cData.gTrimesh; | ||
199 | Contact->side2 = cData.gLocalContacts[iContact].triIndex; | ||
200 | dVector3Inv(Contact->normal); | ||
201 | |||
202 | nFinalContact++; | ||
203 | } | ||
204 | } | ||
205 | // debug | ||
206 | //if (nFinalContact != cData.nContacts) | ||
207 | //{ | ||
208 | // printf("[Info] %d contacts generated,%d filtered.\n",cData.nContacts,cData.nContacts-nFinalContact); | ||
209 | //} | ||
210 | |||
211 | return nFinalContact; | ||
212 | } | ||
213 | |||
214 | |||
215 | bool _cldTestAxis(sData& cData, | ||
216 | const dVector3 &v0, | ||
217 | const dVector3 &v1, | ||
218 | const dVector3 &v2, | ||
219 | dVector3& vAxis, | ||
220 | int iAxis, | ||
221 | bool bNoFlip = false) | ||
222 | { | ||
223 | |||
224 | // calculate length of separating axis vector | ||
225 | dReal fL = dVector3Length(vAxis); | ||
226 | // if not long enough | ||
227 | if ( fL < REAL(1e-5) ) | ||
228 | { | ||
229 | // do nothing | ||
230 | return true; | ||
231 | } | ||
232 | |||
233 | // otherwise normalize it | ||
234 | vAxis[0] /= fL; | ||
235 | vAxis[1] /= fL; | ||
236 | vAxis[2] /= fL; | ||
237 | |||
238 | dReal fdot1 = dVector3Dot(cData.vCylinderAxis,vAxis); | ||
239 | // project capsule on vAxis | ||
240 | dReal frc; | ||
241 | |||
242 | if (dFabs(fdot1) > REAL(1.0) ) | ||
243 | { | ||
244 | // fdot1 = REAL(1.0); | ||
245 | frc = dFabs(cData.fCylinderSize* REAL(0.5)); | ||
246 | } | ||
247 | else | ||
248 | { | ||
249 | frc = dFabs((cData.fCylinderSize* REAL(0.5)) * fdot1) | ||
250 | + cData.fCylinderRadius * dSqrt(REAL(1.0)-(fdot1*fdot1)); | ||
251 | } | ||
252 | |||
253 | dVector3 vV0; | ||
254 | dVector3Subtract(v0,cData.vCylinderPos,vV0); | ||
255 | dVector3 vV1; | ||
256 | dVector3Subtract(v1,cData.vCylinderPos,vV1); | ||
257 | dVector3 vV2; | ||
258 | dVector3Subtract(v2,cData.vCylinderPos,vV2); | ||
259 | |||
260 | // project triangle on vAxis | ||
261 | dReal afv[3]; | ||
262 | afv[0] = dVector3Dot( vV0 , vAxis ); | ||
263 | afv[1] = dVector3Dot( vV1 , vAxis ); | ||
264 | afv[2] = dVector3Dot( vV2 , vAxis ); | ||
265 | |||
266 | dReal fMin = MAX_REAL; | ||
267 | dReal fMax = -MAX_REAL; | ||
268 | |||
269 | // for each vertex | ||
270 | for(int i = 0; i < 3; i++) | ||
271 | { | ||
272 | // find minimum | ||
273 | if (afv[i]<fMin) | ||
274 | { | ||
275 | fMin = afv[i]; | ||
276 | } | ||
277 | // find maximum | ||
278 | if (afv[i]>fMax) | ||
279 | { | ||
280 | fMax = afv[i]; | ||
281 | } | ||
282 | } | ||
283 | |||
284 | // find capsule's center of interval on axis | ||
285 | dReal fCenter = (fMin+fMax)* REAL(0.5); | ||
286 | // calculate triangles halfinterval | ||
287 | dReal fTriangleRadius = (fMax-fMin)*REAL(0.5); | ||
288 | |||
289 | // if they do not overlap, | ||
290 | if( dFabs(fCenter) > (frc+fTriangleRadius) ) | ||
291 | { | ||
292 | // exit, we have no intersection | ||
293 | return false; | ||
294 | } | ||
295 | |||
296 | // calculate depth | ||
297 | dReal fDepth = -(dFabs(fCenter) - (frc + fTriangleRadius ) ); | ||
298 | |||
299 | // if greater then best found so far | ||
300 | if ( fDepth < cData.fBestDepth ) | ||
301 | { | ||
302 | // remember depth | ||
303 | cData.fBestDepth = fDepth; | ||
304 | cData.fBestCenter = fCenter; | ||
305 | cData.fBestrt = frc; | ||
306 | dVector3Copy(vAxis,cData.vContactNormal); | ||
307 | cData.iBestAxis = iAxis; | ||
308 | |||
309 | // flip normal if interval is wrong faced | ||
310 | if ( fCenter< REAL(0.0) && !bNoFlip) | ||
311 | { | ||
312 | dVector3Inv(cData.vContactNormal); | ||
313 | cData.fBestCenter = -fCenter; | ||
314 | } | ||
315 | } | ||
316 | |||
317 | return true; | ||
318 | } | ||
319 | |||
320 | // intersection test between edge and circle | ||
321 | bool _cldTestCircleToEdgeAxis(sData& cData, | ||
322 | const dVector3 &v0, const dVector3 &v1, const dVector3 &v2, | ||
323 | const dVector3 &vCenterPoint, const dVector3 &vCylinderAxis1, | ||
324 | const dVector3 &vVx0, const dVector3 &vVx1, int iAxis) | ||
325 | { | ||
326 | // calculate direction of edge | ||
327 | dVector3 vkl; | ||
328 | dVector3Subtract( vVx1 , vVx0 , vkl); | ||
329 | dNormalize3(vkl); | ||
330 | // starting point of edge | ||
331 | dVector3 vol; | ||
332 | dVector3Copy(vVx0,vol); | ||
333 | |||
334 | // calculate angle cosine between cylinder axis and edge | ||
335 | dReal fdot2 = dVector3Dot(vkl , vCylinderAxis1); | ||
336 | |||
337 | // if edge is perpendicular to cylinder axis | ||
338 | if(dFabs(fdot2)<REAL(1e-5)) | ||
339 | { | ||
340 | // this can't be separating axis, because edge is parallel to circle plane | ||
341 | return true; | ||
342 | } | ||
343 | |||
344 | // find point of intersection between edge line and circle plane | ||
345 | dVector3 vTemp; | ||
346 | dVector3Subtract(vCenterPoint,vol,vTemp); | ||
347 | dReal fdot1 = dVector3Dot(vTemp,vCylinderAxis1); | ||
348 | dVector3 vpnt;// = vol + vkl * (fdot1/fdot2); | ||
349 | vpnt[0] = vol[0] + vkl[0] * fdot1/fdot2; | ||
350 | vpnt[1] = vol[1] + vkl[1] * fdot1/fdot2; | ||
351 | vpnt[2] = vol[2] + vkl[2] * fdot1/fdot2; | ||
352 | |||
353 | // find tangent vector on circle with same center (vCenterPoint) that touches point of intersection (vpnt) | ||
354 | dVector3 vTangent; | ||
355 | dVector3Subtract(vCenterPoint,vpnt,vTemp); | ||
356 | dVector3Cross(vTemp,vCylinderAxis1,vTangent); | ||
357 | |||
358 | // find vector orthogonal both to tangent and edge direction | ||
359 | dVector3 vAxis; | ||
360 | dVector3Cross(vTangent,vkl,vAxis); | ||
361 | |||
362 | // use that vector as separating axis | ||
363 | return _cldTestAxis( cData ,v0, v1, v2, vAxis, iAxis ); | ||
364 | } | ||
365 | |||
366 | // helper for less key strokes | ||
367 | // r = ( (v1 - v2) cross v3 ) cross v3 | ||
368 | inline void _CalculateAxis(const dVector3& v1, | ||
369 | const dVector3& v2, | ||
370 | const dVector3& v3, | ||
371 | dVector3& r) | ||
372 | { | ||
373 | dVector3 t1; | ||
374 | dVector3 t2; | ||
375 | |||
376 | dVector3Subtract(v1,v2,t1); | ||
377 | dVector3Cross(t1,v3,t2); | ||
378 | dVector3Cross(t2,v3,r); | ||
379 | } | ||
380 | |||
381 | bool _cldTestSeparatingAxes(sData& cData, | ||
382 | const dVector3 &v0, | ||
383 | const dVector3 &v1, | ||
384 | const dVector3 &v2) | ||
385 | { | ||
386 | |||
387 | // calculate edge vectors | ||
388 | dVector3Subtract(v1 ,v0 , cData.vE0); | ||
389 | // cData.vE1 has been calculated before -> so save some cycles here | ||
390 | dVector3Subtract(v0 ,v2 , cData.vE2); | ||
391 | |||
392 | // calculate caps centers in absolute space | ||
393 | dVector3 vCp0; | ||
394 | vCp0[0] = cData.vCylinderPos[0] + cData.vCylinderAxis[0]*(cData.fCylinderSize* REAL(0.5)); | ||
395 | vCp0[1] = cData.vCylinderPos[1] + cData.vCylinderAxis[1]*(cData.fCylinderSize* REAL(0.5)); | ||
396 | vCp0[2] = cData.vCylinderPos[2] + cData.vCylinderAxis[2]*(cData.fCylinderSize* REAL(0.5)); | ||
397 | |||
398 | dVector3 vCp1; | ||
399 | vCp1[0] = cData.vCylinderPos[0] - cData.vCylinderAxis[0]*(cData.fCylinderSize* REAL(0.5)); | ||
400 | vCp1[1] = cData.vCylinderPos[1] - cData.vCylinderAxis[1]*(cData.fCylinderSize* REAL(0.5)); | ||
401 | vCp1[2] = cData.vCylinderPos[2] - cData.vCylinderAxis[2]*(cData.fCylinderSize* REAL(0.5)); | ||
402 | |||
403 | // reset best axis | ||
404 | cData.iBestAxis = 0; | ||
405 | dVector3 vAxis; | ||
406 | |||
407 | // axis cData.vNormal | ||
408 | //vAxis = -cData.vNormal; | ||
409 | vAxis[0] = -cData.vNormal[0]; | ||
410 | vAxis[1] = -cData.vNormal[1]; | ||
411 | vAxis[2] = -cData.vNormal[2]; | ||
412 | if (!_cldTestAxis(cData, v0, v1, v2, vAxis, 1, true)) | ||
413 | { | ||
414 | return false; | ||
415 | } | ||
416 | |||
417 | // axis CxE0 | ||
418 | // vAxis = ( cData.vCylinderAxis cross cData.vE0 ); | ||
419 | dVector3Cross(cData.vCylinderAxis, cData.vE0,vAxis); | ||
420 | if (!_cldTestAxis(cData, v0, v1, v2, vAxis, 2)) | ||
421 | { | ||
422 | return false; | ||
423 | } | ||
424 | |||
425 | // axis CxE1 | ||
426 | // vAxis = ( cData.vCylinderAxis cross cData.vE1 ); | ||
427 | dVector3Cross(cData.vCylinderAxis, cData.vE1,vAxis); | ||
428 | if (!_cldTestAxis(cData, v0, v1, v2, vAxis, 3)) | ||
429 | { | ||
430 | return false; | ||
431 | } | ||
432 | |||
433 | // axis CxE2 | ||
434 | // vAxis = ( cData.vCylinderAxis cross cData.vE2 ); | ||
435 | dVector3Cross(cData.vCylinderAxis, cData.vE2,vAxis); | ||
436 | if (!_cldTestAxis( cData ,v0, v1, v2, vAxis, 4)) | ||
437 | { | ||
438 | return false; | ||
439 | } | ||
440 | |||
441 | // first vertex on triangle | ||
442 | // axis ((V0-Cp0) x C) x C | ||
443 | //vAxis = ( ( v0-vCp0 ) cross cData.vCylinderAxis ) cross cData.vCylinderAxis; | ||
444 | _CalculateAxis(v0 , vCp0 , cData.vCylinderAxis , vAxis); | ||
445 | if (!_cldTestAxis(cData, v0, v1, v2, vAxis, 11)) | ||
446 | { | ||
447 | return false; | ||
448 | } | ||
449 | |||
450 | // second vertex on triangle | ||
451 | // axis ((V1-Cp0) x C) x C | ||
452 | // vAxis = ( ( v1-vCp0 ) cross cData.vCylinderAxis ) cross cData.vCylinderAxis; | ||
453 | _CalculateAxis(v1 , vCp0 , cData.vCylinderAxis , vAxis); | ||
454 | if (!_cldTestAxis(cData, v0, v1, v2, vAxis, 12)) | ||
455 | { | ||
456 | return false; | ||
457 | } | ||
458 | |||
459 | // third vertex on triangle | ||
460 | // axis ((V2-Cp0) x C) x C | ||
461 | //vAxis = ( ( v2-vCp0 ) cross cData.vCylinderAxis ) cross cData.vCylinderAxis; | ||
462 | _CalculateAxis(v2 , vCp0 , cData.vCylinderAxis , vAxis); | ||
463 | if (!_cldTestAxis(cData, v0, v1, v2, vAxis, 13)) | ||
464 | { | ||
465 | return false; | ||
466 | } | ||
467 | |||
468 | // test cylinder axis | ||
469 | // vAxis = cData.vCylinderAxis; | ||
470 | dVector3Copy(cData.vCylinderAxis , vAxis); | ||
471 | if (!_cldTestAxis(cData , v0, v1, v2, vAxis, 14)) | ||
472 | { | ||
473 | return false; | ||
474 | } | ||
475 | |||
476 | // Test top and bottom circle ring of cylinder for separation | ||
477 | dVector3 vccATop; | ||
478 | vccATop[0] = cData.vCylinderPos[0] + cData.vCylinderAxis[0]*(cData.fCylinderSize * REAL(0.5)); | ||
479 | vccATop[1] = cData.vCylinderPos[1] + cData.vCylinderAxis[1]*(cData.fCylinderSize * REAL(0.5)); | ||
480 | vccATop[2] = cData.vCylinderPos[2] + cData.vCylinderAxis[2]*(cData.fCylinderSize * REAL(0.5)); | ||
481 | |||
482 | dVector3 vccABottom; | ||
483 | vccABottom[0] = cData.vCylinderPos[0] - cData.vCylinderAxis[0]*(cData.fCylinderSize * REAL(0.5)); | ||
484 | vccABottom[1] = cData.vCylinderPos[1] - cData.vCylinderAxis[1]*(cData.fCylinderSize * REAL(0.5)); | ||
485 | vccABottom[2] = cData.vCylinderPos[2] - cData.vCylinderAxis[2]*(cData.fCylinderSize * REAL(0.5)); | ||
486 | |||
487 | |||
488 | if (!_cldTestCircleToEdgeAxis(cData, v0, v1, v2, vccATop, cData.vCylinderAxis, v0, v1, 15)) | ||
489 | { | ||
490 | return false; | ||
491 | } | ||
492 | |||
493 | if (!_cldTestCircleToEdgeAxis(cData, v0, v1, v2, vccATop, cData.vCylinderAxis, v1, v2, 16)) | ||
494 | { | ||
495 | return false; | ||
496 | } | ||
497 | |||
498 | if (!_cldTestCircleToEdgeAxis(cData, v0, v1, v2, vccATop, cData.vCylinderAxis, v0, v2, 17)) | ||
499 | { | ||
500 | return false; | ||
501 | } | ||
502 | |||
503 | if (!_cldTestCircleToEdgeAxis(cData, v0, v1, v2, vccABottom, cData.vCylinderAxis, v0, v1, 18)) | ||
504 | { | ||
505 | return false; | ||
506 | } | ||
507 | |||
508 | if (!_cldTestCircleToEdgeAxis(cData, v0, v1, v2, vccABottom, cData.vCylinderAxis, v1, v2, 19)) | ||
509 | { | ||
510 | return false; | ||
511 | } | ||
512 | |||
513 | if (!_cldTestCircleToEdgeAxis(cData, v0, v1, v2, vccABottom, cData.vCylinderAxis, v0, v2, 20)) | ||
514 | { | ||
515 | return false; | ||
516 | } | ||
517 | |||
518 | return true; | ||
519 | } | ||
520 | |||
521 | bool _cldClipCylinderEdgeToTriangle(sData& cData, const dVector3 &v0, const dVector3 &v1, const dVector3 &v2) | ||
522 | { | ||
523 | // translate cylinder | ||
524 | dReal fTemp = dVector3Dot(cData.vCylinderAxis , cData.vContactNormal); | ||
525 | dVector3 vN2; | ||
526 | vN2[0] = cData.vContactNormal[0] - cData.vCylinderAxis[0]*fTemp; | ||
527 | vN2[1] = cData.vContactNormal[1] - cData.vCylinderAxis[1]*fTemp; | ||
528 | vN2[2] = cData.vContactNormal[2] - cData.vCylinderAxis[2]*fTemp; | ||
529 | |||
530 | fTemp = dVector3Length(vN2); | ||
531 | if (fTemp < REAL(1e-5)) | ||
532 | { | ||
533 | return false; | ||
534 | } | ||
535 | |||
536 | // Normalize it | ||
537 | vN2[0] /= fTemp; | ||
538 | vN2[1] /= fTemp; | ||
539 | vN2[2] /= fTemp; | ||
540 | |||
541 | // calculate caps centers in absolute space | ||
542 | dVector3 vCposTrans; | ||
543 | vCposTrans[0] = cData.vCylinderPos[0] + vN2[0]*cData.fCylinderRadius; | ||
544 | vCposTrans[1] = cData.vCylinderPos[1] + vN2[1]*cData.fCylinderRadius; | ||
545 | vCposTrans[2] = cData.vCylinderPos[2] + vN2[2]*cData.fCylinderRadius; | ||
546 | |||
547 | dVector3 vCEdgePoint0; | ||
548 | vCEdgePoint0[0] = vCposTrans[0] + cData.vCylinderAxis[0] * (cData.fCylinderSize* REAL(0.5)); | ||
549 | vCEdgePoint0[1] = vCposTrans[1] + cData.vCylinderAxis[1] * (cData.fCylinderSize* REAL(0.5)); | ||
550 | vCEdgePoint0[2] = vCposTrans[2] + cData.vCylinderAxis[2] * (cData.fCylinderSize* REAL(0.5)); | ||
551 | |||
552 | dVector3 vCEdgePoint1; | ||
553 | vCEdgePoint1[0] = vCposTrans[0] - cData.vCylinderAxis[0] * (cData.fCylinderSize* REAL(0.5)); | ||
554 | vCEdgePoint1[1] = vCposTrans[1] - cData.vCylinderAxis[1] * (cData.fCylinderSize* REAL(0.5)); | ||
555 | vCEdgePoint1[2] = vCposTrans[2] - cData.vCylinderAxis[2] * (cData.fCylinderSize* REAL(0.5)); | ||
556 | |||
557 | // transform cylinder edge points into triangle space | ||
558 | vCEdgePoint0[0] -= v0[0]; | ||
559 | vCEdgePoint0[1] -= v0[1]; | ||
560 | vCEdgePoint0[2] -= v0[2]; | ||
561 | |||
562 | vCEdgePoint1[0] -= v0[0]; | ||
563 | vCEdgePoint1[1] -= v0[1]; | ||
564 | vCEdgePoint1[2] -= v0[2]; | ||
565 | |||
566 | dVector4 plPlane; | ||
567 | dVector3 vPlaneNormal; | ||
568 | |||
569 | // triangle plane | ||
570 | //plPlane = Plane4f( -cData.vNormal, 0); | ||
571 | vPlaneNormal[0] = -cData.vNormal[0]; | ||
572 | vPlaneNormal[1] = -cData.vNormal[1]; | ||
573 | vPlaneNormal[2] = -cData.vNormal[2]; | ||
574 | dConstructPlane(vPlaneNormal,REAL(0.0),plPlane); | ||
575 | if(!dClipEdgeToPlane( vCEdgePoint0, vCEdgePoint1, plPlane )) | ||
576 | { | ||
577 | return false; | ||
578 | } | ||
579 | |||
580 | // plane with edge 0 | ||
581 | //plPlane = Plane4f( ( cData.vNormal cross cData.vE0 ), REAL(1e-5)); | ||
582 | dVector3Cross(cData.vNormal,cData.vE0,vPlaneNormal); | ||
583 | dConstructPlane(vPlaneNormal,REAL(1e-5),plPlane); | ||
584 | if(!dClipEdgeToPlane( vCEdgePoint0, vCEdgePoint1, plPlane )) | ||
585 | { | ||
586 | return false; | ||
587 | } | ||
588 | |||
589 | // plane with edge 1 | ||
590 | //dVector3 vTemp = ( cData.vNormal cross cData.vE1 ); | ||
591 | dVector3Cross(cData.vNormal,cData.vE1,vPlaneNormal); | ||
592 | fTemp = dVector3Dot(cData.vE0 , vPlaneNormal) - REAL(1e-5); | ||
593 | //plPlane = Plane4f( vTemp, -(( cData.vE0 dot vTemp )-REAL(1e-5))); | ||
594 | dConstructPlane(vPlaneNormal,-fTemp,plPlane); | ||
595 | if(!dClipEdgeToPlane( vCEdgePoint0, vCEdgePoint1, plPlane )) | ||
596 | { | ||
597 | return false; | ||
598 | } | ||
599 | |||
600 | // plane with edge 2 | ||
601 | // plPlane = Plane4f( ( cData.vNormal cross cData.vE2 ), REAL(1e-5)); | ||
602 | dVector3Cross(cData.vNormal,cData.vE2,vPlaneNormal); | ||
603 | dConstructPlane(vPlaneNormal,REAL(1e-5),plPlane); | ||
604 | if(!dClipEdgeToPlane( vCEdgePoint0, vCEdgePoint1, plPlane )) | ||
605 | { | ||
606 | return false; | ||
607 | } | ||
608 | |||
609 | // return capsule edge points into absolute space | ||
610 | vCEdgePoint0[0] += v0[0]; | ||
611 | vCEdgePoint0[1] += v0[1]; | ||
612 | vCEdgePoint0[2] += v0[2]; | ||
613 | |||
614 | vCEdgePoint1[0] += v0[0]; | ||
615 | vCEdgePoint1[1] += v0[1]; | ||
616 | vCEdgePoint1[2] += v0[2]; | ||
617 | |||
618 | // calculate depths for both contact points | ||
619 | dVector3 vTemp; | ||
620 | dVector3Subtract(vCEdgePoint0,cData.vCylinderPos, vTemp); | ||
621 | dReal fRestDepth0 = -dVector3Dot(vTemp,cData.vContactNormal) + cData.fBestrt; | ||
622 | dVector3Subtract(vCEdgePoint1,cData.vCylinderPos, vTemp); | ||
623 | dReal fRestDepth1 = -dVector3Dot(vTemp,cData.vContactNormal) + cData.fBestrt; | ||
624 | |||
625 | dReal fDepth0 = cData.fBestDepth - (fRestDepth0); | ||
626 | dReal fDepth1 = cData.fBestDepth - (fRestDepth1); | ||
627 | |||
628 | // clamp depths to zero | ||
629 | if(fDepth0 < REAL(0.0) ) | ||
630 | { | ||
631 | fDepth0 = REAL(0.0); | ||
632 | } | ||
633 | |||
634 | if(fDepth1<REAL(0.0)) | ||
635 | { | ||
636 | fDepth1 = REAL(0.0); | ||
637 | } | ||
638 | |||
639 | // Generate contact 0 | ||
640 | { | ||
641 | cData.gLocalContacts[cData.nContacts].fDepth = fDepth0; | ||
642 | dVector3Copy(cData.vContactNormal,cData.gLocalContacts[cData.nContacts].vNormal); | ||
643 | dVector3Copy(vCEdgePoint0,cData.gLocalContacts[cData.nContacts].vPos); | ||
644 | cData.gLocalContacts[cData.nContacts].nFlags = 1; | ||
645 | cData.nContacts++; | ||
646 | if(cData.nContacts >= (cData.iFlags & NUMC_MASK)) | ||
647 | return true; | ||
648 | } | ||
649 | |||
650 | // Generate contact 1 | ||
651 | { | ||
652 | // generate contacts | ||
653 | cData.gLocalContacts[cData.nContacts].fDepth = fDepth1; | ||
654 | dVector3Copy(cData.vContactNormal,cData.gLocalContacts[cData.nContacts].vNormal); | ||
655 | dVector3Copy(vCEdgePoint1,cData.gLocalContacts[cData.nContacts].vPos); | ||
656 | cData.gLocalContacts[cData.nContacts].nFlags = 1; | ||
657 | cData.nContacts++; | ||
658 | } | ||
659 | |||
660 | return true; | ||
661 | } | ||
662 | |||
663 | void _cldClipCylinderToTriangle(sData& cData,const dVector3 &v0, const dVector3 &v1, const dVector3 &v2) | ||
664 | { | ||
665 | int i = 0; | ||
666 | dVector3 avPoints[3]; | ||
667 | dVector3 avTempArray1[nMAX_CYLINDER_TRIANGLE_CLIP_POINTS]; | ||
668 | dVector3 avTempArray2[nMAX_CYLINDER_TRIANGLE_CLIP_POINTS]; | ||
669 | |||
670 | dSetZero(&avTempArray1[0][0],nMAX_CYLINDER_TRIANGLE_CLIP_POINTS * 4); | ||
671 | dSetZero(&avTempArray2[0][0],nMAX_CYLINDER_TRIANGLE_CLIP_POINTS * 4); | ||
672 | |||
673 | // setup array of triangle vertices | ||
674 | dVector3Copy(v0,avPoints[0]); | ||
675 | dVector3Copy(v1,avPoints[1]); | ||
676 | dVector3Copy(v2,avPoints[2]); | ||
677 | |||
678 | dVector3 vCylinderCirclePos, vCylinderCircleNormal_Rel; | ||
679 | dSetZero(vCylinderCircleNormal_Rel,4); | ||
680 | // check which circle from cylinder we take for clipping | ||
681 | if ( dVector3Dot(cData.vCylinderAxis , cData.vContactNormal) > REAL(0.0)) | ||
682 | { | ||
683 | // get top circle | ||
684 | vCylinderCirclePos[0] = cData.vCylinderPos[0] + cData.vCylinderAxis[0]*(cData.fCylinderSize*REAL(0.5)); | ||
685 | vCylinderCirclePos[1] = cData.vCylinderPos[1] + cData.vCylinderAxis[1]*(cData.fCylinderSize*REAL(0.5)); | ||
686 | vCylinderCirclePos[2] = cData.vCylinderPos[2] + cData.vCylinderAxis[2]*(cData.fCylinderSize*REAL(0.5)); | ||
687 | |||
688 | vCylinderCircleNormal_Rel[nCYLINDER_AXIS] = REAL(-1.0); | ||
689 | } | ||
690 | else | ||
691 | { | ||
692 | // get bottom circle | ||
693 | vCylinderCirclePos[0] = cData.vCylinderPos[0] - cData.vCylinderAxis[0]*(cData.fCylinderSize*REAL(0.5)); | ||
694 | vCylinderCirclePos[1] = cData.vCylinderPos[1] - cData.vCylinderAxis[1]*(cData.fCylinderSize*REAL(0.5)); | ||
695 | vCylinderCirclePos[2] = cData.vCylinderPos[2] - cData.vCylinderAxis[2]*(cData.fCylinderSize*REAL(0.5)); | ||
696 | |||
697 | vCylinderCircleNormal_Rel[nCYLINDER_AXIS] = REAL(1.0); | ||
698 | } | ||
699 | |||
700 | dVector3 vTemp; | ||
701 | dQuatInv(cData.qCylinderRot , cData.qInvCylinderRot); | ||
702 | // transform triangle points to space of cylinder circle | ||
703 | for(i=0; i<3; i++) | ||
704 | { | ||
705 | dVector3Subtract(avPoints[i] , vCylinderCirclePos , vTemp); | ||
706 | dQuatTransform(cData.qInvCylinderRot,vTemp,avPoints[i]); | ||
707 | } | ||
708 | |||
709 | int iTmpCounter1 = 0; | ||
710 | int iTmpCounter2 = 0; | ||
711 | dVector4 plPlane; | ||
712 | |||
713 | // plane of cylinder that contains circle for intersection | ||
714 | //plPlane = Plane4f( vCylinderCircleNormal_Rel, 0.0f ); | ||
715 | dConstructPlane(vCylinderCircleNormal_Rel,REAL(0.0),plPlane); | ||
716 | dClipPolyToPlane(avPoints, 3, avTempArray1, iTmpCounter1, plPlane); | ||
717 | |||
718 | // Body of base circle of Cylinder | ||
719 | int nCircleSegment = 0; | ||
720 | for (nCircleSegment = 0; nCircleSegment < nCYLINDER_CIRCLE_SEGMENTS; nCircleSegment++) | ||
721 | { | ||
722 | dConstructPlane(cData.avCylinderNormals[nCircleSegment],cData.fCylinderRadius,plPlane); | ||
723 | |||
724 | if (0 == (nCircleSegment % 2)) | ||
725 | { | ||
726 | dClipPolyToPlane( avTempArray1 , iTmpCounter1 , avTempArray2, iTmpCounter2, plPlane); | ||
727 | } | ||
728 | else | ||
729 | { | ||
730 | dClipPolyToPlane( avTempArray2, iTmpCounter2, avTempArray1 , iTmpCounter1 , plPlane ); | ||
731 | } | ||
732 | |||
733 | dIASSERT( iTmpCounter1 >= 0 && iTmpCounter1 <= nMAX_CYLINDER_TRIANGLE_CLIP_POINTS ); | ||
734 | dIASSERT( iTmpCounter2 >= 0 && iTmpCounter2 <= nMAX_CYLINDER_TRIANGLE_CLIP_POINTS ); | ||
735 | } | ||
736 | |||
737 | // back transform clipped points to absolute space | ||
738 | dReal ftmpdot; | ||
739 | dReal fTempDepth; | ||
740 | dVector3 vPoint; | ||
741 | |||
742 | if (nCircleSegment %2) | ||
743 | { | ||
744 | for( i=0; i<iTmpCounter2; i++) | ||
745 | { | ||
746 | dQuatTransform(cData.qCylinderRot,avTempArray2[i], vPoint); | ||
747 | vPoint[0] += vCylinderCirclePos[0]; | ||
748 | vPoint[1] += vCylinderCirclePos[1]; | ||
749 | vPoint[2] += vCylinderCirclePos[2]; | ||
750 | |||
751 | dVector3Subtract(vPoint,cData.vCylinderPos,vTemp); | ||
752 | ftmpdot = dFabs(dVector3Dot(vTemp, cData.vContactNormal)); | ||
753 | fTempDepth = cData.fBestrt - ftmpdot; | ||
754 | // Depth must be positive | ||
755 | if (fTempDepth > REAL(0.0)) | ||
756 | { | ||
757 | cData.gLocalContacts[cData.nContacts].fDepth = fTempDepth; | ||
758 | dVector3Copy(cData.vContactNormal,cData.gLocalContacts[cData.nContacts].vNormal); | ||
759 | dVector3Copy(vPoint,cData.gLocalContacts[cData.nContacts].vPos); | ||
760 | cData.gLocalContacts[cData.nContacts].nFlags = 1; | ||
761 | cData.nContacts++; | ||
762 | if(cData.nContacts >= (cData.iFlags & NUMC_MASK)) | ||
763 | return;; | ||
764 | } | ||
765 | } | ||
766 | } | ||
767 | else | ||
768 | { | ||
769 | for( i=0; i<iTmpCounter1; i++) | ||
770 | { | ||
771 | dQuatTransform(cData.qCylinderRot,avTempArray1[i], vPoint); | ||
772 | vPoint[0] += vCylinderCirclePos[0]; | ||
773 | vPoint[1] += vCylinderCirclePos[1]; | ||
774 | vPoint[2] += vCylinderCirclePos[2]; | ||
775 | |||
776 | dVector3Subtract(vPoint,cData.vCylinderPos,vTemp); | ||
777 | ftmpdot = dFabs(dVector3Dot(vTemp, cData.vContactNormal)); | ||
778 | fTempDepth = cData.fBestrt - ftmpdot; | ||
779 | // Depth must be positive | ||
780 | if (fTempDepth > REAL(0.0)) | ||
781 | { | ||
782 | cData.gLocalContacts[cData.nContacts].fDepth = fTempDepth; | ||
783 | dVector3Copy(cData.vContactNormal,cData.gLocalContacts[cData.nContacts].vNormal); | ||
784 | dVector3Copy(vPoint,cData.gLocalContacts[cData.nContacts].vPos); | ||
785 | cData.gLocalContacts[cData.nContacts].nFlags = 1; | ||
786 | cData.nContacts++; | ||
787 | if(cData.nContacts >= (cData.iFlags & NUMC_MASK)) | ||
788 | return;; | ||
789 | } | ||
790 | } | ||
791 | } | ||
792 | } | ||
793 | |||
794 | void TestOneTriangleVsCylinder( sData& cData, | ||
795 | const dVector3 &v0, | ||
796 | const dVector3 &v1, | ||
797 | const dVector3 &v2, | ||
798 | const bool bDoubleSided) | ||
799 | { | ||
800 | |||
801 | // calculate triangle normal | ||
802 | dVector3Subtract( v2 , v1 ,cData.vE1); | ||
803 | dVector3 vTemp; | ||
804 | dVector3Subtract( v0 , v1 ,vTemp); | ||
805 | dVector3Cross(cData.vE1 , vTemp , cData.vNormal ); | ||
806 | |||
807 | dNormalize3( cData.vNormal); | ||
808 | |||
809 | // create plane from triangle | ||
810 | //Plane4f plTrianglePlane = Plane4f( vPolyNormal, v0 ); | ||
811 | dReal plDistance = -dVector3Dot(v0, cData.vNormal); | ||
812 | dVector4 plTrianglePlane; | ||
813 | dConstructPlane( cData.vNormal,plDistance,plTrianglePlane); | ||
814 | |||
815 | // calculate sphere distance to plane | ||
816 | dReal fDistanceCylinderCenterToPlane = dPointPlaneDistance(cData.vCylinderPos , plTrianglePlane); | ||
817 | |||
818 | // Sphere must be over positive side of triangle | ||
819 | if(fDistanceCylinderCenterToPlane < 0 && !bDoubleSided) | ||
820 | { | ||
821 | // if not don't generate contacts | ||
822 | return; | ||
823 | } | ||
824 | |||
825 | dVector3 vPnt0; | ||
826 | dVector3 vPnt1; | ||
827 | dVector3 vPnt2; | ||
828 | |||
829 | if (fDistanceCylinderCenterToPlane < REAL(0.0) ) | ||
830 | { | ||
831 | // flip it | ||
832 | dVector3Copy(v0 , vPnt0); | ||
833 | dVector3Copy(v1 , vPnt2); | ||
834 | dVector3Copy(v2 , vPnt1); | ||
835 | } | ||
836 | else | ||
837 | { | ||
838 | dVector3Copy(v0 , vPnt0); | ||
839 | dVector3Copy(v1 , vPnt1); | ||
840 | dVector3Copy(v2 , vPnt2); | ||
841 | } | ||
842 | |||
843 | cData.fBestDepth = MAX_REAL; | ||
844 | |||
845 | // do intersection test and find best separating axis | ||
846 | if(!_cldTestSeparatingAxes(cData , vPnt0, vPnt1, vPnt2) ) | ||
847 | { | ||
848 | // if not found do nothing | ||
849 | return; | ||
850 | } | ||
851 | |||
852 | // if best separation axis is not found | ||
853 | if ( cData.iBestAxis == 0 ) | ||
854 | { | ||
855 | // this should not happen (we should already exit in that case) | ||
856 | dIASSERT(false); | ||
857 | // do nothing | ||
858 | return; | ||
859 | } | ||
860 | |||
861 | dReal fdot = dVector3Dot( cData.vContactNormal , cData.vCylinderAxis ); | ||
862 | |||
863 | // choose which clipping method are we going to apply | ||
864 | if (dFabs(fdot) < REAL(0.9) ) | ||
865 | { | ||
866 | if (!_cldClipCylinderEdgeToTriangle(cData ,vPnt0, vPnt1, vPnt2)) | ||
867 | { | ||
868 | return; | ||
869 | } | ||
870 | } | ||
871 | else | ||
872 | { | ||
873 | _cldClipCylinderToTriangle(cData ,vPnt0, vPnt1, vPnt2); | ||
874 | } | ||
875 | |||
876 | } | ||
877 | |||
878 | void _InitCylinderTrimeshData(sData& cData) | ||
879 | { | ||
880 | // get cylinder information | ||
881 | // Rotation | ||
882 | const dReal* pRotCyc = dGeomGetRotation(cData.gCylinder); | ||
883 | dMatrix3Copy(pRotCyc,cData.mCylinderRot); | ||
884 | dGeomGetQuaternion(cData.gCylinder,cData.qCylinderRot); | ||
885 | |||
886 | // Position | ||
887 | const dVector3* pPosCyc = (const dVector3*)dGeomGetPosition(cData.gCylinder); | ||
888 | dVector3Copy(*pPosCyc,cData.vCylinderPos); | ||
889 | // Cylinder axis | ||
890 | dMat3GetCol(cData.mCylinderRot,nCYLINDER_AXIS,cData.vCylinderAxis); | ||
891 | // get cylinder radius and size | ||
892 | dGeomCylinderGetParams(cData.gCylinder,&cData.fCylinderRadius,&cData.fCylinderSize); | ||
893 | |||
894 | // get trimesh position and orientation | ||
895 | const dReal* pRotTris = dGeomGetRotation(cData.gTrimesh); | ||
896 | dMatrix3Copy(pRotTris,cData.mTrimeshRot); | ||
897 | dGeomGetQuaternion(cData.gTrimesh,cData.qTrimeshRot); | ||
898 | |||
899 | // Position | ||
900 | const dVector3* pPosTris = (const dVector3*)dGeomGetPosition(cData.gTrimesh); | ||
901 | dVector3Copy(*pPosTris,cData.vTrimeshPos); | ||
902 | |||
903 | |||
904 | // calculate basic angle for 8-gon | ||
905 | dReal fAngle = M_PI / nCYLINDER_CIRCLE_SEGMENTS; | ||
906 | // calculate angle increment | ||
907 | dReal fAngleIncrement = fAngle*REAL(2.0); | ||
908 | |||
909 | // calculate plane normals | ||
910 | // axis dependant code | ||
911 | for(int i=0; i<nCYLINDER_CIRCLE_SEGMENTS; i++) | ||
912 | { | ||
913 | cData.avCylinderNormals[i][0] = -dCos(fAngle); | ||
914 | cData.avCylinderNormals[i][1] = -dSin(fAngle); | ||
915 | cData.avCylinderNormals[i][2] = REAL(0.0); | ||
916 | |||
917 | fAngle += fAngleIncrement; | ||
918 | } | ||
919 | |||
920 | dSetZero(cData.vBestPoint,4); | ||
921 | // reset best depth | ||
922 | cData.fBestCenter = REAL(0.0); | ||
923 | } | ||
924 | |||
925 | #if dTRIMESH_ENABLED | ||
926 | |||
927 | // OPCODE version of cylinder to mesh collider | ||
928 | #if dTRIMESH_OPCODE | ||
929 | int dCollideCylinderTrimesh(dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip) | ||
930 | { | ||
931 | dIASSERT( skip >= (int)sizeof( dContactGeom ) ); | ||
932 | dIASSERT( o1->type == dCylinderClass ); | ||
933 | dIASSERT( o2->type == dTriMeshClass ); | ||
934 | dIASSERT ((flags & NUMC_MASK) >= 1); | ||
935 | |||
936 | // Main data holder | ||
937 | sData cData; | ||
938 | |||
939 | // Assign ODE stuff | ||
940 | cData.gCylinder = o1; | ||
941 | cData.gTrimesh = (dxTriMesh*)o2; | ||
942 | cData.iFlags = flags; | ||
943 | cData.iSkip = skip; | ||
944 | cData.gContact = contact; | ||
945 | cData.nContacts = 0; | ||
946 | |||
947 | _InitCylinderTrimeshData(cData); | ||
948 | |||
949 | OBBCollider& Collider = cData.gTrimesh->_OBBCollider; | ||
950 | |||
951 | Point cCenter(cData.vCylinderPos[0],cData.vCylinderPos[1],cData.vCylinderPos[2]); | ||
952 | |||
953 | Point cExtents(cData.fCylinderRadius,cData.fCylinderRadius,cData.fCylinderRadius); | ||
954 | cExtents[nCYLINDER_AXIS] = cData.fCylinderSize * REAL(0.5); | ||
955 | |||
956 | Matrix3x3 obbRot; | ||
957 | |||
958 | // It is a potential issue to explicitly cast to float | ||
959 | // if custom width floating point type is introduced in OPCODE. | ||
960 | // It is necessary to make a typedef and cast to it | ||
961 | // (e.g. typedef float opc_float;) | ||
962 | // However I'm not sure in what header it should be added. | ||
963 | |||
964 | obbRot[0][0] = /*(float)*/cData.mCylinderRot[0]; | ||
965 | obbRot[1][0] = /*(float)*/cData.mCylinderRot[1]; | ||
966 | obbRot[2][0] = /*(float)*/cData.mCylinderRot[2]; | ||
967 | |||
968 | obbRot[0][1] = /*(float)*/cData.mCylinderRot[4]; | ||
969 | obbRot[1][1] = /*(float)*/cData.mCylinderRot[5]; | ||
970 | obbRot[2][1] = /*(float)*/cData.mCylinderRot[6]; | ||
971 | |||
972 | obbRot[0][2] = /*(float)*/cData.mCylinderRot[8]; | ||
973 | obbRot[1][2] = /*(float)*/cData.mCylinderRot[9]; | ||
974 | obbRot[2][2] = /*(float)*/cData.mCylinderRot[10]; | ||
975 | |||
976 | OBB obbCapsule(cCenter,cExtents,obbRot); | ||
977 | |||
978 | Matrix4x4 CapsuleMatrix; | ||
979 | MakeMatrix(cData.vCylinderPos, cData.mCylinderRot, CapsuleMatrix); | ||
980 | |||
981 | Matrix4x4 MeshMatrix; | ||
982 | MakeMatrix(cData.vTrimeshPos, cData.mTrimeshRot, MeshMatrix); | ||
983 | |||
984 | // TC results | ||
985 | if (cData.gTrimesh->doBoxTC) | ||
986 | { | ||
987 | dxTriMesh::BoxTC* BoxTC = 0; | ||
988 | for (int i = 0; i < cData.gTrimesh->BoxTCCache.size(); i++) | ||
989 | { | ||
990 | if (cData.gTrimesh->BoxTCCache[i].Geom == cData.gCylinder) | ||
991 | { | ||
992 | BoxTC = &cData.gTrimesh->BoxTCCache[i]; | ||
993 | break; | ||
994 | } | ||
995 | } | ||
996 | if (!BoxTC) | ||
997 | { | ||
998 | cData.gTrimesh->BoxTCCache.push(dxTriMesh::BoxTC()); | ||
999 | |||
1000 | BoxTC = &cData.gTrimesh->BoxTCCache[cData.gTrimesh->BoxTCCache.size() - 1]; | ||
1001 | BoxTC->Geom = cData.gCylinder; | ||
1002 | BoxTC->FatCoeff = REAL(1.0); | ||
1003 | } | ||
1004 | |||
1005 | // Intersect | ||
1006 | Collider.SetTemporalCoherence(true); | ||
1007 | Collider.Collide(*BoxTC, obbCapsule, cData.gTrimesh->Data->BVTree, null, &MeshMatrix); | ||
1008 | } | ||
1009 | else | ||
1010 | { | ||
1011 | Collider.SetTemporalCoherence(false); | ||
1012 | Collider.Collide(dxTriMesh::defaultBoxCache, obbCapsule, cData.gTrimesh->Data->BVTree, null,&MeshMatrix); | ||
1013 | } | ||
1014 | |||
1015 | // Retrieve data | ||
1016 | int TriCount = Collider.GetNbTouchedPrimitives(); | ||
1017 | const int* Triangles = (const int*)Collider.GetTouchedPrimitives(); | ||
1018 | |||
1019 | |||
1020 | if (TriCount != 0) | ||
1021 | { | ||
1022 | if (cData.gTrimesh->ArrayCallback != null) | ||
1023 | { | ||
1024 | cData.gTrimesh->ArrayCallback(cData.gTrimesh, cData.gCylinder, Triangles, TriCount); | ||
1025 | } | ||
1026 | |||
1027 | // allocate buffer for local contacts on stack | ||
1028 | cData.gLocalContacts = (sLocalContactData*)dALLOCA16(sizeof(sLocalContactData)*(cData.iFlags & NUMC_MASK)); | ||
1029 | |||
1030 | int ctContacts0 = 0; | ||
1031 | |||
1032 | // loop through all intersecting triangles | ||
1033 | for (int i = 0; i < TriCount; i++) | ||
1034 | { | ||
1035 | const int Triint = Triangles[i]; | ||
1036 | if (!Callback(cData.gTrimesh, cData.gCylinder, Triint)) continue; | ||
1037 | |||
1038 | |||
1039 | dVector3 dv[3]; | ||
1040 | FetchTriangle(cData.gTrimesh, Triint, cData.vTrimeshPos, cData.mTrimeshRot, dv); | ||
1041 | |||
1042 | // test this triangle | ||
1043 | TestOneTriangleVsCylinder(cData , dv[0],dv[1],dv[2], false); | ||
1044 | |||
1045 | // fill-in tri index for generated contacts | ||
1046 | for (; ctContacts0<cData.nContacts; ctContacts0++) | ||
1047 | cData.gLocalContacts[ctContacts0].triIndex = Triint; | ||
1048 | |||
1049 | // Putting "break" at the end of loop prevents unnecessary checks on first pass and "continue" | ||
1050 | if(cData.nContacts >= (cData.iFlags & NUMC_MASK)) | ||
1051 | { | ||
1052 | break; | ||
1053 | } | ||
1054 | } | ||
1055 | } | ||
1056 | |||
1057 | return _ProcessLocalContacts(cData); | ||
1058 | } | ||
1059 | #endif | ||
1060 | |||
1061 | // GIMPACT version of cylinder to mesh collider | ||
1062 | #if dTRIMESH_GIMPACT | ||
1063 | int dCollideCylinderTrimesh(dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip) | ||
1064 | { | ||
1065 | dIASSERT( skip >= (int)sizeof( dContactGeom ) ); | ||
1066 | dIASSERT( o1->type == dCylinderClass ); | ||
1067 | dIASSERT( o2->type == dTriMeshClass ); | ||
1068 | dIASSERT ((flags & NUMC_MASK) >= 1); | ||
1069 | |||
1070 | // Main data holder | ||
1071 | sData cData; | ||
1072 | |||
1073 | // Assign ODE stuff | ||
1074 | cData.gCylinder = o1; | ||
1075 | cData.gTrimesh = (dxTriMesh*)o2; | ||
1076 | cData.iFlags = flags; | ||
1077 | cData.iSkip = skip; | ||
1078 | cData.gContact = contact; | ||
1079 | cData.nContacts = 0; | ||
1080 | |||
1081 | _InitCylinderTrimeshData(cData); | ||
1082 | |||
1083 | //*****at first , collide box aabb******// | ||
1084 | |||
1085 | aabb3f test_aabb; | ||
1086 | |||
1087 | test_aabb.minX = o1->aabb[0]; | ||
1088 | test_aabb.maxX = o1->aabb[1]; | ||
1089 | test_aabb.minY = o1->aabb[2]; | ||
1090 | test_aabb.maxY = o1->aabb[3]; | ||
1091 | test_aabb.minZ = o1->aabb[4]; | ||
1092 | test_aabb.maxZ = o1->aabb[5]; | ||
1093 | |||
1094 | |||
1095 | GDYNAMIC_ARRAY collision_result; | ||
1096 | GIM_CREATE_BOXQUERY_LIST(collision_result); | ||
1097 | |||
1098 | gim_aabbset_box_collision(&test_aabb, &cData.gTrimesh->m_collision_trimesh.m_aabbset , &collision_result); | ||
1099 | |||
1100 | if(collision_result.m_size==0) | ||
1101 | { | ||
1102 | GIM_DYNARRAY_DESTROY(collision_result); | ||
1103 | return 0; | ||
1104 | } | ||
1105 | //*****Set globals for box collision******// | ||
1106 | |||
1107 | int ctContacts0 = 0; | ||
1108 | cData.gLocalContacts = (sLocalContactData*)dALLOCA16(sizeof(sLocalContactData)*(cData.iFlags & NUMC_MASK)); | ||
1109 | |||
1110 | GUINT * boxesresult = GIM_DYNARRAY_POINTER(GUINT,collision_result); | ||
1111 | GIM_TRIMESH * ptrimesh = &cData.gTrimesh->m_collision_trimesh; | ||
1112 | |||
1113 | gim_trimesh_locks_work_data(ptrimesh); | ||
1114 | |||
1115 | |||
1116 | for(unsigned int i=0;i<collision_result.m_size;i++) | ||
1117 | { | ||
1118 | const int Triint = boxesresult[i]; | ||
1119 | |||
1120 | dVector3 dv[3]; | ||
1121 | gim_trimesh_get_triangle_vertices(ptrimesh, Triint,dv[0],dv[1],dv[2]); | ||
1122 | // test this triangle | ||
1123 | TestOneTriangleVsCylinder(cData , dv[0],dv[1],dv[2], false); | ||
1124 | |||
1125 | // fill-in triangle index for generated contacts | ||
1126 | for (; ctContacts0<cData.nContacts; ctContacts0++) | ||
1127 | cData.gLocalContacts[ctContacts0].triIndex = Triint; | ||
1128 | |||
1129 | // Putting "break" at the end of loop prevents unnecessary checks on first pass and "continue" | ||
1130 | if(cData.nContacts >= (cData.iFlags & NUMC_MASK)) | ||
1131 | { | ||
1132 | break; | ||
1133 | } | ||
1134 | } | ||
1135 | |||
1136 | gim_trimesh_unlocks_work_data(ptrimesh); | ||
1137 | GIM_DYNARRAY_DESTROY(collision_result); | ||
1138 | |||
1139 | return _ProcessLocalContacts(cData); | ||
1140 | } | ||
1141 | #endif | ||
1142 | |||
1143 | #endif // dTRIMESH_ENABLED | ||
1144 | |||
1145 | |||