diff options
author | dan miller | 2007-10-19 05:20:48 +0000 |
---|---|---|
committer | dan miller | 2007-10-19 05:20:48 +0000 |
commit | d48ea5bb797037069d641da41da0f195f0124491 (patch) | |
tree | 40ff433d94859d629aac933d5ec73b382f62ba1a /libraries/ode-0.9/contrib/dCylinder/dCylinder.cpp | |
parent | dont ask (diff) | |
download | opensim-SC_OLD-d48ea5bb797037069d641da41da0f195f0124491.zip opensim-SC_OLD-d48ea5bb797037069d641da41da0f195f0124491.tar.gz opensim-SC_OLD-d48ea5bb797037069d641da41da0f195f0124491.tar.bz2 opensim-SC_OLD-d48ea5bb797037069d641da41da0f195f0124491.tar.xz |
one more for the gipper
Diffstat (limited to 'libraries/ode-0.9/contrib/dCylinder/dCylinder.cpp')
-rw-r--r-- | libraries/ode-0.9/contrib/dCylinder/dCylinder.cpp | 1445 |
1 files changed, 1445 insertions, 0 deletions
diff --git a/libraries/ode-0.9/contrib/dCylinder/dCylinder.cpp b/libraries/ode-0.9/contrib/dCylinder/dCylinder.cpp new file mode 100644 index 0000000..215da25 --- /dev/null +++ b/libraries/ode-0.9/contrib/dCylinder/dCylinder.cpp | |||
@@ -0,0 +1,1445 @@ | |||
1 | #include <ode/ode.h> | ||
2 | #include "dCylinder.h" | ||
3 | // given a pointer `p' to a dContactGeom, return the dContactGeom at | ||
4 | // p + skip bytes. | ||
5 | |||
6 | struct dxCylinder { // cylinder | ||
7 | dReal radius,lz; // radius, length along y axis // | ||
8 | }; | ||
9 | |||
10 | int dCylinderClassUser = -1; | ||
11 | |||
12 | #define NUMC_MASK (0xffff) | ||
13 | |||
14 | #define CONTACT(p,skip) ((dContactGeom*) (((char*)p) + (skip))) | ||
15 | |||
16 | ///////////////////////////////////////////////////////////////////////////////////////////////// | ||
17 | /////////////////////////////circleIntersection////////////////////////////////////////////////// | ||
18 | //this does following: | ||
19 | //takes two circles as normals to planes n1,n2, center points cp1,cp2,and radiuses r1,r2 | ||
20 | //finds line on which circles' planes intersect | ||
21 | //finds four points O1,O2 - intersection between the line and sphere with center cp1 radius r1 | ||
22 | // O3,O4 - intersection between the line and sphere with center cp2 radius r2 | ||
23 | //returns false if there is no intersection | ||
24 | //computes distances O1-O3, O1-O4, O2-O3, O2-O4 | ||
25 | //in "point" returns mean point between intersection points with smallest distance | ||
26 | ///////////////////////////////////////////////////////////////////////////////////////////////// | ||
27 | inline bool circleIntersection(const dReal* n1,const dReal* cp1,dReal r1,const dReal* n2,const dReal* cp2,dReal r2,dVector3 point){ | ||
28 | dReal c1=dDOT14(cp1,n1); | ||
29 | dReal c2=dDOT14(cp2,n2); | ||
30 | dReal cos=dDOT44(n1,n2); | ||
31 | dReal cos_2=cos*cos; | ||
32 | dReal sin_2=1-cos_2; | ||
33 | dReal p1=(c1-c2*cos)/sin_2; | ||
34 | dReal p2=(c2-c1*cos)/sin_2; | ||
35 | dVector3 lp={p1*n1[0]+p2*n2[0],p1*n1[4]+p2*n2[4],p1*n1[8]+p2*n2[8]}; | ||
36 | dVector3 n; | ||
37 | dCROSS144(n,=,n1,n2); | ||
38 | dVector3 LC1={lp[0]-cp1[0],lp[1]-cp1[1],lp[2]-cp1[2]}; | ||
39 | dVector3 LC2={lp[0]-cp2[0],lp[1]-cp2[1],lp[2]-cp2[2]}; | ||
40 | dReal A,B,C,B_A,B_A_2,D; | ||
41 | dReal t1,t2,t3,t4; | ||
42 | A=dDOT(n,n); | ||
43 | B=dDOT(LC1,n); | ||
44 | C=dDOT(LC1,LC1)-r1*r1; | ||
45 | B_A=B/A; | ||
46 | B_A_2=B_A*B_A; | ||
47 | D=B_A_2-C; | ||
48 | if(D<0.f){ //somewhat strange solution | ||
49 | //- it is needed to set some | ||
50 | //axis to sepparate cylinders | ||
51 | //when their edges approach | ||
52 | t1=-B_A+sqrtf(-D); | ||
53 | t2=-B_A-sqrtf(-D); | ||
54 | // return false; | ||
55 | } | ||
56 | else{ | ||
57 | t1=-B_A-sqrtf(D); | ||
58 | t2=-B_A+sqrtf(D); | ||
59 | } | ||
60 | B=dDOT(LC2,n); | ||
61 | C=dDOT(LC2,LC2)-r2*r2; | ||
62 | B_A=B/A; | ||
63 | B_A_2=B_A*B_A; | ||
64 | D=B_A_2-C; | ||
65 | |||
66 | if(D<0.f) { | ||
67 | t3=-B_A+sqrtf(-D); | ||
68 | t4=-B_A-sqrtf(-D); | ||
69 | // return false; | ||
70 | } | ||
71 | else{ | ||
72 | t3=-B_A-sqrtf(D); | ||
73 | t4=-B_A+sqrtf(D); | ||
74 | } | ||
75 | dVector3 O1={lp[0]+n[0]*t1,lp[1]+n[1]*t1,lp[2]+n[2]*t1}; | ||
76 | dVector3 O2={lp[0]+n[0]*t2,lp[1]+n[1]*t2,lp[2]+n[2]*t2}; | ||
77 | |||
78 | dVector3 O3={lp[0]+n[0]*t3,lp[1]+n[1]*t3,lp[2]+n[2]*t3}; | ||
79 | dVector3 O4={lp[0]+n[0]*t4,lp[1]+n[1]*t4,lp[2]+n[2]*t4}; | ||
80 | |||
81 | dVector3 L1_3={O3[0]-O1[0],O3[1]-O1[1],O3[2]-O1[2]}; | ||
82 | dVector3 L1_4={O4[0]-O1[0],O4[1]-O1[1],O4[2]-O1[2]}; | ||
83 | |||
84 | dVector3 L2_3={O3[0]-O2[0],O3[1]-O2[1],O3[2]-O2[2]}; | ||
85 | dVector3 L2_4={O4[0]-O2[0],O4[1]-O2[1],O4[2]-O2[2]}; | ||
86 | |||
87 | |||
88 | dReal l1_3=dDOT(L1_3,L1_3); | ||
89 | dReal l1_4=dDOT(L1_4,L1_4); | ||
90 | |||
91 | dReal l2_3=dDOT(L2_3,L2_3); | ||
92 | dReal l2_4=dDOT(L2_4,L2_4); | ||
93 | |||
94 | |||
95 | if (l1_3<l1_4) | ||
96 | if(l2_3<l2_4) | ||
97 | if(l1_3<l2_3) | ||
98 | { | ||
99 | //l1_3; | ||
100 | point[0]=0.5f*(O1[0]+O3[0]); | ||
101 | point[1]=0.5f*(O1[1]+O3[1]); | ||
102 | point[2]=0.5f*(O1[2]+O3[2]); | ||
103 | } | ||
104 | else{ | ||
105 | //l2_3; | ||
106 | point[0]=0.5f*(O2[0]+O3[0]); | ||
107 | point[1]=0.5f*(O2[1]+O3[1]); | ||
108 | point[2]=0.5f*(O2[2]+O3[2]); | ||
109 | } | ||
110 | else | ||
111 | if(l1_3<l2_4) | ||
112 | { | ||
113 | //l1_3; | ||
114 | point[0]=0.5f*(O1[0]+O3[0]); | ||
115 | point[1]=0.5f*(O1[1]+O3[1]); | ||
116 | point[2]=0.5f*(O1[2]+O3[2]); | ||
117 | } | ||
118 | else{ | ||
119 | //l2_4; | ||
120 | point[0]=0.5f*(O2[0]+O4[0]); | ||
121 | point[1]=0.5f*(O2[1]+O4[1]); | ||
122 | point[2]=0.5f*(O2[2]+O4[2]); | ||
123 | } | ||
124 | |||
125 | else | ||
126 | if(l2_3<l2_4) | ||
127 | if(l1_4<l2_3) | ||
128 | { | ||
129 | //l1_4; | ||
130 | point[0]=0.5f*(O1[0]+O4[0]); | ||
131 | point[1]=0.5f*(O1[1]+O4[1]); | ||
132 | point[2]=0.5f*(O1[2]+O4[2]); | ||
133 | } | ||
134 | else{ | ||
135 | //l2_3; | ||
136 | point[0]=0.5f*(O2[0]+O3[0]); | ||
137 | point[1]=0.5f*(O2[1]+O3[1]); | ||
138 | point[2]=0.5f*(O2[2]+O3[2]); | ||
139 | } | ||
140 | else | ||
141 | if(l1_4<l2_4) | ||
142 | { | ||
143 | //l1_4; | ||
144 | point[0]=0.5f*(O1[0]+O4[0]); | ||
145 | point[1]=0.5f*(O1[1]+O4[1]); | ||
146 | point[2]=0.5f*(O1[2]+O4[2]); | ||
147 | } | ||
148 | else{ | ||
149 | //l2_4; | ||
150 | point[0]=0.5f*(O2[0]+O4[0]); | ||
151 | point[1]=0.5f*(O2[1]+O4[1]); | ||
152 | point[2]=0.5f*(O2[2]+O4[2]); | ||
153 | } | ||
154 | |||
155 | return true; | ||
156 | } | ||
157 | |||
158 | |||
159 | |||
160 | |||
161 | void lineClosestApproach (const dVector3 pa, const dVector3 ua, | ||
162 | const dVector3 pb, const dVector3 ub, | ||
163 | dReal *alpha, dReal *beta) | ||
164 | { | ||
165 | dVector3 p; | ||
166 | p[0] = pb[0] - pa[0]; | ||
167 | p[1] = pb[1] - pa[1]; | ||
168 | p[2] = pb[2] - pa[2]; | ||
169 | dReal uaub = dDOT(ua,ub); | ||
170 | dReal q1 = dDOT(ua,p); | ||
171 | dReal q2 = -dDOT(ub,p); | ||
172 | dReal d = 1-uaub*uaub; | ||
173 | if (d <= 0) { | ||
174 | // @@@ this needs to be made more robust | ||
175 | *alpha = 0; | ||
176 | *beta = 0; | ||
177 | } | ||
178 | else { | ||
179 | d = dRecip(d); | ||
180 | *alpha = (q1 + uaub*q2)*d; | ||
181 | *beta = (uaub*q1 + q2)*d; | ||
182 | } | ||
183 | } | ||
184 | |||
185 | |||
186 | // @@@ some stuff to optimize here, reuse code in contact point calculations. | ||
187 | |||
188 | extern "C" int dCylBox (const dVector3 p1, const dMatrix3 R1, | ||
189 | const dReal radius,const dReal lz, const dVector3 p2, | ||
190 | const dMatrix3 R2, const dVector3 side2, | ||
191 | dVector3 normal, dReal *depth, int *code, | ||
192 | int maxc, dContactGeom *contact, int skip) | ||
193 | { | ||
194 | dVector3 p,pp,normalC; | ||
195 | const dReal *normalR = 0; | ||
196 | dReal B1,B2,B3,R11,R12,R13,R21,R22,R23,R31,R32,R33, | ||
197 | Q11,Q12,Q13,Q21,Q22,Q23,Q31,Q32,Q33,s,s2,l,sQ21,sQ22,sQ23; | ||
198 | int i,invert_normal; | ||
199 | |||
200 | // get vector from centers of box 1 to box 2, relative to box 1 | ||
201 | p[0] = p2[0] - p1[0]; | ||
202 | p[1] = p2[1] - p1[1]; | ||
203 | p[2] = p2[2] - p1[2]; | ||
204 | dMULTIPLY1_331 (pp,R1,p); // get pp = p relative to body 1 | ||
205 | |||
206 | // get side lengths / 2 | ||
207 | //A1 =radius; A2 = lz*REAL(0.5); A3 = radius; | ||
208 | dReal hlz=lz/2.f; | ||
209 | B1 = side2[0]*REAL(0.5); B2 = side2[1]*REAL(0.5); B3 = side2[2]*REAL(0.5); | ||
210 | |||
211 | // Rij is R1'*R2, i.e. the relative rotation between R1 and R2 | ||
212 | R11 = dDOT44(R1+0,R2+0); R12 = dDOT44(R1+0,R2+1); R13 = dDOT44(R1+0,R2+2); | ||
213 | R21 = dDOT44(R1+1,R2+0); R22 = dDOT44(R1+1,R2+1); R23 = dDOT44(R1+1,R2+2); | ||
214 | R31 = dDOT44(R1+2,R2+0); R32 = dDOT44(R1+2,R2+1); R33 = dDOT44(R1+2,R2+2); | ||
215 | |||
216 | Q11 = dFabs(R11); Q12 = dFabs(R12); Q13 = dFabs(R13); | ||
217 | Q21 = dFabs(R21); Q22 = dFabs(R22); Q23 = dFabs(R23); | ||
218 | Q31 = dFabs(R31); Q32 = dFabs(R32); Q33 = dFabs(R33); | ||
219 | |||
220 | |||
221 | // * see if the axis separates the box with cylinder. if so, return 0. | ||
222 | // * find the depth of the penetration along the separating axis (s2) | ||
223 | // * if this is the largest depth so far, record it. | ||
224 | // the normal vector will be set to the separating axis with the smallest | ||
225 | // depth. note: normalR is set to point to a column of R1 or R2 if that is | ||
226 | // the smallest depth normal so far. otherwise normalR is 0 and normalC is | ||
227 | // set to a vector relative to body 1. invert_normal is 1 if the sign of | ||
228 | // the normal should be flipped. | ||
229 | |||
230 | #define TEST(expr1,expr2,norm,cc) \ | ||
231 | s2 = dFabs(expr1) - (expr2); \ | ||
232 | if (s2 > 0) return 0; \ | ||
233 | if (s2 > s) { \ | ||
234 | s = s2; \ | ||
235 | normalR = norm; \ | ||
236 | invert_normal = ((expr1) < 0); \ | ||
237 | *code = (cc); \ | ||
238 | } | ||
239 | |||
240 | s = -dInfinity; | ||
241 | invert_normal = 0; | ||
242 | *code = 0; | ||
243 | |||
244 | // separating axis = cylinder ax u2 | ||
245 | //used when a box vertex touches a flat face of the cylinder | ||
246 | TEST (pp[1],(hlz + B1*Q21 + B2*Q22 + B3*Q23),R1+1,0); | ||
247 | |||
248 | |||
249 | // separating axis = box axis v1,v2,v3 | ||
250 | //used when cylinder edge touches box face | ||
251 | //there is two ways to compute sQ: sQ21=sqrtf(1.f-Q21*Q21); or sQ21=sqrtf(Q23*Q23+Q22*Q22); | ||
252 | //if we did not need Q23 and Q22 the first way might be used to quiken the routine but then it need to | ||
253 | //check if Q21<=1.f, becouse it may slightly exeed 1.f. | ||
254 | |||
255 | |||
256 | sQ21=sqrtf(Q23*Q23+Q22*Q22); | ||
257 | TEST (dDOT41(R2+0,p),(radius*sQ21 + hlz*Q21 + B1),R2+0,1); | ||
258 | |||
259 | sQ22=sqrtf(Q23*Q23+Q21*Q21); | ||
260 | TEST (dDOT41(R2+1,p),(radius*sQ22 + hlz*Q22 + B2),R2+1,2); | ||
261 | |||
262 | sQ23=sqrtf(Q22*Q22+Q21*Q21); | ||
263 | TEST (dDOT41(R2+2,p),(radius*sQ23 + hlz*Q23 + B3),R2+2,3); | ||
264 | |||
265 | |||
266 | #undef TEST | ||
267 | #define TEST(expr1,expr2,n1,n2,n3,cc) \ | ||
268 | s2 = dFabs(expr1) - (expr2); \ | ||
269 | if (s2 > 0) return 0; \ | ||
270 | if (s2 > s) { \ | ||
271 | s = s2; \ | ||
272 | normalR = 0; \ | ||
273 | normalC[0] = (n1); normalC[1] = (n2); normalC[2] = (n3); \ | ||
274 | invert_normal = ((expr1) < 0); \ | ||
275 | *code = (cc); \ | ||
276 | } | ||
277 | |||
278 | |||
279 | |||
280 | // separating axis is a normal to the cylinder axis passing across the nearest box vertex | ||
281 | //used when a box vertex touches the lateral surface of the cylinder | ||
282 | |||
283 | dReal proj,boxProj,cos,sin,cos1,cos3; | ||
284 | dVector3 tAx,Ax,pb; | ||
285 | { | ||
286 | //making Ax which is perpendicular to cyl ax to box position// | ||
287 | proj=dDOT14(p2,R1+1)-dDOT14(p1,R1+1); | ||
288 | |||
289 | Ax[0]=p2[0]-p1[0]-R1[1]*proj; | ||
290 | Ax[1]=p2[1]-p1[1]-R1[5]*proj; | ||
291 | Ax[2]=p2[2]-p1[2]-R1[9]*proj; | ||
292 | dNormalize3(Ax); | ||
293 | //using Ax find box vertex which is nearest to the cylinder axis | ||
294 | dReal sign; | ||
295 | |||
296 | for (i=0; i<3; i++) pb[i] = p2[i]; | ||
297 | sign = (dDOT14(Ax,R2+0) > 0) ? REAL(-1.0) : REAL(1.0); | ||
298 | for (i=0; i<3; i++) pb[i] += sign * B1 * R2[i*4]; | ||
299 | sign = (dDOT14(Ax,R2+1) > 0) ? REAL(-1.0) : REAL(1.0); | ||
300 | for (i=0; i<3; i++) pb[i] += sign * B2 * R2[i*4+1]; | ||
301 | sign = (dDOT14(Ax,R2+2) > 0) ? REAL(-1.0) : REAL(1.0); | ||
302 | for (i=0; i<3; i++) pb[i] += sign * B3 * R2[i*4+2]; | ||
303 | |||
304 | //building axis which is normal to cylinder ax to the nearest box vertex | ||
305 | proj=dDOT14(pb,R1+1)-dDOT14(p1,R1+1); | ||
306 | |||
307 | Ax[0]=pb[0]-p1[0]-R1[1]*proj; | ||
308 | Ax[1]=pb[1]-p1[1]-R1[5]*proj; | ||
309 | Ax[2]=pb[2]-p1[2]-R1[9]*proj; | ||
310 | dNormalize3(Ax); | ||
311 | } | ||
312 | |||
313 | boxProj=dFabs(dDOT14(Ax,R2+0)*B1)+ | ||
314 | dFabs(dDOT14(Ax,R2+1)*B2)+ | ||
315 | dFabs(dDOT14(Ax,R2+2)*B3); | ||
316 | |||
317 | TEST(p[0]*Ax[0]+p[1]*Ax[1]+p[2]*Ax[2],(radius+boxProj),Ax[0],Ax[1],Ax[2],4); | ||
318 | |||
319 | |||
320 | //next three test used to handle collisions between cylinder circles and box ages | ||
321 | proj=dDOT14(p1,R2+0)-dDOT14(p2,R2+0); | ||
322 | |||
323 | tAx[0]=-p1[0]+p2[0]+R2[0]*proj; | ||
324 | tAx[1]=-p1[1]+p2[1]+R2[4]*proj; | ||
325 | tAx[2]=-p1[2]+p2[2]+R2[8]*proj; | ||
326 | dNormalize3(tAx); | ||
327 | |||
328 | //now tAx is normal to first ax of the box to cylinder center | ||
329 | //making perpendicular to tAx lying in the plane which is normal to the cylinder axis | ||
330 | //it is tangent in the point where projection of tAx on cylinder's ring intersect edge circle | ||
331 | |||
332 | cos=dDOT14(tAx,R1+0); | ||
333 | sin=dDOT14(tAx,R1+2); | ||
334 | tAx[0]=R1[2]*cos-R1[0]*sin; | ||
335 | tAx[1]=R1[6]*cos-R1[4]*sin; | ||
336 | tAx[2]=R1[10]*cos-R1[8]*sin; | ||
337 | |||
338 | |||
339 | //use cross between tAx and first ax of the box as separating axix | ||
340 | |||
341 | dCROSS114(Ax,=,tAx,R2+0); | ||
342 | dNormalize3(Ax); | ||
343 | |||
344 | boxProj=dFabs(dDOT14(Ax,R2+1)*B2)+ | ||
345 | dFabs(dDOT14(Ax,R2+0)*B1)+ | ||
346 | dFabs(dDOT14(Ax,R2+2)*B3); | ||
347 | |||
348 | cos=dFabs(dDOT14(Ax,R1+1)); | ||
349 | cos1=dDOT14(Ax,R1+0); | ||
350 | cos3=dDOT14(Ax,R1+2); | ||
351 | sin=sqrtf(cos1*cos1+cos3*cos3); | ||
352 | |||
353 | TEST(p[0]*Ax[0]+p[1]*Ax[1]+p[2]*Ax[2],(sin*radius+cos*hlz+boxProj),Ax[0],Ax[1],Ax[2],5); | ||
354 | |||
355 | |||
356 | //same thing with the second axis of the box | ||
357 | proj=dDOT14(p1,R2+1)-dDOT14(p2,R2+1); | ||
358 | |||
359 | tAx[0]=-p1[0]+p2[0]+R2[1]*proj; | ||
360 | tAx[1]=-p1[1]+p2[1]+R2[5]*proj; | ||
361 | tAx[2]=-p1[2]+p2[2]+R2[9]*proj; | ||
362 | dNormalize3(tAx); | ||
363 | |||
364 | |||
365 | cos=dDOT14(tAx,R1+0); | ||
366 | sin=dDOT14(tAx,R1+2); | ||
367 | tAx[0]=R1[2]*cos-R1[0]*sin; | ||
368 | tAx[1]=R1[6]*cos-R1[4]*sin; | ||
369 | tAx[2]=R1[10]*cos-R1[8]*sin; | ||
370 | |||
371 | dCROSS114(Ax,=,tAx,R2+1); | ||
372 | dNormalize3(Ax); | ||
373 | |||
374 | boxProj=dFabs(dDOT14(Ax,R2+0)*B1)+ | ||
375 | dFabs(dDOT14(Ax,R2+1)*B2)+ | ||
376 | dFabs(dDOT14(Ax,R2+2)*B3); | ||
377 | |||
378 | cos=dFabs(dDOT14(Ax,R1+1)); | ||
379 | cos1=dDOT14(Ax,R1+0); | ||
380 | cos3=dDOT14(Ax,R1+2); | ||
381 | sin=sqrtf(cos1*cos1+cos3*cos3); | ||
382 | TEST(p[0]*Ax[0]+p[1]*Ax[1]+p[2]*Ax[2],(sin*radius+cos*hlz+boxProj),Ax[0],Ax[1],Ax[2],6); | ||
383 | |||
384 | //same thing with the third axis of the box | ||
385 | proj=dDOT14(p1,R2+2)-dDOT14(p2,R2+2); | ||
386 | |||
387 | Ax[0]=-p1[0]+p2[0]+R2[2]*proj; | ||
388 | Ax[1]=-p1[1]+p2[1]+R2[6]*proj; | ||
389 | Ax[2]=-p1[2]+p2[2]+R2[10]*proj; | ||
390 | dNormalize3(tAx); | ||
391 | |||
392 | cos=dDOT14(tAx,R1+0); | ||
393 | sin=dDOT14(tAx,R1+2); | ||
394 | tAx[0]=R1[2]*cos-R1[0]*sin; | ||
395 | tAx[1]=R1[6]*cos-R1[4]*sin; | ||
396 | tAx[2]=R1[10]*cos-R1[8]*sin; | ||
397 | |||
398 | dCROSS114(Ax,=,tAx,R2+2); | ||
399 | dNormalize3(Ax); | ||
400 | boxProj=dFabs(dDOT14(Ax,R2+1)*B2)+ | ||
401 | dFabs(dDOT14(Ax,R2+2)*B3)+ | ||
402 | dFabs(dDOT14(Ax,R2+0)*B1); | ||
403 | |||
404 | cos=dFabs(dDOT14(Ax,R1+1)); | ||
405 | cos1=dDOT14(Ax,R1+0); | ||
406 | cos3=dDOT14(Ax,R1+2); | ||
407 | sin=sqrtf(cos1*cos1+cos3*cos3); | ||
408 | TEST(p[0]*Ax[0]+p[1]*Ax[1]+p[2]*Ax[2],(sin*radius+cos*hlz+boxProj),Ax[0],Ax[1],Ax[2],7); | ||
409 | |||
410 | |||
411 | #undef TEST | ||
412 | |||
413 | // note: cross product axes need to be scaled when s is computed. | ||
414 | // normal (n1,n2,n3) is relative to box 1. | ||
415 | |||
416 | #define TEST(expr1,expr2,n1,n2,n3,cc) \ | ||
417 | s2 = dFabs(expr1) - (expr2); \ | ||
418 | if (s2 > 0) return 0; \ | ||
419 | l = dSqrt ((n1)*(n1) + (n2)*(n2) + (n3)*(n3)); \ | ||
420 | if (l > 0) { \ | ||
421 | s2 /= l; \ | ||
422 | if (s2 > s) { \ | ||
423 | s = s2; \ | ||
424 | normalR = 0; \ | ||
425 | normalC[0] = (n1)/l; normalC[1] = (n2)/l; normalC[2] = (n3)/l; \ | ||
426 | invert_normal = ((expr1) < 0); \ | ||
427 | *code = (cc); \ | ||
428 | } \ | ||
429 | } | ||
430 | |||
431 | //crosses between cylinder axis and box axes | ||
432 | // separating axis = u2 x (v1,v2,v3) | ||
433 | TEST(pp[0]*R31-pp[2]*R11,(radius+B2*Q23+B3*Q22),R31,0,-R11,8); | ||
434 | TEST(pp[0]*R32-pp[2]*R12,(radius+B1*Q23+B3*Q21),R32,0,-R12,9); | ||
435 | TEST(pp[0]*R33-pp[2]*R13,(radius+B1*Q22+B2*Q21),R33,0,-R13,10); | ||
436 | |||
437 | |||
438 | #undef TEST | ||
439 | |||
440 | // if we get to this point, the boxes interpenetrate. compute the normal | ||
441 | // in global coordinates. | ||
442 | if (normalR) { | ||
443 | normal[0] = normalR[0]; | ||
444 | normal[1] = normalR[4]; | ||
445 | normal[2] = normalR[8]; | ||
446 | } | ||
447 | else { | ||
448 | if(*code>7) dMULTIPLY0_331 (normal,R1,normalC); | ||
449 | else {normal[0] =normalC[0];normal[1] = normalC[1];normal[2] = normalC[2];} | ||
450 | } | ||
451 | if (invert_normal) { | ||
452 | normal[0] = -normal[0]; | ||
453 | normal[1] = -normal[1]; | ||
454 | normal[2] = -normal[2]; | ||
455 | } | ||
456 | *depth = -s; | ||
457 | |||
458 | // compute contact point(s) | ||
459 | |||
460 | if (*code > 7) { | ||
461 | //find point on the cylinder pa deepest along normal | ||
462 | dVector3 pa; | ||
463 | dReal sign, cos1,cos3,factor; | ||
464 | |||
465 | |||
466 | for (i=0; i<3; i++) pa[i] = p1[i]; | ||
467 | |||
468 | cos1 = dDOT14(normal,R1+0); | ||
469 | cos3 = dDOT14(normal,R1+2) ; | ||
470 | factor=sqrtf(cos1*cos1+cos3*cos3); | ||
471 | |||
472 | cos1/=factor; | ||
473 | cos3/=factor; | ||
474 | |||
475 | for (i=0; i<3; i++) pa[i] += cos1 * radius * R1[i*4]; | ||
476 | |||
477 | sign = (dDOT14(normal,R1+1) > 0) ? REAL(1.0) : REAL(-1.0); | ||
478 | for (i=0; i<3; i++) pa[i] += sign * hlz * R1[i*4+1]; | ||
479 | |||
480 | |||
481 | for (i=0; i<3; i++) pa[i] += cos3 * radius * R1[i*4+2]; | ||
482 | |||
483 | // find vertex of the box deepest along normal | ||
484 | dVector3 pb; | ||
485 | for (i=0; i<3; i++) pb[i] = p2[i]; | ||
486 | sign = (dDOT14(normal,R2+0) > 0) ? REAL(-1.0) : REAL(1.0); | ||
487 | for (i=0; i<3; i++) pb[i] += sign * B1 * R2[i*4]; | ||
488 | sign = (dDOT14(normal,R2+1) > 0) ? REAL(-1.0) : REAL(1.0); | ||
489 | for (i=0; i<3; i++) pb[i] += sign * B2 * R2[i*4+1]; | ||
490 | sign = (dDOT14(normal,R2+2) > 0) ? REAL(-1.0) : REAL(1.0); | ||
491 | for (i=0; i<3; i++) pb[i] += sign * B3 * R2[i*4+2]; | ||
492 | |||
493 | |||
494 | dReal alpha,beta; | ||
495 | dVector3 ua,ub; | ||
496 | for (i=0; i<3; i++) ua[i] = R1[1 + i*4]; | ||
497 | for (i=0; i<3; i++) ub[i] = R2[*code-8 + i*4]; | ||
498 | |||
499 | lineClosestApproach (pa,ua,pb,ub,&alpha,&beta); | ||
500 | for (i=0; i<3; i++) pa[i] += ua[i]*alpha; | ||
501 | for (i=0; i<3; i++) pb[i] += ub[i]*beta; | ||
502 | |||
503 | for (i=0; i<3; i++) contact[0].pos[i] = REAL(0.5)*(pa[i]+pb[i]); | ||
504 | contact[0].depth = *depth; | ||
505 | return 1; | ||
506 | } | ||
507 | |||
508 | |||
509 | if(*code==4){ | ||
510 | for (i=0; i<3; i++) contact[0].pos[i] = pb[i]; | ||
511 | contact[0].depth = *depth; | ||
512 | return 1; | ||
513 | } | ||
514 | |||
515 | |||
516 | dVector3 vertex; | ||
517 | if (*code == 0) { | ||
518 | |||
519 | dReal sign; | ||
520 | for (i=0; i<3; i++) vertex[i] = p2[i]; | ||
521 | sign = (dDOT14(normal,R2+0) > 0) ? REAL(-1.0) : REAL(1.0); | ||
522 | for (i=0; i<3; i++) vertex[i] += sign * B1 * R2[i*4]; | ||
523 | sign = (dDOT14(normal,R2+1) > 0) ? REAL(-1.0) : REAL(1.0); | ||
524 | for (i=0; i<3; i++) vertex[i] += sign * B2 * R2[i*4+1]; | ||
525 | sign = (dDOT14(normal,R2+2) > 0) ? REAL(-1.0) : REAL(1.0); | ||
526 | for (i=0; i<3; i++) vertex[i] += sign * B3 * R2[i*4+2]; | ||
527 | } | ||
528 | else { | ||
529 | |||
530 | dReal sign,cos1,cos3,factor; | ||
531 | for (i=0; i<3; i++) vertex[i] = p1[i]; | ||
532 | cos1 = dDOT14(normal,R1+0) ; | ||
533 | cos3 = dDOT14(normal,R1+2); | ||
534 | factor=sqrtf(cos1*cos1+cos3*cos3); | ||
535 | factor= factor ? factor : 1.f; | ||
536 | cos1/=factor; | ||
537 | cos3/=factor; | ||
538 | for (i=0; i<3; i++) vertex[i] += cos1 * radius * R1[i*4]; | ||
539 | |||
540 | sign = (dDOT14(normal,R1+1) > 0) ? REAL(1.0) : REAL(-1.0); | ||
541 | for (i=0; i<3; i++) vertex[i] += sign * hlz * R1[i*4+1]; | ||
542 | |||
543 | for (i=0; i<3; i++) vertex[i] += cos3 * radius * R1[i*4+2]; | ||
544 | } | ||
545 | for (i=0; i<3; i++) contact[0].pos[i] = vertex[i]; | ||
546 | contact[0].depth = *depth; | ||
547 | return 1; | ||
548 | } | ||
549 | |||
550 | //**************************************************************************** | ||
551 | |||
552 | extern "C" int dCylCyl (const dVector3 p1, const dMatrix3 R1, | ||
553 | const dReal radius1,const dReal lz1, const dVector3 p2, | ||
554 | const dMatrix3 R2, const dReal radius2,const dReal lz2, | ||
555 | dVector3 normal, dReal *depth, int *code, | ||
556 | int maxc, dContactGeom *contact, int skip) | ||
557 | { | ||
558 | dVector3 p,pp1,pp2,normalC; | ||
559 | const dReal *normalR = 0; | ||
560 | dReal hlz1,hlz2,s,s2; | ||
561 | int i,invert_normal; | ||
562 | |||
563 | // get vector from centers of box 1 to box 2, relative to box 1 | ||
564 | p[0] = p2[0] - p1[0]; | ||
565 | p[1] = p2[1] - p1[1]; | ||
566 | p[2] = p2[2] - p1[2]; | ||
567 | dMULTIPLY1_331 (pp1,R1,p); // get pp1 = p relative to body 1 | ||
568 | dMULTIPLY1_331 (pp2,R2,p); | ||
569 | // get side lengths / 2 | ||
570 | hlz1 = lz1*REAL(0.5); | ||
571 | hlz2 = lz2*REAL(0.5); | ||
572 | |||
573 | dReal proj,cos,sin,cos1,cos3; | ||
574 | |||
575 | |||
576 | |||
577 | #define TEST(expr1,expr2,norm,cc) \ | ||
578 | s2 = dFabs(expr1) - (expr2); \ | ||
579 | if (s2 > 0) return 0; \ | ||
580 | if (s2 > s) { \ | ||
581 | s = s2; \ | ||
582 | normalR = norm; \ | ||
583 | invert_normal = ((expr1) < 0); \ | ||
584 | *code = (cc); \ | ||
585 | } | ||
586 | |||
587 | s = -dInfinity; | ||
588 | invert_normal = 0; | ||
589 | *code = 0; | ||
590 | |||
591 | cos=dFabs(dDOT44(R1+1,R2+1)); | ||
592 | sin=sqrtf(1.f-(cos>1.f ? 1.f : cos)); | ||
593 | |||
594 | TEST (pp1[1],(hlz1 + radius2*sin + hlz2*cos ),R1+1,0);//pp | ||
595 | |||
596 | TEST (pp2[1],(radius1*sin + hlz1*cos + hlz2),R2+1,1); | ||
597 | |||
598 | |||
599 | |||
600 | // note: cross product axes need to be scaled when s is computed. | ||
601 | |||
602 | #undef TEST | ||
603 | #define TEST(expr1,expr2,n1,n2,n3,cc) \ | ||
604 | s2 = dFabs(expr1) - (expr2); \ | ||
605 | if (s2 > 0) return 0; \ | ||
606 | if (s2 > s) { \ | ||
607 | s = s2; \ | ||
608 | normalR = 0; \ | ||
609 | normalC[0] = (n1); normalC[1] = (n2); normalC[2] = (n3); \ | ||
610 | invert_normal = ((expr1) < 0); \ | ||
611 | *code = (cc); \ | ||
612 | } | ||
613 | |||
614 | |||
615 | dVector3 tAx,Ax,pa,pb; | ||
616 | |||
617 | //cross between cylinders' axes | ||
618 | dCROSS144(Ax,=,R1+1,R2+1); | ||
619 | dNormalize3(Ax); | ||
620 | TEST(p[0]*Ax[0]+p[1]*Ax[1]+p[2]*Ax[2],radius1+radius2,Ax[0],Ax[1],Ax[2],6); | ||
621 | |||
622 | |||
623 | { | ||
624 | |||
625 | dReal sign, factor; | ||
626 | |||
627 | //making ax which is perpendicular to cyl1 ax passing across cyl2 position// | ||
628 | //(project p on cyl1 flat surface ) | ||
629 | for (i=0; i<3; i++) pb[i] = p2[i]; | ||
630 | //cos1 = dDOT14(p,R1+0); | ||
631 | //cos3 = dDOT14(p,R1+2) ; | ||
632 | tAx[0]=pp1[0]*R1[0]+pp1[2]*R1[2]; | ||
633 | tAx[1]=pp1[0]*R1[4]+pp1[2]*R1[6]; | ||
634 | tAx[2]=pp1[0]*R1[8]+pp1[2]*R1[10]; | ||
635 | dNormalize3(tAx); | ||
636 | |||
637 | //find deepest point pb of cyl2 on opposite direction of tAx | ||
638 | cos1 = dDOT14(tAx,R2+0); | ||
639 | cos3 = dDOT14(tAx,R2+2) ; | ||
640 | factor=sqrtf(cos1*cos1+cos3*cos3); | ||
641 | cos1/=factor; | ||
642 | cos3/=factor; | ||
643 | for (i=0; i<3; i++) pb[i] -= cos1 * radius2 * R2[i*4]; | ||
644 | |||
645 | sign = (dDOT14(tAx,R2+1) > 0) ? REAL(1.0) : REAL(-1.0); | ||
646 | for (i=0; i<3; i++) pb[i] -= sign * hlz2 * R2[i*4+1]; | ||
647 | |||
648 | for (i=0; i<3; i++) pb[i] -= cos3 * radius2 * R2[i*4+2]; | ||
649 | |||
650 | //making perpendicular to cyl1 ax passing across pb | ||
651 | proj=dDOT14(pb,R1+1)-dDOT14(p1,R1+1); | ||
652 | |||
653 | Ax[0]=pb[0]-p1[0]-R1[1]*proj; | ||
654 | Ax[1]=pb[1]-p1[1]-R1[5]*proj; | ||
655 | Ax[2]=pb[2]-p1[2]-R1[9]*proj; | ||
656 | |||
657 | } | ||
658 | |||
659 | dNormalize3(Ax); | ||
660 | |||
661 | |||
662 | cos=dFabs(dDOT14(Ax,R2+1)); | ||
663 | cos1=dDOT14(Ax,R2+0); | ||
664 | cos3=dDOT14(Ax,R2+2); | ||
665 | sin=sqrtf(cos1*cos1+cos3*cos3); | ||
666 | |||
667 | TEST(p[0]*Ax[0]+p[1]*Ax[1]+p[2]*Ax[2],radius1+cos*hlz2+sin*radius2,Ax[0],Ax[1],Ax[2],3); | ||
668 | |||
669 | |||
670 | |||
671 | { | ||
672 | |||
673 | dReal sign, factor; | ||
674 | |||
675 | for (i=0; i<3; i++) pa[i] = p1[i]; | ||
676 | |||
677 | //making ax which is perpendicular to cyl2 ax passing across cyl1 position// | ||
678 | //(project p on cyl2 flat surface ) | ||
679 | //cos1 = dDOT14(p,R2+0); | ||
680 | //cos3 = dDOT14(p,R2+2) ; | ||
681 | tAx[0]=pp2[0]*R2[0]+pp2[2]*R2[2]; | ||
682 | tAx[1]=pp2[0]*R2[4]+pp2[2]*R2[6]; | ||
683 | tAx[2]=pp2[0]*R2[8]+pp2[2]*R2[10]; | ||
684 | dNormalize3(tAx); | ||
685 | |||
686 | cos1 = dDOT14(tAx,R1+0); | ||
687 | cos3 = dDOT14(tAx,R1+2) ; | ||
688 | factor=sqrtf(cos1*cos1+cos3*cos3); | ||
689 | cos1/=factor; | ||
690 | cos3/=factor; | ||
691 | |||
692 | //find deepest point pa of cyl2 on direction of tAx | ||
693 | for (i=0; i<3; i++) pa[i] += cos1 * radius1 * R1[i*4]; | ||
694 | |||
695 | sign = (dDOT14(tAx,R1+1) > 0) ? REAL(1.0) : REAL(-1.0); | ||
696 | for (i=0; i<3; i++) pa[i] += sign * hlz1 * R1[i*4+1]; | ||
697 | |||
698 | |||
699 | for (i=0; i<3; i++) pa[i] += cos3 * radius1 * R1[i*4+2]; | ||
700 | |||
701 | proj=dDOT14(pa,R2+1)-dDOT14(p2,R2+1); | ||
702 | |||
703 | Ax[0]=pa[0]-p2[0]-R2[1]*proj; | ||
704 | Ax[1]=pa[1]-p2[1]-R2[5]*proj; | ||
705 | Ax[2]=pa[2]-p2[2]-R2[9]*proj; | ||
706 | |||
707 | } | ||
708 | dNormalize3(Ax); | ||
709 | |||
710 | |||
711 | |||
712 | cos=dFabs(dDOT14(Ax,R1+1)); | ||
713 | cos1=dDOT14(Ax,R1+0); | ||
714 | cos3=dDOT14(Ax,R1+2); | ||
715 | sin=sqrtf(cos1*cos1+cos3*cos3); | ||
716 | |||
717 | TEST(p[0]*Ax[0]+p[1]*Ax[1]+p[2]*Ax[2],radius2+cos*hlz1+sin*radius1,Ax[0],Ax[1],Ax[2],4); | ||
718 | |||
719 | |||
720 | ////test circl | ||
721 | |||
722 | //@ this needed to set right normal when cylinders edges intersect | ||
723 | //@ the most precise axis for this test may be found as a line between nearest points of two | ||
724 | //@ circles. But it needs comparatively a lot of computation. | ||
725 | //@ I use a trick which lets not to solve quadric equation. | ||
726 | //@ In the case when cylinder eidges touches the test below rather accurate. | ||
727 | //@ I still not sure about problems with sepparation but they have not been revealed during testing. | ||
728 | dVector3 point; | ||
729 | { | ||
730 | dVector3 ca,cb; | ||
731 | dReal sign; | ||
732 | for (i=0; i<3; i++) ca[i] = p1[i]; | ||
733 | for (i=0; i<3; i++) cb[i] = p2[i]; | ||
734 | //find two nearest flat rings | ||
735 | sign = (pp1[1] > 0) ? REAL(1.0) : REAL(-1.0); | ||
736 | for (i=0; i<3; i++) ca[i] += sign * hlz1 * R1[i*4+1]; | ||
737 | |||
738 | sign = (pp2[1] > 0) ? REAL(1.0) : REAL(-1.0); | ||
739 | for (i=0; i<3; i++) cb[i] -= sign * hlz2 * R2[i*4+1]; | ||
740 | |||
741 | dVector3 tAx,tAx1; | ||
742 | circleIntersection(R1+1,ca,radius1,R2+1,cb,radius2,point); | ||
743 | |||
744 | Ax[0]=point[0]-ca[0]; | ||
745 | Ax[1]=point[1]-ca[1]; | ||
746 | Ax[2]=point[2]-ca[2]; | ||
747 | |||
748 | cos1 = dDOT14(Ax,R1+0); | ||
749 | cos3 = dDOT14(Ax,R1+2) ; | ||
750 | |||
751 | tAx[0]=cos3*R1[0]-cos1*R1[2]; | ||
752 | tAx[1]=cos3*R1[4]-cos1*R1[6]; | ||
753 | tAx[2]=cos3*R1[8]-cos1*R1[10]; | ||
754 | |||
755 | Ax[0]=point[0]-cb[0]; | ||
756 | Ax[1]=point[1]-cb[1]; | ||
757 | Ax[2]=point[2]-cb[2]; | ||
758 | |||
759 | |||
760 | cos1 = dDOT14(Ax,R2+0); | ||
761 | cos3 = dDOT14(Ax,R2+2) ; | ||
762 | |||
763 | tAx1[0]=cos3*R2[0]-cos1*R2[2]; | ||
764 | tAx1[1]=cos3*R2[4]-cos1*R2[6]; | ||
765 | tAx1[2]=cos3*R2[8]-cos1*R2[10]; | ||
766 | dCROSS(Ax,=,tAx,tAx1); | ||
767 | |||
768 | |||
769 | |||
770 | |||
771 | dNormalize3(Ax); | ||
772 | dReal cyl1Pr,cyl2Pr; | ||
773 | |||
774 | cos=dFabs(dDOT14(Ax,R1+1)); | ||
775 | cos1=dDOT14(Ax,R1+0); | ||
776 | cos3=dDOT14(Ax,R1+2); | ||
777 | sin=sqrtf(cos1*cos1+cos3*cos3); | ||
778 | cyl1Pr=cos*hlz1+sin*radius1; | ||
779 | |||
780 | cos=dFabs(dDOT14(Ax,R2+1)); | ||
781 | cos1=dDOT14(Ax,R2+0); | ||
782 | cos3=dDOT14(Ax,R2+2); | ||
783 | sin=sqrtf(cos1*cos1+cos3*cos3); | ||
784 | cyl2Pr=cos*hlz2+sin*radius2; | ||
785 | TEST(p[0]*Ax[0]+p[1]*Ax[1]+p[2]*Ax[2],cyl1Pr+cyl2Pr,Ax[0],Ax[1],Ax[2],5); | ||
786 | |||
787 | |||
788 | } | ||
789 | |||
790 | |||
791 | #undef TEST | ||
792 | |||
793 | |||
794 | |||
795 | // if we get to this point, the cylinders interpenetrate. compute the normal | ||
796 | // in global coordinates. | ||
797 | if (normalR) { | ||
798 | normal[0] = normalR[0]; | ||
799 | normal[1] = normalR[4]; | ||
800 | normal[2] = normalR[8]; | ||
801 | } | ||
802 | else { | ||
803 | normal[0] =normalC[0];normal[1] = normalC[1];normal[2] = normalC[2]; | ||
804 | } | ||
805 | if (invert_normal) { | ||
806 | normal[0] = -normal[0]; | ||
807 | normal[1] = -normal[1]; | ||
808 | normal[2] = -normal[2]; | ||
809 | } | ||
810 | |||
811 | *depth = -s; | ||
812 | |||
813 | // compute contact point(s) | ||
814 | |||
815 | if(*code==3){ | ||
816 | for (i=0; i<3; i++) contact[0].pos[i] = pb[i]; | ||
817 | contact[0].depth = *depth; | ||
818 | return 1; | ||
819 | } | ||
820 | |||
821 | if(*code==4){ | ||
822 | for (i=0; i<3; i++) contact[0].pos[i] = pa[i]; | ||
823 | contact[0].depth = *depth; | ||
824 | return 1; | ||
825 | } | ||
826 | |||
827 | if(*code==5){ | ||
828 | for (i=0; i<3; i++) contact[0].pos[i] = point[i]; | ||
829 | contact[0].depth = *depth; | ||
830 | return 1; | ||
831 | } | ||
832 | |||
833 | if (*code == 6) { | ||
834 | dVector3 pa; | ||
835 | dReal sign, cos1,cos3,factor; | ||
836 | |||
837 | |||
838 | for (i=0; i<3; i++) pa[i] = p1[i]; | ||
839 | |||
840 | cos1 = dDOT14(normal,R1+0); | ||
841 | cos3 = dDOT14(normal,R1+2) ; | ||
842 | factor=sqrtf(cos1*cos1+cos3*cos3); | ||
843 | |||
844 | cos1/=factor; | ||
845 | cos3/=factor; | ||
846 | |||
847 | for (i=0; i<3; i++) pa[i] += cos1 * radius1 * R1[i*4]; | ||
848 | |||
849 | sign = (dDOT14(normal,R1+1) > 0) ? REAL(1.0) : REAL(-1.0); | ||
850 | for (i=0; i<3; i++) pa[i] += sign * hlz1 * R1[i*4+1]; | ||
851 | |||
852 | |||
853 | for (i=0; i<3; i++) pa[i] += cos3 * radius1 * R1[i*4+2]; | ||
854 | |||
855 | // find a point pb on the intersecting edge of cylinder 2 | ||
856 | dVector3 pb; | ||
857 | for (i=0; i<3; i++) pb[i] = p2[i]; | ||
858 | cos1 = dDOT14(normal,R2+0); | ||
859 | cos3 = dDOT14(normal,R2+2) ; | ||
860 | factor=sqrtf(cos1*cos1+cos3*cos3); | ||
861 | |||
862 | cos1/=factor; | ||
863 | cos3/=factor; | ||
864 | |||
865 | for (i=0; i<3; i++) pb[i] -= cos1 * radius2 * R2[i*4]; | ||
866 | |||
867 | sign = (dDOT14(normal,R2+1) > 0) ? REAL(1.0) : REAL(-1.0); | ||
868 | for (i=0; i<3; i++) pb[i] -= sign * hlz2 * R2[i*4+1]; | ||
869 | |||
870 | |||
871 | for (i=0; i<3; i++) pb[i] -= cos3 * radius2 * R2[i*4+2]; | ||
872 | |||
873 | |||
874 | dReal alpha,beta; | ||
875 | dVector3 ua,ub; | ||
876 | for (i=0; i<3; i++) ua[i] = R1[1 + i*4]; | ||
877 | for (i=0; i<3; i++) ub[i] = R2[1 + i*4]; | ||
878 | lineClosestApproach (pa,ua,pb,ub,&alpha,&beta); | ||
879 | for (i=0; i<3; i++) pa[i] += ua[i]*alpha; | ||
880 | for (i=0; i<3; i++) pb[i] += ub[i]*beta; | ||
881 | |||
882 | for (i=0; i<3; i++) contact[0].pos[i] = REAL(0.5)*(pa[i]+pb[i]); | ||
883 | contact[0].depth = *depth; | ||
884 | return 1; | ||
885 | } | ||
886 | |||
887 | // okay, we have a face-something intersection (because the separating | ||
888 | // axis is perpendicular to a face). | ||
889 | |||
890 | // @@@ temporary: make deepest point on the "other" cylinder the contact point. | ||
891 | // @@@ this kind of works, but we need multiple contact points for stability, | ||
892 | // @@@ especially for face-face contact. | ||
893 | |||
894 | dVector3 vertex; | ||
895 | if (*code == 0) { | ||
896 | // flat face from cylinder 1 touches a edge/face from cylinder 2. | ||
897 | dReal sign,cos1,cos3,factor; | ||
898 | for (i=0; i<3; i++) vertex[i] = p2[i]; | ||
899 | cos1 = dDOT14(normal,R2+0) ; | ||
900 | cos3 = dDOT14(normal,R2+2); | ||
901 | factor=sqrtf(cos1*cos1+cos3*cos3); | ||
902 | |||
903 | cos1/=factor; | ||
904 | cos3/=factor; | ||
905 | for (i=0; i<3; i++) vertex[i] -= cos1 * radius2 * R2[i*4]; | ||
906 | |||
907 | sign = (dDOT14(normal,R1+1) > 0) ? REAL(1.0) : REAL(-1.0); | ||
908 | for (i=0; i<3; i++) vertex[i] -= sign * hlz2 * R2[i*4+1]; | ||
909 | |||
910 | for (i=0; i<3; i++) vertex[i] -= cos3 * radius2 * R2[i*4+2]; | ||
911 | } | ||
912 | else { | ||
913 | // flat face from cylinder 2 touches a edge/face from cylinder 1. | ||
914 | dReal sign,cos1,cos3,factor; | ||
915 | for (i=0; i<3; i++) vertex[i] = p1[i]; | ||
916 | cos1 = dDOT14(normal,R1+0) ; | ||
917 | cos3 = dDOT14(normal,R1+2); | ||
918 | factor=sqrtf(cos1*cos1+cos3*cos3); | ||
919 | |||
920 | cos1/=factor; | ||
921 | cos3/=factor; | ||
922 | for (i=0; i<3; i++) vertex[i] += cos1 * radius1 * R1[i*4]; | ||
923 | |||
924 | sign = (dDOT14(normal,R1+1) > 0) ? REAL(1.0) : REAL(-1.0); | ||
925 | for (i=0; i<3; i++) vertex[i] += sign * hlz1 * R1[i*4+1]; | ||
926 | |||
927 | for (i=0; i<3; i++) vertex[i] += cos3 * radius1 * R1[i*4+2]; | ||
928 | } | ||
929 | for (i=0; i<3; i++) contact[0].pos[i] = vertex[i]; | ||
930 | contact[0].depth = *depth; | ||
931 | return 1; | ||
932 | } | ||
933 | |||
934 | //**************************************************************************** | ||
935 | |||
936 | |||
937 | int dCollideCylS (dxGeom *o1, dxGeom *o2, int flags, | ||
938 | dContactGeom *contact, int skip) | ||
939 | { | ||
940 | |||
941 | |||
942 | dIASSERT (skip >= (int)sizeof(dContactGeom)); | ||
943 | dIASSERT (dGeomGetClass(o2) == dSphereClass); | ||
944 | dIASSERT (dGeomGetClass(o1) == dCylinderClassUser); | ||
945 | const dReal* p1=dGeomGetPosition(o1); | ||
946 | const dReal* p2=dGeomGetPosition(o2); | ||
947 | const dReal* R=dGeomGetRotation(o1); | ||
948 | dVector3 p,normalC,normal; | ||
949 | const dReal *normalR = 0; | ||
950 | dReal cylRadius; | ||
951 | dReal hl; | ||
952 | dGeomCylinderGetParams(o1,&cylRadius,&hl); | ||
953 | dReal sphereRadius; | ||
954 | sphereRadius=dGeomSphereGetRadius(o2); | ||
955 | |||
956 | int i,invert_normal; | ||
957 | |||
958 | // get vector from centers of cyl to shere | ||
959 | p[0] = p2[0] - p1[0]; | ||
960 | p[1] = p2[1] - p1[1]; | ||
961 | p[2] = p2[2] - p1[2]; | ||
962 | |||
963 | dReal s,s2; | ||
964 | unsigned char code; | ||
965 | #define TEST(expr1,expr2,norm,cc) \ | ||
966 | s2 = dFabs(expr1) - (expr2); \ | ||
967 | if (s2 > 0) return 0; \ | ||
968 | if (s2 > s) { \ | ||
969 | s = s2; \ | ||
970 | normalR = norm; \ | ||
971 | invert_normal = ((expr1) < 0); \ | ||
972 | code = (cc); \ | ||
973 | } | ||
974 | |||
975 | s = -dInfinity; | ||
976 | invert_normal = 0; | ||
977 | code = 0; | ||
978 | |||
979 | // separating axis cyl ax | ||
980 | |||
981 | TEST (dDOT14(p,R+1),sphereRadius+hl,R+1,2); | ||
982 | // note: cross product axes need to be scaled when s is computed. | ||
983 | // normal (n1,n2,n3) is relative to | ||
984 | #undef TEST | ||
985 | #define TEST(expr1,expr2,n1,n2,n3,cc) \ | ||
986 | s2 = dFabs(expr1) - (expr2); \ | ||
987 | if (s2 > 0) return 0; \ | ||
988 | if (s2 > s) { \ | ||
989 | s = s2; \ | ||
990 | normalR = 0; \ | ||
991 | normalC[0] = (n1); normalC[1] = (n2); normalC[2] = (n3); \ | ||
992 | invert_normal = ((expr1) < 0); \ | ||
993 | code = (cc); \ | ||
994 | } | ||
995 | |||
996 | //making ax which is perpendicular to cyl1 ax to sphere center// | ||
997 | |||
998 | dReal proj,cos,sin,cos1,cos3; | ||
999 | dVector3 Ax; | ||
1000 | proj=dDOT14(p2,R+1)-dDOT14(p1,R+1); | ||
1001 | |||
1002 | Ax[0]=p2[0]-p1[0]-R[1]*proj; | ||
1003 | Ax[1]=p2[1]-p1[1]-R[5]*proj; | ||
1004 | Ax[2]=p2[2]-p1[2]-R[9]*proj; | ||
1005 | dNormalize3(Ax); | ||
1006 | TEST(dDOT(p,Ax),sphereRadius+cylRadius,Ax[0],Ax[1],Ax[2],9); | ||
1007 | |||
1008 | |||
1009 | Ax[0]=p[0]; | ||
1010 | Ax[1]=p[1]; | ||
1011 | Ax[2]=p[2]; | ||
1012 | dNormalize3(Ax); | ||
1013 | |||
1014 | dVector3 pa; | ||
1015 | dReal sign, factor; | ||
1016 | for (i=0; i<3; i++) pa[i] = p1[i]; | ||
1017 | |||
1018 | cos1 = dDOT14(Ax,R+0); | ||
1019 | cos3 = dDOT14(Ax,R+2) ; | ||
1020 | factor=sqrtf(cos1*cos1+cos3*cos3); | ||
1021 | cos1/=factor; | ||
1022 | cos3/=factor; | ||
1023 | for (i=0; i<3; i++) pa[i] += cos1 * cylRadius * R[i*4]; | ||
1024 | sign = (dDOT14(normal,R+1) > 0) ? REAL(1.0) : REAL(-1.0); | ||
1025 | for (i=0; i<3; i++) pa[i] += sign * hl * R[i*4+1]; | ||
1026 | for (i=0; i<3; i++) pa[i] += cos3 * cylRadius * R[i*4+2]; | ||
1027 | |||
1028 | Ax[0]=p2[0]-pa[0]; | ||
1029 | Ax[1]=p2[1]-pa[1]; | ||
1030 | Ax[2]=p2[2]-pa[2]; | ||
1031 | dNormalize3(Ax); | ||
1032 | |||
1033 | cos=dFabs(dDOT14(Ax,R+1)); | ||
1034 | cos1=dDOT14(Ax,R+0); | ||
1035 | cos3=dDOT14(Ax,R+2); | ||
1036 | sin=sqrtf(cos1*cos1+cos3*cos3); | ||
1037 | TEST(dDOT(p,Ax),sphereRadius+cylRadius*sin+hl*cos,Ax[0],Ax[1],Ax[2],14); | ||
1038 | |||
1039 | |||
1040 | #undef TEST | ||
1041 | |||
1042 | if (normalR) { | ||
1043 | normal[0] = normalR[0]; | ||
1044 | normal[1] = normalR[4]; | ||
1045 | normal[2] = normalR[8]; | ||
1046 | } | ||
1047 | else { | ||
1048 | |||
1049 | normal[0] = normalC[0]; | ||
1050 | normal[1] = normalC[1]; | ||
1051 | normal[2] = normalC[2]; | ||
1052 | } | ||
1053 | if (invert_normal) { | ||
1054 | normal[0] = -normal[0]; | ||
1055 | normal[1] = -normal[1]; | ||
1056 | normal[2] = -normal[2]; | ||
1057 | } | ||
1058 | // compute contact point(s) | ||
1059 | contact->depth=-s; | ||
1060 | contact->normal[0]=-normal[0]; | ||
1061 | contact->normal[1]=-normal[1]; | ||
1062 | contact->normal[2]=-normal[2]; | ||
1063 | contact->g1=const_cast<dxGeom*> (o1); | ||
1064 | contact->g2=const_cast<dxGeom*> (o2); | ||
1065 | contact->pos[0]=p2[0]-normal[0]*sphereRadius; | ||
1066 | contact->pos[1]=p2[1]-normal[1]*sphereRadius; | ||
1067 | contact->pos[2]=p2[2]-normal[2]*sphereRadius; | ||
1068 | return 1; | ||
1069 | } | ||
1070 | |||
1071 | |||
1072 | |||
1073 | int dCollideCylB (dxGeom *o1, dxGeom *o2, int flags, | ||
1074 | dContactGeom *contact, int skip) | ||
1075 | { | ||
1076 | dVector3 normal; | ||
1077 | dReal depth; | ||
1078 | int code; | ||
1079 | dReal cylRadius,cylLength; | ||
1080 | dVector3 boxSides; | ||
1081 | dGeomCylinderGetParams(o1,&cylRadius,&cylLength); | ||
1082 | dGeomBoxGetLengths(o2,boxSides); | ||
1083 | int num = dCylBox(dGeomGetPosition(o1),dGeomGetRotation(o1),cylRadius,cylLength, | ||
1084 | dGeomGetPosition(o2),dGeomGetRotation(o2),boxSides, | ||
1085 | normal,&depth,&code,flags & NUMC_MASK,contact,skip); | ||
1086 | for (int i=0; i<num; i++) { | ||
1087 | CONTACT(contact,i*skip)->normal[0] = -normal[0]; | ||
1088 | CONTACT(contact,i*skip)->normal[1] = -normal[1]; | ||
1089 | CONTACT(contact,i*skip)->normal[2] = -normal[2]; | ||
1090 | CONTACT(contact,i*skip)->g1 = const_cast<dxGeom*> (o1); | ||
1091 | CONTACT(contact,i*skip)->g2 = const_cast<dxGeom*> (o2); | ||
1092 | } | ||
1093 | return num; | ||
1094 | } | ||
1095 | |||
1096 | int dCollideCylCyl (dxGeom *o1, dxGeom *o2, int flags, | ||
1097 | dContactGeom *contact, int skip) | ||
1098 | { | ||
1099 | dVector3 normal; | ||
1100 | dReal depth; | ||
1101 | int code; | ||
1102 | dReal cylRadius1,cylRadius2; | ||
1103 | dReal cylLength1,cylLength2; | ||
1104 | dGeomCylinderGetParams(o1,&cylRadius1,&cylLength1); | ||
1105 | dGeomCylinderGetParams(o2,&cylRadius2,&cylLength2); | ||
1106 | int num = dCylCyl (dGeomGetPosition(o1),dGeomGetRotation(o1),cylRadius1,cylLength1, | ||
1107 | dGeomGetPosition(o2),dGeomGetRotation(o2),cylRadius2,cylLength2, | ||
1108 | normal,&depth,&code,flags & NUMC_MASK,contact,skip); | ||
1109 | |||
1110 | for (int i=0; i<num; i++) { | ||
1111 | CONTACT(contact,i*skip)->normal[0] = -normal[0]; | ||
1112 | CONTACT(contact,i*skip)->normal[1] = -normal[1]; | ||
1113 | CONTACT(contact,i*skip)->normal[2] = -normal[2]; | ||
1114 | CONTACT(contact,i*skip)->g1 = const_cast<dxGeom*> (o1); | ||
1115 | CONTACT(contact,i*skip)->g2 = const_cast<dxGeom*> (o2); | ||
1116 | } | ||
1117 | return num; | ||
1118 | } | ||
1119 | |||
1120 | struct dxPlane { | ||
1121 | dReal p[4]; | ||
1122 | }; | ||
1123 | |||
1124 | |||
1125 | int dCollideCylPlane | ||
1126 | ( | ||
1127 | dxGeom *o1, dxGeom *o2, int flags, | ||
1128 | dContactGeom *contact, int skip){ | ||
1129 | dIASSERT (skip >= (int)sizeof(dContactGeom)); | ||
1130 | dIASSERT (dGeomGetClass(o1) == dCylinderClassUser); | ||
1131 | dIASSERT (dGeomGetClass(o2) == dPlaneClass); | ||
1132 | contact->g1 = const_cast<dxGeom*> (o1); | ||
1133 | contact->g2 = const_cast<dxGeom*> (o2); | ||
1134 | |||
1135 | unsigned int ret = 0; | ||
1136 | |||
1137 | dReal radius; | ||
1138 | dReal hlz; | ||
1139 | dGeomCylinderGetParams(o1,&radius,&hlz); | ||
1140 | hlz /= 2; | ||
1141 | |||
1142 | const dReal *R = dGeomGetRotation(o1);// rotation of cylinder | ||
1143 | const dReal* p = dGeomGetPosition(o1); | ||
1144 | dVector4 n; // normal vector | ||
1145 | dReal pp; | ||
1146 | dGeomPlaneGetParams (o2, n); | ||
1147 | pp=n[3]; | ||
1148 | dReal cos1,sin1; | ||
1149 | cos1=dFabs(dDOT14(n,R+1)); | ||
1150 | |||
1151 | cos1=cos1<REAL(1.) ? cos1 : REAL(1.); //cos1 may slightly exeed 1.f | ||
1152 | sin1=sqrtf(REAL(1.)-cos1*cos1); | ||
1153 | ////////////////////////////// | ||
1154 | |||
1155 | dReal sidePr=cos1*hlz+sin1*radius; | ||
1156 | |||
1157 | dReal dist=-pp+dDOT(n,p); | ||
1158 | dReal outDepth=sidePr-dist; | ||
1159 | |||
1160 | if(outDepth<0.f) return 0; | ||
1161 | |||
1162 | dVector3 pos; | ||
1163 | |||
1164 | |||
1165 | /////////////////////////////////////////// from geom.cpp dCollideBP | ||
1166 | dReal Q1 = dDOT14(n,R+0); | ||
1167 | dReal Q2 = dDOT14(n,R+1); | ||
1168 | dReal Q3 = dDOT14(n,R+2); | ||
1169 | dReal factor =sqrtf(Q1*Q1+Q3*Q3); | ||
1170 | factor= factor ? factor :1.f; | ||
1171 | dReal A1 = radius * Q1/factor; | ||
1172 | dReal A2 = hlz*Q2; | ||
1173 | dReal A3 = radius * Q3/factor; | ||
1174 | |||
1175 | pos[0]=p[0]; | ||
1176 | pos[1]=p[1]; | ||
1177 | pos[2]=p[2]; | ||
1178 | |||
1179 | pos[0]-= A1*R[0]; | ||
1180 | pos[1]-= A1*R[4]; | ||
1181 | pos[2]-= A1*R[8]; | ||
1182 | |||
1183 | pos[0]-= A3*R[2]; | ||
1184 | pos[1]-= A3*R[6]; | ||
1185 | pos[2]-= A3*R[10]; | ||
1186 | |||
1187 | pos[0]-= A2>0 ? hlz*R[1]:-hlz*R[1]; | ||
1188 | pos[1]-= A2>0 ? hlz*R[5]:-hlz*R[5]; | ||
1189 | pos[2]-= A2>0 ? hlz*R[9]:-hlz*R[9]; | ||
1190 | |||
1191 | |||
1192 | |||
1193 | contact->pos[0] = pos[0]; | ||
1194 | contact->pos[1] = pos[1]; | ||
1195 | contact->pos[2] = pos[2]; | ||
1196 | contact->depth = outDepth; | ||
1197 | ret=1; | ||
1198 | |||
1199 | if(dFabs(Q2)>M_SQRT1_2){ | ||
1200 | |||
1201 | CONTACT(contact,ret*skip)->pos[0]=pos[0]+2.f*A1*R[0]; | ||
1202 | CONTACT(contact,ret*skip)->pos[1]=pos[1]+2.f*A1*R[4]; | ||
1203 | CONTACT(contact,ret*skip)->pos[2]=pos[2]+2.f*A1*R[8]; | ||
1204 | CONTACT(contact,ret*skip)->depth=outDepth-dFabs(Q1*2.f*A1); | ||
1205 | |||
1206 | if(CONTACT(contact,ret*skip)->depth>0.f) | ||
1207 | ret++; | ||
1208 | |||
1209 | |||
1210 | CONTACT(contact,ret*skip)->pos[0]=pos[0]+2.f*A3*R[2]; | ||
1211 | CONTACT(contact,ret*skip)->pos[1]=pos[1]+2.f*A3*R[6]; | ||
1212 | CONTACT(contact,ret*skip)->pos[2]=pos[2]+2.f*A3*R[10]; | ||
1213 | CONTACT(contact,ret*skip)->depth=outDepth-dFabs(Q3*2.f*A3); | ||
1214 | |||
1215 | if(CONTACT(contact,ret*skip)->depth>0.f) ret++; | ||
1216 | } else { | ||
1217 | |||
1218 | CONTACT(contact,ret*skip)->pos[0]=pos[0]+2.f*(A2>0 ? hlz*R[1]:-hlz*R[1]); | ||
1219 | CONTACT(contact,ret*skip)->pos[1]=pos[1]+2.f*(A2>0 ? hlz*R[5]:-hlz*R[5]); | ||
1220 | CONTACT(contact,ret*skip)->pos[2]=pos[2]+2.f*(A2>0 ? hlz*R[9]:-hlz*R[9]); | ||
1221 | CONTACT(contact,ret*skip)->depth=outDepth-dFabs(Q2*2.f*A2); | ||
1222 | |||
1223 | if(CONTACT(contact,ret*skip)->depth>0.f) ret++; | ||
1224 | } | ||
1225 | |||
1226 | |||
1227 | |||
1228 | for (unsigned int i=0; i<ret; i++) { | ||
1229 | CONTACT(contact,i*skip)->g1 = const_cast<dxGeom*> (o1); | ||
1230 | CONTACT(contact,i*skip)->g2 = const_cast<dxGeom*> (o2); | ||
1231 | CONTACT(contact,i*skip)->normal[0] =n[0]; | ||
1232 | CONTACT(contact,i*skip)->normal[1] =n[1]; | ||
1233 | CONTACT(contact,i*skip)->normal[2] =n[2]; | ||
1234 | } | ||
1235 | return ret; | ||
1236 | } | ||
1237 | |||
1238 | int dCollideCylRay(dxGeom *o1, dxGeom *o2, int flags, | ||
1239 | dContactGeom *contact, int skip) { | ||
1240 | dIASSERT (skip >= (int)sizeof(dContactGeom)); | ||
1241 | dIASSERT (dGeomGetClass(o1) == dCylinderClassUser); | ||
1242 | dIASSERT (dGeomGetClass(o2) == dRayClass); | ||
1243 | contact->g1 = const_cast<dxGeom*> (o1); | ||
1244 | contact->g2 = const_cast<dxGeom*> (o2); | ||
1245 | dReal radius; | ||
1246 | dReal lz; | ||
1247 | dGeomCylinderGetParams(o1,&radius,&lz); | ||
1248 | dReal lz2=lz*REAL(0.5); | ||
1249 | const dReal *R = dGeomGetRotation(o1); // rotation of the cylinder | ||
1250 | const dReal *p = dGeomGetPosition(o1); // position of the cylinder | ||
1251 | dVector3 start,dir; | ||
1252 | dGeomRayGet(o2,start,dir); // position and orientation of the ray | ||
1253 | dReal length = dGeomRayGetLength(o2); | ||
1254 | |||
1255 | // compute some useful info | ||
1256 | dVector3 cs,q,r; | ||
1257 | dReal C,k; | ||
1258 | cs[0] = start[0] - p[0]; | ||
1259 | cs[1] = start[1] - p[1]; | ||
1260 | cs[2] = start[2] - p[2]; | ||
1261 | k = dDOT41(R+1,cs); // position of ray start along cyl axis (Y) | ||
1262 | q[0] = k*R[0*4+1] - cs[0]; | ||
1263 | q[1] = k*R[1*4+1] - cs[1]; | ||
1264 | q[2] = k*R[2*4+1] - cs[2]; | ||
1265 | C = dDOT(q,q) - radius*radius; | ||
1266 | // if C < 0 then ray start position within infinite extension of cylinder | ||
1267 | // if ray start position is inside the cylinder | ||
1268 | int inside_cyl=0; | ||
1269 | if (C<0 && !(k<-lz2 || k>lz2)) inside_cyl=1; | ||
1270 | // compute ray collision with infinite cylinder, except for the case where | ||
1271 | // the ray is outside the cylinder but within the infinite cylinder | ||
1272 | // (it that case the ray can only hit endcaps) | ||
1273 | if (!inside_cyl && C < 0) { | ||
1274 | // set k to cap position to check | ||
1275 | if (k < 0) k = -lz2; else k = lz2; | ||
1276 | } | ||
1277 | else { | ||
1278 | dReal uv = dDOT41(R+1,dir); | ||
1279 | r[0] = uv*R[0*4+1] - dir[0]; | ||
1280 | r[1] = uv*R[1*4+1] - dir[1]; | ||
1281 | r[2] = uv*R[2*4+1] - dir[2]; | ||
1282 | dReal A = dDOT(r,r); | ||
1283 | dReal B = 2*dDOT(q,r); | ||
1284 | k = B*B-4*A*C; | ||
1285 | if (k < 0) { | ||
1286 | // the ray does not intersect the infinite cylinder, but if the ray is | ||
1287 | // inside and parallel to the cylinder axis it may intersect the end | ||
1288 | // caps. set k to cap position to check. | ||
1289 | if (!inside_cyl) return 0; | ||
1290 | if (uv < 0) k = -lz2; else k = lz2; | ||
1291 | } | ||
1292 | else { | ||
1293 | k = dSqrt(k); | ||
1294 | A = dRecip (2*A); | ||
1295 | dReal alpha = (-B-k)*A; | ||
1296 | if (alpha < 0) { | ||
1297 | alpha = (-B+k)*A; | ||
1298 | if (alpha<0) return 0; | ||
1299 | } | ||
1300 | if (alpha>length) return 0; | ||
1301 | // the ray intersects the infinite cylinder. check to see if the | ||
1302 | // intersection point is between the caps | ||
1303 | contact->pos[0] = start[0] + alpha*dir[0]; | ||
1304 | contact->pos[1] = start[1] + alpha*dir[1]; | ||
1305 | contact->pos[2] = start[2] + alpha*dir[2]; | ||
1306 | q[0] = contact->pos[0] - p[0]; | ||
1307 | q[1] = contact->pos[1] - p[1]; | ||
1308 | q[2] = contact->pos[2] - p[2]; | ||
1309 | k = dDOT14(q,R+1); | ||
1310 | dReal nsign = inside_cyl ? -1 : 1; | ||
1311 | if (k >= -lz2 && k <= lz2) { | ||
1312 | contact->normal[0] = nsign * (contact->pos[0] - | ||
1313 | (p[0] + k*R[0*4+1])); | ||
1314 | contact->normal[1] = nsign * (contact->pos[1] - | ||
1315 | (p[1] + k*R[1*4+1])); | ||
1316 | contact->normal[2] = nsign * (contact->pos[2] - | ||
1317 | (p[2] + k*R[2*4+1])); | ||
1318 | dNormalize3 (contact->normal); | ||
1319 | contact->depth = alpha; | ||
1320 | return 1; | ||
1321 | } | ||
1322 | // the infinite cylinder intersection point is not between the caps. | ||
1323 | // set k to cap position to check. | ||
1324 | if (k < 0) k = -lz2; else k = lz2; | ||
1325 | } | ||
1326 | } | ||
1327 | // check for ray intersection with the caps. k must indicate the cap | ||
1328 | // position to check | ||
1329 | // perform a ray plan interesection | ||
1330 | // R+1 is the plan normal | ||
1331 | q[0] = start[0] - (p[0] + k*R[0*4+1]); | ||
1332 | q[1] = start[1] - (p[1] + k*R[1*4+1]); | ||
1333 | q[2] = start[2] - (p[2] + k*R[2*4+1]); | ||
1334 | dReal alpha = -dDOT14(q,R+1); | ||
1335 | dReal k2 = dDOT14(dir,R+1); | ||
1336 | if (k2==0) return 0; // ray parallel to the plane | ||
1337 | alpha/=k2; | ||
1338 | if (alpha<0 || alpha>length) return 0; // too short | ||
1339 | contact->pos[0]=start[0]+alpha*dir[0]; | ||
1340 | contact->pos[1]=start[1]+alpha*dir[1]; | ||
1341 | contact->pos[2]=start[2]+alpha*dir[2]; | ||
1342 | dReal nsign = (k<0)?-1:1; | ||
1343 | contact->normal[0]=nsign*R[0*4+1]; | ||
1344 | contact->normal[1]=nsign*R[1*4+1]; | ||
1345 | contact->normal[2]=nsign*R[2*4+1]; | ||
1346 | contact->depth=alpha; | ||
1347 | return 1; | ||
1348 | } | ||
1349 | |||
1350 | static dColliderFn * dCylinderColliderFn (int num) | ||
1351 | { | ||
1352 | if (num == dBoxClass) return (dColliderFn *) &dCollideCylB; | ||
1353 | else if (num == dSphereClass) return (dColliderFn *) &dCollideCylS; | ||
1354 | else if (num == dCylinderClassUser) return (dColliderFn *) &dCollideCylCyl; | ||
1355 | else if (num == dPlaneClass) return (dColliderFn *) &dCollideCylPlane; | ||
1356 | else if (num == dRayClass) return (dColliderFn *) &dCollideCylRay; | ||
1357 | return 0; | ||
1358 | } | ||
1359 | |||
1360 | |||
1361 | static void dCylinderAABB (dxGeom *geom, dReal aabb[6]) | ||
1362 | { | ||
1363 | dReal radius,lz; | ||
1364 | dGeomCylinderGetParams(geom,&radius,&lz); | ||
1365 | const dReal* R= dGeomGetRotation(geom); | ||
1366 | const dReal* pos= dGeomGetPosition(geom); | ||
1367 | dReal xrange = dFabs (R[0] *radius) + | ||
1368 | REAL(0.5) *dFabs (R[1] * lz) + dFabs (R[2] * radius); | ||
1369 | |||
1370 | dReal yrange = dFabs (R[4] *radius) + | ||
1371 | REAL(0.5) * dFabs (R[5] * lz) + dFabs (R[6] * radius); | ||
1372 | |||
1373 | dReal zrange = dFabs (R[8] * radius) + | ||
1374 | REAL(0.5) *dFabs (R[9] * lz) + dFabs (R[10] * radius); | ||
1375 | |||
1376 | aabb[0] = pos[0] - xrange; | ||
1377 | aabb[1] = pos[0] + xrange; | ||
1378 | aabb[2] = pos[1] - yrange; | ||
1379 | aabb[3] = pos[1] + yrange; | ||
1380 | aabb[4] = pos[2] - zrange; | ||
1381 | aabb[5] = pos[2] + zrange; | ||
1382 | } | ||
1383 | |||
1384 | dxGeom *dCreateCylinder (dSpaceID space, dReal r, dReal lz) | ||
1385 | { | ||
1386 | dAASSERT (r > 0 && lz > 0); | ||
1387 | if (dCylinderClassUser == -1) | ||
1388 | { | ||
1389 | dGeomClass c; | ||
1390 | c.bytes = sizeof (dxCylinder); | ||
1391 | c.collider = &dCylinderColliderFn; | ||
1392 | c.aabb = &dCylinderAABB; | ||
1393 | c.aabb_test = 0; | ||
1394 | c.dtor = 0; | ||
1395 | dCylinderClassUser=dCreateGeomClass (&c); | ||
1396 | |||
1397 | } | ||
1398 | |||
1399 | dGeomID g = dCreateGeom (dCylinderClassUser); | ||
1400 | if (space) dSpaceAdd (space,g); | ||
1401 | dxCylinder *c = (dxCylinder*) dGeomGetClassData(g); | ||
1402 | |||
1403 | c->radius = r; | ||
1404 | c->lz = lz; | ||
1405 | return g; | ||
1406 | } | ||
1407 | |||
1408 | |||
1409 | |||
1410 | void dGeomCylinderSetParams (dGeomID g, dReal radius, dReal length) | ||
1411 | { | ||
1412 | dUASSERT (g && dGeomGetClass(g) == dCylinderClassUser,"argument not a cylinder"); | ||
1413 | dAASSERT (radius > 0 && length > 0); | ||
1414 | dxCylinder *c = (dxCylinder*) dGeomGetClassData(g); | ||
1415 | c->radius = radius; | ||
1416 | c->lz = length; | ||
1417 | } | ||
1418 | |||
1419 | |||
1420 | |||
1421 | void dGeomCylinderGetParams (dGeomID g, dReal *radius, dReal *length) | ||
1422 | { | ||
1423 | dUASSERT (g && dGeomGetClass(g) == dCylinderClassUser ,"argument not a cylinder"); | ||
1424 | dxCylinder *c = (dxCylinder*) dGeomGetClassData(g); | ||
1425 | *radius = c->radius; | ||
1426 | *length = c->lz; | ||
1427 | } | ||
1428 | |||
1429 | /* | ||
1430 | void dMassSetCylinder (dMass *m, dReal density, | ||
1431 | dReal radius, dReal length) | ||
1432 | { | ||
1433 | dAASSERT (m); | ||
1434 | dMassSetZero (m); | ||
1435 | dReal M = length*M_PI*radius*radius*density; | ||
1436 | m->mass = M; | ||
1437 | m->_I(0,0) = M/REAL(4.0) * (ly*ly + lz*lz); | ||
1438 | m->_I(1,1) = M/REAL(12.0) * (lx*lx + lz*lz); | ||
1439 | m->_I(2,2) = M/REAL(4.0) * (lx*lx + ly*ly); | ||
1440 | |||
1441 | # ifndef dNODEBUG | ||
1442 | checkMass (m); | ||
1443 | # endif | ||
1444 | } | ||
1445 | */ | ||