Rect2.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. #include "Rect2.hpp"
  2. #include "Vector2.hpp"
  3. #include "String.hpp"
  4. #include <cmath>
  5. #include "Transform2D.hpp"
  6. namespace godot {
  7. #ifndef MAX
  8. #define MAX(a, b) (a > b ? a : b)
  9. #endif
  10. #ifndef MIN
  11. #define MIN(a, b) (a < b ? a : b)
  12. #endif
  13. real_t Rect2::distance_to(const Vector2& p_point) const {
  14. real_t dist = 1e20;
  15. if (p_point.x < pos.x) {
  16. dist=MIN(dist,pos.x-p_point.x);
  17. }
  18. if (p_point.y < pos.y) {
  19. dist=MIN(dist,pos.y-p_point.y);
  20. }
  21. if (p_point.x >= (pos.x+size.x) ) {
  22. dist=MIN(p_point.x-(pos.x+size.x),dist);
  23. }
  24. if (p_point.y >= (pos.y+size.y) ) {
  25. dist=MIN(p_point.y-(pos.y+size.y),dist);
  26. }
  27. if (dist==1e20)
  28. return 0;
  29. else
  30. return dist;
  31. }
  32. Rect2 Rect2::clip(const Rect2& p_rect) const { /// return a clipped rect
  33. Rect2 new_rect=p_rect;
  34. if (!intersects( new_rect ))
  35. return Rect2();
  36. new_rect.pos.x = MAX( p_rect.pos.x , pos.x );
  37. new_rect.pos.y = MAX( p_rect.pos.y , pos.y );
  38. Point2 p_rect_end=p_rect.pos+p_rect.size;
  39. Point2 end=pos+size;
  40. new_rect.size.x=MIN(p_rect_end.x,end.x) - new_rect.pos.x;
  41. new_rect.size.y=MIN(p_rect_end.y,end.y) - new_rect.pos.y;
  42. return new_rect;
  43. }
  44. Rect2 Rect2::merge(const Rect2& p_rect) const { ///< return a merged rect
  45. Rect2 new_rect;
  46. new_rect.pos.x=MIN( p_rect.pos.x , pos.x );
  47. new_rect.pos.y=MIN( p_rect.pos.y , pos.y );
  48. new_rect.size.x = MAX( p_rect.pos.x+p_rect.size.x , pos.x+size.x );
  49. new_rect.size.y = MAX( p_rect.pos.y+p_rect.size.y , pos.y+size.y );
  50. new_rect.size = new_rect.size - new_rect.pos; //make relative again
  51. return new_rect;
  52. }
  53. Rect2::operator String() const
  54. {
  55. return String(pos)+", "+String(size);
  56. }
  57. bool Rect2::intersects_segment(const Point2& p_from, const Point2& p_to, Point2* r_pos,Point2* r_normal) const {
  58. real_t min=0,max=1;
  59. int axis=0;
  60. real_t sign=0;
  61. for(int i=0;i<2;i++) {
  62. real_t seg_from=p_from[i];
  63. real_t seg_to=p_to[i];
  64. real_t box_begin=pos[i];
  65. real_t box_end=box_begin+size[i];
  66. real_t cmin,cmax;
  67. real_t csign;
  68. if (seg_from < seg_to) {
  69. if (seg_from > box_end || seg_to < box_begin)
  70. return false;
  71. real_t length=seg_to-seg_from;
  72. cmin = (seg_from < box_begin)?((box_begin - seg_from)/length):0;
  73. cmax = (seg_to > box_end)?((box_end - seg_from)/length):1;
  74. csign=-1.0;
  75. } else {
  76. if (seg_to > box_end || seg_from < box_begin)
  77. return false;
  78. real_t length=seg_to-seg_from;
  79. cmin = (seg_from > box_end)?(box_end - seg_from)/length:0;
  80. cmax = (seg_to < box_begin)?(box_begin - seg_from)/length:1;
  81. csign=1.0;
  82. }
  83. if (cmin > min) {
  84. min = cmin;
  85. axis=i;
  86. sign=csign;
  87. }
  88. if (cmax < max)
  89. max = cmax;
  90. if (max < min)
  91. return false;
  92. }
  93. Vector2 rel=p_to-p_from;
  94. if (r_normal) {
  95. Vector2 normal;
  96. normal[axis]=sign;
  97. *r_normal=normal;
  98. }
  99. if (r_pos)
  100. *r_pos=p_from+rel*min;
  101. return true;
  102. }
  103. bool Rect2::intersects_transformed(const Transform2D& p_xform, const Rect2& p_rect) const {
  104. //SAT intersection between local and transformed rect2
  105. Vector2 xf_points[4]={
  106. p_xform.xform(p_rect.pos),
  107. p_xform.xform(Vector2(p_rect.pos.x+p_rect.size.x,p_rect.pos.y)),
  108. p_xform.xform(Vector2(p_rect.pos.x,p_rect.pos.y+p_rect.size.y)),
  109. p_xform.xform(Vector2(p_rect.pos.x+p_rect.size.x,p_rect.pos.y+p_rect.size.y)),
  110. };
  111. real_t low_limit;
  112. //base rect2 first (faster)
  113. if (xf_points[0].y>pos.y)
  114. goto next1;
  115. if (xf_points[1].y>pos.y)
  116. goto next1;
  117. if (xf_points[2].y>pos.y)
  118. goto next1;
  119. if (xf_points[3].y>pos.y)
  120. goto next1;
  121. return false;
  122. next1:
  123. low_limit=pos.y+size.y;
  124. if (xf_points[0].y<low_limit)
  125. goto next2;
  126. if (xf_points[1].y<low_limit)
  127. goto next2;
  128. if (xf_points[2].y<low_limit)
  129. goto next2;
  130. if (xf_points[3].y<low_limit)
  131. goto next2;
  132. return false;
  133. next2:
  134. if (xf_points[0].x>pos.x)
  135. goto next3;
  136. if (xf_points[1].x>pos.x)
  137. goto next3;
  138. if (xf_points[2].x>pos.x)
  139. goto next3;
  140. if (xf_points[3].x>pos.x)
  141. goto next3;
  142. return false;
  143. next3:
  144. low_limit=pos.x+size.x;
  145. if (xf_points[0].x<low_limit)
  146. goto next4;
  147. if (xf_points[1].x<low_limit)
  148. goto next4;
  149. if (xf_points[2].x<low_limit)
  150. goto next4;
  151. if (xf_points[3].x<low_limit)
  152. goto next4;
  153. return false;
  154. next4:
  155. Vector2 xf_points2[4]={
  156. pos,
  157. Vector2(pos.x+size.x,pos.y),
  158. Vector2(pos.x,pos.y+size.y),
  159. Vector2(pos.x+size.x,pos.y+size.y),
  160. };
  161. real_t maxa=p_xform.elements[0].dot(xf_points2[0]);
  162. real_t mina=maxa;
  163. real_t dp = p_xform.elements[0].dot(xf_points2[1]);
  164. maxa=MAX(dp,maxa);
  165. mina=MIN(dp,mina);
  166. dp = p_xform.elements[0].dot(xf_points2[2]);
  167. maxa=MAX(dp,maxa);
  168. mina=MIN(dp,mina);
  169. dp = p_xform.elements[0].dot(xf_points2[3]);
  170. maxa=MAX(dp,maxa);
  171. mina=MIN(dp,mina);
  172. real_t maxb=p_xform.elements[0].dot(xf_points[0]);
  173. real_t minb=maxb;
  174. dp = p_xform.elements[0].dot(xf_points[1]);
  175. maxb=MAX(dp,maxb);
  176. minb=MIN(dp,minb);
  177. dp = p_xform.elements[0].dot(xf_points[2]);
  178. maxb=MAX(dp,maxb);
  179. minb=MIN(dp,minb);
  180. dp = p_xform.elements[0].dot(xf_points[3]);
  181. maxb=MAX(dp,maxb);
  182. minb=MIN(dp,minb);
  183. if ( mina > maxb )
  184. return false;
  185. if ( minb > maxa )
  186. return false;
  187. maxa=p_xform.elements[1].dot(xf_points2[0]);
  188. mina=maxa;
  189. dp = p_xform.elements[1].dot(xf_points2[1]);
  190. maxa=MAX(dp,maxa);
  191. mina=MIN(dp,mina);
  192. dp = p_xform.elements[1].dot(xf_points2[2]);
  193. maxa=MAX(dp,maxa);
  194. mina=MIN(dp,mina);
  195. dp = p_xform.elements[1].dot(xf_points2[3]);
  196. maxa=MAX(dp,maxa);
  197. mina=MIN(dp,mina);
  198. maxb=p_xform.elements[1].dot(xf_points[0]);
  199. minb=maxb;
  200. dp = p_xform.elements[1].dot(xf_points[1]);
  201. maxb=MAX(dp,maxb);
  202. minb=MIN(dp,minb);
  203. dp = p_xform.elements[1].dot(xf_points[2]);
  204. maxb=MAX(dp,maxb);
  205. minb=MIN(dp,minb);
  206. dp = p_xform.elements[1].dot(xf_points[3]);
  207. maxb=MAX(dp,maxb);
  208. minb=MIN(dp,minb);
  209. if ( mina > maxb )
  210. return false;
  211. if ( minb > maxa )
  212. return false;
  213. return true;
  214. }
  215. }