dCylinder.cpp 38 KB

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