Circle.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. /******************************************************************************/
  5. void Circle::draw(C Color &color, Bool fill, Int resolution)C
  6. {
  7. if(resolution<0)resolution=96;else if(resolution<3)resolution=3;
  8. Vec2 prev(pos.x+r, pos.y);
  9. VI.color(color);
  10. REP(resolution)
  11. {
  12. Flt c, s; CosSin(c, s, (PI2*i)/resolution); Vec2 next(pos.x+c*r, pos.y+s*r);
  13. if(fill)VI.tri (pos , next, prev);
  14. else VI.line(prev, next);
  15. prev=next;
  16. }
  17. VI.end();
  18. }
  19. void Circle::drawPie(C Color &color, Flt r_start, Flt angle_start, Flt angle_range, Bool fill, Int resolution)C
  20. {
  21. if(Abs(angle_range)>=PI2 && !fill) // draw inner and outer lines only
  22. {
  23. Circle(r_start, pos).draw(color, false, resolution); // draw inner lines
  24. draw(color, false, resolution); // draw outer lines
  25. }else
  26. {
  27. if(resolution<0)resolution=96;else if(resolution<3)resolution=3;
  28. Flt c, s; CosSin(c, s, angle_start+angle_range); Vec2 prev(pos.x+c*r, pos.y+s*r), prev2(pos.x+c*r_start, pos.y+s*r_start);
  29. VI.color(color);
  30. if(!fill)VI.line(prev, prev2); // side line
  31. REP(resolution)
  32. {
  33. CosSin(c, s, angle_start+(angle_range*i)/resolution); Vec2 next(pos.x+c*r, pos.y+s*r), next2(pos.x+c*r_start, pos.y+s*r_start);
  34. if(fill)VI.quad(prev, next, next2, prev2);
  35. else {VI.line(prev, next); VI.line(prev2, next2);}
  36. prev=next; prev2=next2;
  37. }
  38. if(!fill)VI.line(prev, prev2); // side line
  39. VI.end();
  40. }
  41. }
  42. /******************************************************************************/
  43. Flt Dist(C Vec2 &point, C Circle &circle)
  44. {
  45. return Max(0, Dist(point, circle.pos)-circle.r);
  46. }
  47. Flt Dist(C VecI2 &point, C Circle &circle)
  48. {
  49. return Max(0, Dist(point, circle.pos)-circle.r);
  50. }
  51. Flt Dist(C Rect &rect, C Circle &circle)
  52. {
  53. Flt dist2=0;
  54. if(circle.pos.x<rect.min.x)dist2+=Sqr(circle.pos.x-rect.min.x);else
  55. if(circle.pos.x>rect.max.x)dist2+=Sqr(circle.pos.x-rect.max.x);
  56. if(circle.pos.y<rect.min.y)dist2+=Sqr(circle.pos.y-rect.min.y);else
  57. if(circle.pos.y>rect.max.y)dist2+=Sqr(circle.pos.y-rect.max.y);
  58. return Max(0, SqrtFast(dist2)-circle.r);
  59. }
  60. Flt Dist(C RectI &rect, C Circle &circle)
  61. {
  62. Flt dist2=0;
  63. if(circle.pos.x<rect.min.x)dist2+=Sqr(circle.pos.x-rect.min.x);else
  64. if(circle.pos.x>rect.max.x)dist2+=Sqr(circle.pos.x-rect.max.x);
  65. if(circle.pos.y<rect.min.y)dist2+=Sqr(circle.pos.y-rect.min.y);else
  66. if(circle.pos.y>rect.max.y)dist2+=Sqr(circle.pos.y-rect.max.y);
  67. return Max(0, SqrtFast(dist2)-circle.r);
  68. }
  69. Flt Dist(C Circle &a, C Circle &b)
  70. {
  71. return Max(0, Dist(a.pos, b.pos)-a.r-b.r);
  72. }
  73. /******************************************************************************/
  74. Bool Cuts(C Vec2 &point, C Circle &circle)
  75. {
  76. return Dist2(point, circle.pos)<=Sqr(circle.r);
  77. }
  78. Bool Cuts(C VecI2 &point, C Circle &circle)
  79. {
  80. return Dist2(point, circle.pos)<=Sqr(circle.r);
  81. }
  82. Bool Cuts(C Rect &rect, C Circle &circle)
  83. {
  84. Flt dist2=0;
  85. if(circle.pos.x<rect.min.x)dist2+=Sqr(circle.pos.x-rect.min.x);else
  86. if(circle.pos.x>rect.max.x)dist2+=Sqr(circle.pos.x-rect.max.x);
  87. if(circle.pos.y<rect.min.y)dist2+=Sqr(circle.pos.y-rect.min.y);else
  88. if(circle.pos.y>rect.max.y)dist2+=Sqr(circle.pos.y-rect.max.y);
  89. return dist2<=Sqr(circle.r);
  90. }
  91. Bool Cuts(C RectI &rect, C Circle &circle)
  92. {
  93. Flt dist2=0;
  94. if(circle.pos.x<rect.min.x)dist2+=Sqr(circle.pos.x-rect.min.x);else
  95. if(circle.pos.x>rect.max.x)dist2+=Sqr(circle.pos.x-rect.max.x);
  96. if(circle.pos.y<rect.min.y)dist2+=Sqr(circle.pos.y-rect.min.y);else
  97. if(circle.pos.y>rect.max.y)dist2+=Sqr(circle.pos.y-rect.max.y);
  98. return dist2<=Sqr(circle.r);
  99. }
  100. Bool Cuts(C Circle &a, C Circle &b)
  101. {
  102. return Dist2(a.pos, b.pos)<=Sqr(a.r+b.r);
  103. }
  104. /******************************************************************************/
  105. Int CutsStrCircle(C Vec2 &point, C Vec2 &normal, C Circle &circle, Vec2 *contact_a, Vec2 *contact_b, Flt *width)
  106. {
  107. Flt d=DistPointPlane(point, circle.pos, normal),
  108. y=Abs(d);
  109. Vec2 right(normal.y, -normal.x);
  110. if(!y)
  111. {
  112. right*=circle.r;
  113. if(contact_a )*contact_a=circle.pos+right;
  114. if(contact_b )*contact_b=circle.pos-right;
  115. if(width )*width =circle.r;
  116. return 2;
  117. }
  118. if(y==circle.r)
  119. {
  120. if(contact_a)*contact_a=circle.pos+d*normal;
  121. if(width )*width =0;
  122. return 1;
  123. }
  124. if(y>circle.r)return 0;
  125. Vec2 center=circle.pos+d*normal;
  126. Flt x =Sqrt(circle.r*circle.r - y*y);
  127. right*=x;
  128. if(contact_a)*contact_a=center+right;
  129. if(contact_b)*contact_b=center-right;
  130. if(width )*width =x;
  131. return 2;
  132. }
  133. /******************************************************************************/
  134. Int CutsCircleCircle(C Circle &c1, C Circle &c2, Vec2 *contact_a, Vec2 *contact_b, Flt *width)
  135. {
  136. Vec2 edge=c2.pos-c1.pos;
  137. Flt Sr, Lr, d=edge.length();
  138. MinMax(c1.r, c2.r, Sr, Lr);
  139. // the same center
  140. if(!d)return (c1.r==c2.r) ? -1 : 0;
  141. // inside || outside separate
  142. if(d+Sr<Lr || d>c1.r+c2.r)return 0;
  143. // inside || outside together
  144. if(d+Sr==Lr || d==c1.r+c2.r){if(contact_a)*contact_a=c1.pos+(c1.r/d)*edge; return 1;}
  145. // 2 points, straight covering those points : ax + by = c
  146. Flt c =c1.r*c1.r - c2.r*c2.r;
  147. Flt x1=c1.pos.x, x2=c2.pos.x, a=2*(x2-x1); c+=x2*x2 - x1*x1;
  148. Flt y1=c1.pos.y, y2=c2.pos.y, b=2*(y2-y1); c+=y2*y2 - y1*y1;
  149. Flt l =Sqrt(a*a + b*b);
  150. a/=l;
  151. b/=l;
  152. c/=l;
  153. Vec2 normal(a, b), point(a*c, b*c);
  154. return CutsStrCircle(point, normal, c1, contact_a, contact_b, width);
  155. }
  156. /******************************************************************************/
  157. Bool Inside(C Rect &a, C Circle &b)
  158. {
  159. #if 0 // this is slower
  160. return Dist2(Max(Abs(a.max.x-b.pos.x), Abs(a.min.x-b.pos.x)),
  161. Max(Abs(a.max.y-b.pos.y), Abs(a.min.y-b.pos.y)))<=Sqr(b.r);
  162. #else // this is faster
  163. return Max(Sqr(a.max.x-b.pos.x), Sqr(a.min.x-b.pos.x))
  164. +Max(Sqr(a.max.y-b.pos.y), Sqr(a.min.y-b.pos.y))<=Sqr(b.r);
  165. #endif
  166. }
  167. /******************************************************************************/
  168. Bool SweepPointCircle(C Vec2 &point, C Vec2 &move, C Circle &circle, Flt *hit_frac, Vec2 *hit_normal)
  169. {
  170. Vec2 dir =move; Flt length=dir.normalize();
  171. Vec2 dir_n =Perp(dir);
  172. Flt s =DistPointPlane(circle.pos, point, dir_n)/circle.r; if(Abs(s)>1)return false;
  173. Vec2 normal=-s*dir_n-CosSin(s)*dir;
  174. Flt d =DistPointPlane(circle.pos+normal*circle.r, point, dir); if(d<0 || d>length)return false;
  175. if(hit_frac )*hit_frac =d/length;
  176. if(hit_normal)*hit_normal=normal;
  177. return true;
  178. }
  179. Bool SweepPointCircle(C VecD2 &point, C VecD2 &move, C CircleD &circle, Dbl *hit_frac, VecD2 *hit_normal)
  180. {
  181. VecD2 dir =move; Dbl length=dir.normalize();
  182. VecD2 dir_n =Perp(dir);
  183. Dbl s =DistPointPlane(circle.pos, point, dir_n)/circle.r; if(Abs(s)>1)return false;
  184. VecD2 normal=-s*dir_n-CosSin(s)*dir;
  185. Dbl d =DistPointPlane(circle.pos+normal*circle.r, point, dir); if(d<0 || d>length)return false;
  186. if(hit_frac )*hit_frac =d/length;
  187. if(hit_normal)*hit_normal=normal;
  188. return true;
  189. }
  190. /******************************************************************************/
  191. Bool SweepEdgeCircle(C Edge2 &edge, C Vec2 &move, C Circle &circle, Flt *hit_frac, Vec2 *hit_normal)
  192. {
  193. Byte point_test;
  194. Vec2 edge_dir =edge.p[1]-edge.p[0];
  195. Vec2 edge_normal=PerpN(edge_dir);
  196. if(!Dot(move, edge_normal))point_test=(Dot(edge_dir, move)>0);else
  197. {
  198. Vec2 point=circle.pos - edge_normal*circle.r;
  199. Flt frac; if(SweepPlanePoint(Plane2(edge.p[0], edge_normal), move, point, &frac))
  200. {
  201. point-=frac*move;
  202. if(DistPointPlane(point, edge.p[0], edge_dir)<0)point_test=0;else
  203. if(DistPointPlane(point, edge.p[1], edge_dir)>0)point_test=1;else
  204. {
  205. if(hit_frac )*hit_frac = frac;
  206. if(hit_normal)*hit_normal=-edge_normal;
  207. return true;
  208. }
  209. }else point_test=Closer(circle.pos, edge.p[0], edge.p[1]);
  210. }
  211. return SweepPointCircle(edge.p[point_test], move, circle, hit_frac, hit_normal);
  212. }
  213. Bool SweepEdgeCircle(C EdgeD2 &edge, C VecD2 &move, C CircleD &circle, Dbl *hit_frac, VecD2 *hit_normal)
  214. {
  215. Byte point_test;
  216. VecD2 edge_dir =edge.p[1]-edge.p[0];
  217. VecD2 edge_normal=PerpN(edge_dir);
  218. if(!Dot(move, edge_normal))point_test=(Dot(edge_dir, move)>0);else
  219. {
  220. VecD2 point=circle.pos - edge_normal*circle.r;
  221. Dbl frac; if(SweepPlanePoint(PlaneD2(edge.p[0], edge_normal), move, point, &frac))
  222. {
  223. point-=frac*move;
  224. if(DistPointPlane(point, edge.p[0], edge_dir)<0)point_test=0;else
  225. if(DistPointPlane(point, edge.p[1], edge_dir)>0)point_test=1;else
  226. {
  227. if(hit_frac )*hit_frac = frac;
  228. if(hit_normal)*hit_normal=-edge_normal;
  229. return true;
  230. }
  231. }else point_test=Closer(circle.pos, edge.p[0], edge.p[1]);
  232. }
  233. return SweepPointCircle(edge.p[point_test], move, circle, hit_frac, hit_normal);
  234. }
  235. /******************************************************************************/
  236. Bool SweepCircleCircle(C Circle &circle, C Vec2 &move, C Circle &c2, Flt *hit_frac, Vec2 *hit_normal)
  237. {
  238. Vec2 dir=move; Flt length=dir.normalize();
  239. Vec2 d =c2.pos-circle.pos;
  240. Flt b =-2*Dot(dir, d),
  241. c =d.length2()-Sqr(circle.r+c2.r),
  242. x1, x2;
  243. Int xs=Polynominal2(1, b, c, x1, x2);
  244. if(xs>=1 && x1>=0 && x1<=length)
  245. {
  246. Flt frac=x1/length;
  247. if(hit_frac )*hit_frac =frac;
  248. if(hit_normal)*hit_normal=!((circle.pos+frac*move)-c2.pos);
  249. return true;
  250. }
  251. return false;
  252. }
  253. Bool SweepCircleCircle(C CircleD &circle, C VecD2 &move, C CircleD &c2, Dbl *hit_frac, VecD2 *hit_normal)
  254. {
  255. VecD2 dir=move; Dbl length=dir.normalize();
  256. VecD2 d =c2.pos-circle.pos;
  257. Dbl b =-2*Dot(dir, d),
  258. c =d.length2()-Sqr(circle.r+c2.r),
  259. x1, x2;
  260. Int xs=Polynominal2(1, b, c, x1, x2);
  261. if(xs>=1 && x1>=0 && x1<=length)
  262. {
  263. Dbl frac=x1/length;
  264. if(hit_frac )*hit_frac =frac;
  265. if(hit_normal)*hit_normal=!((circle.pos+frac*move)-c2.pos);
  266. return true;
  267. }
  268. return false;
  269. }
  270. /******************************************************************************/
  271. Bool SweepCirclePoint(C Circle &circle, C Vec2 &move, C Vec2 &point, Flt *hit_frac, Vec2 *hit_normal)
  272. {
  273. if(SweepPointCircle(point, -move, circle, hit_frac, hit_normal)){if(hit_normal)hit_normal->chs(); return true;}
  274. return false;
  275. }
  276. Bool SweepCirclePoint(C CircleD &circle, C VecD2 &move, C VecD2 &point, Dbl *hit_frac, VecD2 *hit_normal)
  277. {
  278. if(SweepPointCircle(point, -move, circle, hit_frac, hit_normal)){if(hit_normal)hit_normal->chs(); return true;}
  279. return false;
  280. }
  281. /******************************************************************************/
  282. Bool SweepCircleEdge(C Circle &circle, C Vec2 &move, C Edge2 &edge, Flt *hit_frac, Vec2 *hit_normal)
  283. {
  284. Byte point_test;
  285. Vec2 edge_dir =edge.p[1]-edge.p[0];
  286. Vec2 edge_normal=PerpN(edge_dir);
  287. if(!Dot(move, edge_normal))point_test=(Dot(edge_dir, move)<0);else
  288. {
  289. Vec2 point=circle.pos - edge_normal*circle.r;
  290. if(SweepPointPlane(point, move, Plane2(edge.p[0], edge_normal), hit_frac, hit_normal, &point))
  291. {
  292. if(DistPointPlane(point, edge.p[0], edge_dir)<0)point_test=0;else
  293. if(DistPointPlane(point, edge.p[1], edge_dir)>0)point_test=1;else
  294. return true;
  295. }else point_test=Closer(circle.pos, edge.p[0], edge.p[1]);
  296. }
  297. return SweepCirclePoint(circle, move, edge.p[point_test], hit_frac, hit_normal);
  298. }
  299. Bool SweepCircleEdge(C CircleD &circle, C VecD2 &move, C EdgeD2 &edge, Dbl *hit_frac, VecD2 *hit_normal)
  300. {
  301. Byte point_test;
  302. VecD2 edge_dir =edge.p[1]-edge.p[0];
  303. VecD2 edge_normal=PerpN(edge_dir);
  304. if(!Dot(move, edge_normal))point_test=(Dot(edge_dir, move)<0);else
  305. {
  306. VecD2 point=circle.pos - edge_normal*circle.r;
  307. if(SweepPointPlane(point, move, PlaneD2(edge.p[0], edge_normal), hit_frac, hit_normal, &point))
  308. {
  309. if(DistPointPlane(point, edge.p[0], edge_dir)<0)point_test=0;else
  310. if(DistPointPlane(point, edge.p[1], edge_dir)>0)point_test=1;else
  311. return true;
  312. }else point_test=Closer(circle.pos, edge.p[0], edge.p[1]);
  313. }
  314. return SweepCirclePoint(circle, move, edge.p[point_test], hit_frac, hit_normal);
  315. }
  316. /******************************************************************************/
  317. }
  318. /******************************************************************************/