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 | */ |
---|