Capsule.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. /******************************************************************************/
  5. Capsule& Capsule::operator*=(Flt f) {pos*=f; r*=f; h*=f; return T;}
  6. Capsule& Capsule::operator/=(Flt f) {pos/=f; r/=f; h/=f; return T;}
  7. CapsuleM& CapsuleM::operator*=(Flt f) {pos*=f; r*=f; h*=f; return T;}
  8. CapsuleM& CapsuleM::operator/=(Flt f) {pos/=f; r/=f; h/=f; return T;}
  9. Capsule& Capsule::operator*=(C Vec &v)
  10. {
  11. Matrix3 m; m.setUp(up)*=v;
  12. h*= m.y.length();
  13. r*=Avg(m.x.length(), m.z.length());
  14. pos*=v;
  15. return T;
  16. }
  17. Capsule& Capsule::operator/=(C Vec &v)
  18. {
  19. Matrix3 m; m.setUp(up)/=v;
  20. h*= m.y.length();
  21. r*=Avg(m.x.length(), m.z.length());
  22. pos/=v;
  23. return T;
  24. }
  25. CapsuleM& CapsuleM::operator*=(C Vec &v)
  26. {
  27. Matrix3 m; m.setUp(up)*=v;
  28. h*= m.y.length();
  29. r*=Avg(m.x.length(), m.z.length());
  30. pos*=v;
  31. return T;
  32. }
  33. CapsuleM& CapsuleM::operator/=(C Vec &v)
  34. {
  35. Matrix3 m; m.setUp(up)/=v;
  36. h*= m.y.length();
  37. r*=Avg(m.x.length(), m.z.length());
  38. pos/=v;
  39. return T;
  40. }
  41. Capsule& Capsule::operator*=(C Matrix3 &m)
  42. {
  43. pos*=m;
  44. up *=m;
  45. h *=up.normalize();
  46. r *=m .avgScale ();
  47. return T;
  48. }
  49. Capsule& Capsule::operator/=(C Matrix3 &m)
  50. {
  51. pos/=m;
  52. up /=m;
  53. h *=up.normalize(); // 'h' should indeed be multiplied here because 'up' already got transformed in correct way
  54. r /=m .avgScale ();
  55. return T;
  56. }
  57. Capsule& Capsule::operator*=(C Matrix &m)
  58. {
  59. pos*=m;
  60. up *=m .orn();
  61. h *=up.normalize();
  62. r *=m .avgScale ();
  63. return T;
  64. }
  65. Capsule& Capsule::operator/=(C Matrix &m)
  66. {
  67. pos/=m;
  68. up /=m .orn();
  69. h *=up.normalize(); // 'h' should indeed be multiplied here because 'up' already got transformed in correct way
  70. r /=m .avgScale ();
  71. return T;
  72. }
  73. /******************************************************************************/
  74. Capsule& Capsule::set(Flt r, C Vec &from, C Vec &to)
  75. {
  76. T.r =r;
  77. T.pos=Avg(from, to);
  78. T.up =to-from;
  79. T.h =T.up.normalize()+r*2;
  80. return T;
  81. }
  82. Capsule& Capsule::setEdge(Flt r, C Vec &from, C Vec &to)
  83. {
  84. T.r =r;
  85. T.pos=Avg(from, to);
  86. T.up =to-from;
  87. T.h =T.up.normalize();
  88. return T;
  89. }
  90. /******************************************************************************/
  91. Vec Capsule::nearest(C Vec &normal)C
  92. {
  93. return pos - normal*r - up*( Sign(Dot(up, normal))*(h*0.5f-r) );
  94. }
  95. VecD CapsuleM::nearest(C Vec &normal)C
  96. {
  97. return pos - normal*r - up*( Sign(Dot(up, normal))*(h*0.5f-r) );
  98. }
  99. /******************************************************************************/
  100. void Capsule::draw(C Color &color, Bool fill, Int resolution)C
  101. {
  102. if(isBall())Ball(T).draw(color, fill, resolution);else
  103. {
  104. if(resolution<0)resolution=24;else if(resolution<3)resolution=3;
  105. Tube t(r, h-r*2, pos, up); t.draw(color, fill, resolution); t.up*=t.h*0.5f;
  106. Ball (r, pos+t.up).drawAngle(color, 0, PI_2, up, fill, VecI2(resolution, resolution/3));
  107. Ball (r, pos-t.up).drawAngle(color, 0, -PI_2, up, fill, VecI2(resolution, resolution/3));
  108. }
  109. }
  110. /******************************************************************************/
  111. Flt Dist(C Vec &point, C Capsule &capsule) // safe in case "capsule.isBall()"
  112. {
  113. Vec up=(capsule.h*0.5f-capsule.r)*capsule.up;
  114. return Max(0, DistPointEdge(point, capsule.pos-up, capsule.pos+up)-capsule.r); // 'DistPointEdge' is safe in case edge is zero length
  115. }
  116. Flt Dist(C Edge &edge, C Capsule &capsule) // safe in case "capsule.isBall()"
  117. {
  118. return Max(0, Dist(capsule.edge(), edge)-capsule.r);
  119. }
  120. Flt Dist(C Tri &tri, C Capsule &capsule) // safe in case "capsule.isBall()"
  121. {
  122. return Max(0, Dist(capsule.edge(), tri)-capsule.r);
  123. }
  124. Flt Dist(C Box &box, C Capsule &capsule) // safe in case "capsule.isBall()"
  125. {
  126. return Max(0, Dist(capsule.edge(), box)-capsule.r);
  127. }
  128. Flt Dist(C OBox &obox, C Capsule &capsule) // safe in case "capsule.isBall()"
  129. {
  130. Capsule temp=capsule; // temp = capsule in box local space
  131. temp.pos.divNormalized(obox.matrix );
  132. temp.up .divNormalized(obox.matrix.orn());
  133. return Dist(obox.box, temp);
  134. }
  135. Flt Dist(C Ball &ball, C Capsule &capsule) // safe in case "capsule.isBall()"
  136. {
  137. return Max(0, Dist(ball.pos, capsule.edge())-capsule.r-ball.r);
  138. }
  139. Flt Dist(C Capsule &a, C Capsule &b) // safe in case "capsule.isBall()"
  140. {
  141. return Max(0, Dist(a.edge(), b.edge())-a.r-b.r);
  142. }
  143. Flt DistCapsulePlane(C Capsule &capsule, C Vec &plane, C Vec &normal) // safe in case "capsule.isBall()"
  144. {
  145. return DistPointPlane(capsule.nearest(normal), plane, normal);
  146. }
  147. Dbl DistCapsulePlane(C Capsule &capsule, C VecD &plane, C Vec &normal)
  148. {
  149. return DistPointPlane(capsule.nearest(normal), plane, normal);
  150. }
  151. Dbl DistCapsulePlane(C CapsuleM &capsule, C VecD &plane, C Vec &normal)
  152. {
  153. return DistPointPlane(capsule.nearest(normal), plane, normal);
  154. }
  155. /******************************************************************************/
  156. Bool Cuts(C Vec &point, C Capsule &capsule) // safe in case "capsule.isBall()"
  157. {
  158. Vec up=(capsule.h*0.5f-capsule.r)*capsule.up;
  159. return DistPointEdge(point, capsule.pos-up, capsule.pos+up)<=capsule.r;
  160. }
  161. Bool Cuts(C VecD &point, C Capsule &capsule) // safe in case "capsule.isBall()"
  162. {
  163. Vec up=(capsule.h*0.5f-capsule.r)*capsule.up;
  164. return DistPointEdge(point, capsule.pos-up, capsule.pos+up)<=capsule.r;
  165. }
  166. Bool Cuts(C VecD &point, C CapsuleM &capsule) // safe in case "capsule.isBall()"
  167. {
  168. Vec up=(capsule.h*0.5f-capsule.r)*capsule.up;
  169. return DistPointEdge(point, capsule.pos-up, capsule.pos+up)<=capsule.r;
  170. }
  171. Bool Cuts(C Edge &edge, C Capsule &capsule) // safe in case "capsule.isBall()"
  172. {
  173. return Dist(capsule.edge(), edge)<=capsule.r;
  174. }
  175. Bool Cuts(C Tri &tri, C Capsule &capsule) // safe in case "capsule.isBall()"
  176. {
  177. return Dist(capsule.edge(), tri)<=capsule.r;
  178. }
  179. Bool Cuts(C Box &box, C Capsule &capsule) // safe in case "capsule.isBall()"
  180. {
  181. return Dist(capsule.edge(), box)<=capsule.r;
  182. }
  183. Bool Cuts(C OBox &obox, C Capsule &capsule) // safe in case "capsule.isBall()"
  184. {
  185. Capsule temp=capsule;
  186. temp.pos.divNormalized(obox.matrix );
  187. temp.up .divNormalized(obox.matrix.orn());
  188. return Dist(temp.edge(), obox.box)<=temp.r;
  189. }
  190. Bool Cuts(C Ball &ball, C Capsule &capsule) // safe in case "capsule.isBall()"
  191. {
  192. return Dist(ball.pos, capsule.edge())<=capsule.r+ball.r;
  193. }
  194. Bool Cuts(C Capsule &a, C Capsule &b) // safe in case "capsule.isBall()"
  195. {
  196. return Dist(a.edge(), b.edge())<=a.r+b.r;
  197. }
  198. /******************************************************************************/
  199. Bool SweepPointCapsule(C Vec &point, C Vec &move, C Capsule &capsule, Flt *hit_frac, Vec *hit_normal) // safe in case "capsule.isBall()"
  200. {
  201. return SweepBallEdge(Ball(capsule.r, point), move, capsule.edge(), hit_frac, hit_normal);
  202. }
  203. Bool SweepBallCapsule(C Ball &ball, C Vec &move, C Capsule &capsule, Flt *hit_frac, Vec *hit_normal) // safe in case "capsule.isBall()"
  204. {
  205. return SweepBallEdge(Ball(ball.r+capsule.r, ball.pos), move, capsule.edge(), hit_frac, hit_normal);
  206. }
  207. /******************************************************************************/
  208. Bool SweepCapsuleEdge(C Capsule &capsule, C Vec &move, C Edge &edge, Flt *hit_frac, Vec *hit_normal)
  209. {
  210. Byte check;
  211. Flt tube_h_2=capsule.h*0.5f-capsule.r;
  212. Matrix matrix; matrix. setPosDir(capsule.pos, capsule.up);
  213. Edge2 edge2 (matrix. convert(edge.p[0] , true), matrix.convert(edge.p[1], true));
  214. Vec2 move2 =matrix.orn().convert(move , true);
  215. Vec2 edge2_d=edge2.p[1]-edge2.p[0];
  216. Bool swap=false;
  217. if(Dot(move2, Perp(edge2_d))>0)
  218. {
  219. Swap(edge2.p[0], edge2.p[1]);
  220. edge2_d.chs();
  221. swap=true;
  222. }
  223. Flt frac; Vec2 normal2; if(!SweepCircleEdge(Circle(capsule.r), move2, edge2, &frac, &normal2))
  224. {
  225. check=(DistPointEdge(capsule.pos+capsule.up*tube_h_2, edge.p[0], edge.p[1])<DistPointEdge(capsule.pos-capsule.up*tube_h_2, edge.p[0], edge.p[1]));
  226. }else
  227. {
  228. Byte hitd =false;
  229. Flt pos_h=frac*Dot (move , capsule.up),
  230. e0_h =DistPointPlane(edge.p[0], capsule.pos, capsule.up),
  231. e1_h =DistPointPlane(edge.p[1], capsule.pos, capsule.up);
  232. if(swap)Swap(e0_h, e1_h);
  233. if(Equal(edge2.p[0], edge2.p[1]))
  234. {
  235. Flt min_h, max_h; MinMax(e0_h, e1_h, min_h, max_h);
  236. if(min_h>pos_h+tube_h_2)check=1;else // upper
  237. if(max_h<pos_h-tube_h_2)check=0;else // lower
  238. hitd=true;
  239. }else
  240. {
  241. Vec2 hit_point=frac*move2 - capsule.r*normal2;
  242. Flt edge_step =Sat(DistPointPlane(hit_point, edge2.p[0], edge2_d)/DistPointPlane(edge2.p[1], edge2.p[0], edge2_d));
  243. Flt edge_h =e0_h + edge_step*(e1_h-e0_h);
  244. if(Abs(edge_h-pos_h)>tube_h_2)check=(edge_h>pos_h);else
  245. hitd=true;
  246. }
  247. if(hitd)
  248. {
  249. if(hit_frac )*hit_frac =frac;
  250. if(hit_normal)*hit_normal=matrix.orn().convert(normal2);
  251. return true;
  252. }
  253. }
  254. Ball ball(capsule.r, capsule.pos); ball.pos+=capsule.up*(check ? tube_h_2 : -tube_h_2);
  255. return SweepBallEdge(ball, move, edge, hit_frac, hit_normal);
  256. }
  257. /******************************************************************************/
  258. Bool SweepCapsulePlane(C Capsule &capsule, C Vec &move, C Plane &plane, Flt *hit_frac, Vec *hit_normal, Vec *hit_pos) // safe in case "capsule.isBall()"
  259. {
  260. if(Dot(move, plane.normal)>=0)return false;
  261. return SweepPointPlane(capsule.nearest(plane.normal), move, plane, hit_frac, hit_normal, hit_pos);
  262. }
  263. Bool SweepCapsuleTri(C Capsule &capsule, C Vec &move, C Tri &tri, Flt *hit_frac, Vec *hit_normal)
  264. {
  265. if(Dot(move, tri.n)>=0)return false;
  266. if(SweepPointTri(capsule.nearest(tri.n), move, tri, hit_frac))
  267. {
  268. if(hit_normal)*hit_normal=tri.n;
  269. return true;
  270. }
  271. Byte hit=false;
  272. Flt f, frac;
  273. Vec n, normal;
  274. REP(3)if(SweepCapsuleEdge(capsule, move, tri.edge(i), &f, &n))if(!hit || f<frac){hit=true; frac=f; normal=n;}
  275. if(hit)
  276. {
  277. if(hit_frac )*hit_frac =frac ;
  278. if(hit_normal)*hit_normal=normal;
  279. return true;
  280. }
  281. return false;
  282. }
  283. /******************************************************************************/
  284. }
  285. /******************************************************************************/