Rectangle.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. /******************************************************************************/
  5. Rect::Rect(C RectI &rect ) {set (rect.min , rect.max );}
  6. Rect::Rect(C RectD &rect ) {set (rect.min , rect.max );}
  7. Rect::Rect(C Box &box ) {set (box .min.xy, box .max.xy);}
  8. Rect::Rect(C Extent &ext ) {set (ext .minX(), ext .minY(), ext.maxX(), ext.maxY());}
  9. Rect::Rect(C Circle &circle) {setC(circle.pos , circle.r );}
  10. Rect::Rect(C Edge2 &edge ) {from(edge.p[0] , edge.p[1] );}
  11. Rect::Rect(C Tri2 &tri ) {MinMax(tri .p, 3, min, max);}
  12. Rect::Rect(C Quad2 &quad ) {MinMax(quad.p, 4, min, max);}
  13. Rect::Rect(C MeshBase &mshb ) {mshb.getRect(T);}
  14. /******************************************************************************/
  15. Rect& Rect::operator&=(C Rect &r)
  16. {
  17. if(r.min.x>min.x)min.x=r.min.x; if(r.max.x<max.x)max.x=r.max.x;
  18. if(r.min.y>min.y)min.y=r.min.y; if(r.max.y<max.y)max.y=r.max.y;
  19. return T;
  20. }
  21. Rect& Rect::operator&=(C RectI &r)
  22. {
  23. if(r.min.x>min.x)min.x=r.min.x; if(r.max.x<max.x)max.x=r.max.x;
  24. if(r.min.y>min.y)min.y=r.min.y; if(r.max.y<max.y)max.y=r.max.y;
  25. return T;
  26. }
  27. RectD& RectD::operator&=(C RectD &r)
  28. {
  29. if(r.min.x>min.x)min.x=r.min.x; if(r.max.x<max.x)max.x=r.max.x;
  30. if(r.min.y>min.y)min.y=r.min.y; if(r.max.y<max.y)max.y=r.max.y;
  31. return T;
  32. }
  33. RectD& RectD::operator&=(C RectI &r)
  34. {
  35. if(r.min.x>min.x)min.x=r.min.x; if(r.max.x<max.x)max.x=r.max.x;
  36. if(r.min.y>min.y)min.y=r.min.y; if(r.max.y<max.y)max.y=r.max.y;
  37. return T;
  38. }
  39. RectI& RectI::operator&=(C RectI &r)
  40. {
  41. if(r.min.x>min.x)min.x=r.min.x; if(r.max.x<max.x)max.x=r.max.x;
  42. if(r.min.y>min.y)min.y=r.min.y; if(r.max.y<max.y)max.y=r.max.y;
  43. return T;
  44. }
  45. /******************************************************************************/
  46. Rect& Rect::extendX( Flt e) {min.x-=e; max.x+=e; return T;}
  47. Rect& Rect::extendY( Flt e) {min.y-=e; max.y+=e; return T;}
  48. Rect& Rect::extend ( Flt e) {min -=e; max +=e; return T;}
  49. Rect& Rect::extend (C Vec2 &v) {min -=v; max +=v; return T;}
  50. RectD& RectD::extendX( Dbl e) {min.x-=e; max.x+=e; return T;}
  51. RectD& RectD::extendY( Dbl e) {min.y-=e; max.y+=e; return T;}
  52. RectD& RectD::extend ( Dbl e) {min -=e; max +=e; return T;}
  53. RectD& RectD::extend (C VecD2 &v) {min -=v; max +=v; return T;}
  54. RectI& RectI::extendX( Int e) {min.x-=e; max.x+=e; return T;}
  55. RectI& RectI::extendY( Int e) {min.y-=e; max.y+=e; return T;}
  56. RectI& RectI::extend ( Int e) {min -=e; max +=e; return T;}
  57. RectI& RectI::extend (C VecI2 &v) {min -=v; max +=v; return T;}
  58. Rect& Rect::extend(Flt x, Flt y)
  59. {
  60. min.x-=x; max.x+=x;
  61. min.y-=y; max.y+=y;
  62. return T;
  63. }
  64. RectD& RectD::extend(Dbl x, Dbl y)
  65. {
  66. min.x-=x; max.x+=x;
  67. min.y-=y; max.y+=y;
  68. return T;
  69. }
  70. RectI& RectI::extend(Int x, Int y)
  71. {
  72. min.x-=x; max.x+=x;
  73. min.y-=y; max.y+=y;
  74. return T;
  75. }
  76. /******************************************************************************/
  77. Rect & Rect ::includeX(Flt x ) {if( x< min.x) min.x=x;else if( x> max.x) max.x=x ; return T;}
  78. RectD& RectD::includeX(Dbl x ) {if( x< min.x) min.x=x;else if( x> max.x) max.x=x ; return T;}
  79. RectI& RectI::includeX(Int x ) {if( x< min.x) min.x=x;else if( x> max.x) max.x=x ; return T;}
  80. Rect & Rect ::includeY(Flt y ) {if( y< min.y) min.y=y;else if( y> max.y) max.y=y ; return T;}
  81. RectD& RectD::includeY(Dbl y ) {if( y< min.y) min.y=y;else if( y> max.y) max.y=y ; return T;}
  82. RectI& RectI::includeY(Int y ) {if( y< min.y) min.y=y;else if( y> max.y) max.y=y ; return T;}
  83. Rect & Rect ::includeX(Flt min, Flt max) {if(min<T.min.x)T.min.x=min; if(max>T.max.x)T.max.x=max; return T;}
  84. RectD& RectD::includeX(Dbl min, Dbl max) {if(min<T.min.x)T.min.x=min; if(max>T.max.x)T.max.x=max; return T;}
  85. RectI& RectI::includeX(Int min, Int max) {if(min<T.min.x)T.min.x=min; if(max>T.max.x)T.max.x=max; return T;}
  86. Rect & Rect ::includeY(Flt min, Flt max) {if(min<T.min.y)T.min.y=min; if(max>T.max.y)T.max.y=max; return T;}
  87. RectD& RectD::includeY(Dbl min, Dbl max) {if(min<T.min.y)T.min.y=min; if(max>T.max.y)T.max.y=max; return T;}
  88. RectI& RectI::includeY(Int min, Int max) {if(min<T.min.y)T.min.y=min; if(max>T.max.y)T.max.y=max; return T;}
  89. Rect& Rect::include(C Vec2 &v)
  90. {
  91. Flt x=v.x, y=v.y;
  92. if(x<min.x)min.x=x;else if(x>max.x)max.x=x;
  93. if(y<min.y)min.y=y;else if(y>max.y)max.y=y;
  94. return T;
  95. }
  96. RectD& RectD::include(C VecD2 &v)
  97. {
  98. Dbl x=v.x, y=v.y;
  99. if(x<min.x)min.x=x;else if(x>max.x)max.x=x;
  100. if(y<min.y)min.y=y;else if(y>max.y)max.y=y;
  101. return T;
  102. }
  103. RectI& RectI::include(C VecI2 &v)
  104. {
  105. Int x=v.x, y=v.y;
  106. if(x<min.x)min.x=x;else if(x>max.x)max.x=x;
  107. if(y<min.y)min.y=y;else if(y>max.y)max.y=y;
  108. return T;
  109. }
  110. Rect& Rect::include(C Rect &r)
  111. {
  112. if(r.min.x<min.x)min.x=r.min.x; if(r.max.x>max.x)max.x=r.max.x;
  113. if(r.min.y<min.y)min.y=r.min.y; if(r.max.y>max.y)max.y=r.max.y;
  114. return T;
  115. }
  116. RectD& RectD::include(C RectD &r)
  117. {
  118. if(r.min.x<min.x)min.x=r.min.x; if(r.max.x>max.x)max.x=r.max.x;
  119. if(r.min.y<min.y)min.y=r.min.y; if(r.max.y>max.y)max.y=r.max.y;
  120. return T;
  121. }
  122. RectI& RectI::include(C RectI &r)
  123. {
  124. if(r.min.x<min.x)min.x=r.min.x; if(r.max.x>max.x)max.x=r.max.x;
  125. if(r.min.y<min.y)min.y=r.min.y; if(r.max.y>max.y)max.y=r.max.y;
  126. return T;
  127. }
  128. /******************************************************************************/
  129. Rect& Rect::moveX(Flt dx) {min.x+=dx; max.x+=dx; return T;}
  130. Rect& Rect::moveY(Flt dy) {min.y+=dy; max.y+=dy; return T;}
  131. RectD& RectD::moveX(Dbl dx) {min.x+=dx; max.x+=dx; return T;}
  132. RectD& RectD::moveY(Dbl dy) {min.y+=dy; max.y+=dy; return T;}
  133. /******************************************************************************/
  134. Rect& Rect::swapX() {Swap(min.x, max.x); return T;}
  135. Rect& Rect::swapY() {Swap(min.y, max.y); return T;}
  136. RectD& RectD::swapX() {Swap(min.x, max.x); return T;}
  137. RectD& RectD::swapY() {Swap(min.y, max.y); return T;}
  138. /******************************************************************************/
  139. Rect& Rect::from(C Vec2 &a, C Vec2 &b)
  140. {
  141. MinMax(a.x, b.x, min.x, max.x);
  142. MinMax(a.y, b.y, min.y, max.y);
  143. return T;
  144. }
  145. RectD& RectD::from(C VecD2 &a, C VecD2 &b)
  146. {
  147. MinMax(a.x, b.x, min.x, max.x);
  148. MinMax(a.y, b.y, min.y, max.y);
  149. return T;
  150. }
  151. RectI& RectI::from(C VecI2 &a, C VecI2 &b)
  152. {
  153. MinMax(a.x, b.x, min.x, max.x);
  154. MinMax(a.y, b.y, min.y, max.y);
  155. return T;
  156. }
  157. /******************************************************************************/
  158. Rect& Rect::rotatePI_2(Int rotations)
  159. {
  160. switch(rotations&3)
  161. {
  162. case 1: set(-max.y, min.x, -min.y, max.x); break;
  163. case 2: set(-max.x, -max.y, -min.x, -min.y); break;
  164. case 3: set( min.y, -max.x, max.y, -min.x); break;
  165. }
  166. return T;
  167. }
  168. RectD& RectD::rotatePI_2(Int rotations)
  169. {
  170. switch(rotations&3)
  171. {
  172. case 1: set(-max.y, min.x, -min.y, max.x); break;
  173. case 2: set(-max.x, -max.y, -min.x, -min.y); break;
  174. case 3: set( min.y, -max.x, max.y, -min.x); break;
  175. }
  176. return T;
  177. }
  178. RectI& RectI::rotatePI_2(Int rotations)
  179. {
  180. switch(rotations&3)
  181. {
  182. case 1: set(-max.y, min.x, -min.y, max.x); break;
  183. case 2: set(-max.x, -max.y, -min.x, -min.y); break;
  184. case 3: set( min.y, -max.x, max.y, -min.x); break;
  185. }
  186. return T;
  187. }
  188. /******************************************************************************/
  189. void Rect::draw(C Color &color, Bool fill)C
  190. {
  191. VI.color (color);
  192. VI.setType(VI_2D_FLAT, fill ? VI_STRIP : VI_LINE|VI_STRIP);
  193. if(Vtx2DFlat *v=(Vtx2DFlat*)VI.addVtx(fill ? 4 : 5))
  194. {
  195. if(fill)
  196. {
  197. v[0].pos.set(min.x, max.y);
  198. v[1].pos.set(max.x, max.y);
  199. v[2].pos.set(min.x, min.y);
  200. v[3].pos.set(max.x, min.y);
  201. }else
  202. {
  203. // drawing lines needs adjustments
  204. Rect r(min.x+D._pixel_size_2.x, min.y+D._pixel_size_2.y,
  205. max.x-D._pixel_size_2.x, max.y-D._pixel_size_2.y);
  206. v[0].pos.set(r.min.x, r.min.y);
  207. v[1].pos.set(r.min.x, r.max.y);
  208. v[2].pos.set(r.max.x, r.max.y);
  209. v[3].pos.set(r.max.x, r.min.y);
  210. v[4].pos.set(r.min.x, r.min.y);
  211. }
  212. }
  213. VI.end();
  214. }
  215. void Rect::drawBorder(C Color &color, Flt border)C
  216. {
  217. VI.color (color);
  218. VI.setType(VI_2D_FLAT);
  219. if(Vtx2DFlat *v=(Vtx2DFlat*)VI.addVtx(8))
  220. {
  221. Flt x0=min.x, y0=min.y, x1=x0+border, y1=y0+border,
  222. x3=max.x, y3=max.y, x2=x3-border, y2=y3-border;
  223. v[0].pos.set(x0, y0);
  224. v[1].pos.set(x0, y3);
  225. v[2].pos.set(x3, y3);
  226. v[3].pos.set(x3, y0);
  227. v[4].pos.set(x1, y1);
  228. v[5].pos.set(x1, y2);
  229. v[6].pos.set(x2, y2);
  230. v[7].pos.set(x2, y1);
  231. VI.flushIndexed(IndBufRectBorder, 4*2*3);
  232. }
  233. VI.clear();
  234. }
  235. void Rect::drawBorder(C Color &color, C Vec2 &border)C
  236. {
  237. VI.color (color);
  238. VI.setType(VI_2D_FLAT);
  239. if(Vtx2DFlat *v=(Vtx2DFlat*)VI.addVtx(8))
  240. {
  241. Flt x0=min.x, y0=min.y, x1=x0+border.x, y1=y0+border.y,
  242. x3=max.x, y3=max.y, x2=x3-border.x, y2=y3-border.y;
  243. v[0].pos.set(x0, y0);
  244. v[1].pos.set(x0, y3);
  245. v[2].pos.set(x3, y3);
  246. v[3].pos.set(x3, y0);
  247. v[4].pos.set(x1, y1);
  248. v[5].pos.set(x1, y2);
  249. v[6].pos.set(x2, y2);
  250. v[7].pos.set(x2, y1);
  251. VI.flushIndexed(IndBufRectBorder, 4*2*3);
  252. }
  253. VI.clear();
  254. }
  255. void Rect::drawShadedX(C Color &c0, C Color &c1)C
  256. {
  257. VI.setType(VI_2D_COL, VI_STRIP);
  258. if(Vtx2DCol *v=(Vtx2DCol*)VI.addVtx(4))
  259. {
  260. v[0].pos.set(min.x, max.y);
  261. v[1].pos.set(max.x, max.y);
  262. v[2].pos.set(min.x, min.y);
  263. v[3].pos.set(max.x, min.y);
  264. v[0].color=v[2].color=c0;
  265. v[1].color=v[3].color=c1;
  266. }
  267. VI.end();
  268. }
  269. void Rect::drawShadedY(C Color &c0, C Color &c1)C
  270. {
  271. VI.setType(VI_2D_COL, VI_STRIP);
  272. if(Vtx2DCol *v=(Vtx2DCol*)VI.addVtx(4))
  273. {
  274. v[0].pos.set(min.x, max.y);
  275. v[1].pos.set(max.x, max.y);
  276. v[2].pos.set(min.x, min.y);
  277. v[3].pos.set(max.x, min.y);
  278. v[0].color=v[1].color=c0;
  279. v[2].color=v[3].color=c1;
  280. }
  281. VI.end();
  282. }
  283. void Rect::drawShaded(C Color &c0, C Color &c1, Flt border)C
  284. {
  285. VI.setType(VI_2D_COL);
  286. if(Vtx2DCol *v=(Vtx2DCol*)VI.addVtx(8))
  287. {
  288. Flt x0=min.x, y0=min.y, x1=x0+border, y1=y0+border,
  289. x3=max.x, y3=max.y, x2=x3-border, y2=y3-border;
  290. v[0].pos.set(x0, y0);
  291. v[1].pos.set(x0, y3);
  292. v[2].pos.set(x3, y3);
  293. v[3].pos.set(x3, y0);
  294. v[4].pos.set(x1, y1);
  295. v[5].pos.set(x1, y2);
  296. v[6].pos.set(x2, y2);
  297. v[7].pos.set(x2, y1);
  298. v[5].color=v[6].color=v[4].color=v[7].color=c0;
  299. v[0].color=v[1].color=v[2].color=v[3].color=c1;
  300. VI.flushIndexed(IndBufRectShaded, 5*2*3);
  301. }
  302. VI.clear();
  303. }
  304. void Rect::drawBorderShaded(C Color &c0, C Color &c1, C Rect &border)C
  305. {
  306. VI.setType(VI_2D_COL);
  307. if(Vtx2DCol *v=(Vtx2DCol*)VI.addVtx(8))
  308. {
  309. Flt x0=min.x, y0=min.y, x1=x0+border.min.x, y1=y0+border.min.y,
  310. x3=max.x, y3=max.y, x2=x3-border.max.x, y2=y3-border.max.y;
  311. v[0].pos.set(x0, y0);
  312. v[1].pos.set(x0, y3);
  313. v[2].pos.set(x3, y3);
  314. v[3].pos.set(x3, y0);
  315. v[4].pos.set(x1, y1);
  316. v[5].pos.set(x1, y2);
  317. v[6].pos.set(x2, y2);
  318. v[7].pos.set(x2, y1);
  319. v[5].color=v[6].color=v[4].color=v[7].color=c0;
  320. v[0].color=v[1].color=v[2].color=v[3].color=c1;
  321. VI.flushIndexed(IndBufRectBorder, 4*2*3);
  322. }
  323. VI.clear();
  324. }
  325. /******************************************************************************/
  326. void Rects::set(C Rect &rect, C VecI2 &cells)
  327. {
  328. T.rect =rect;
  329. T.cells.x=Max(cells.x, 1);
  330. T.cells.y=Max(cells.y, 1);
  331. T.size =rect.size()/T.cells;
  332. }
  333. void Rects::set(C Rect &rect, Int elms)
  334. {
  335. VecI2 cells;
  336. Vec2 size=rect.size();
  337. Flt area=size.mul(),
  338. mul =Sqrt(elms/area); // = 1/avg_cell_size
  339. if(size.x<size.y)
  340. {
  341. cells.x=Max(1, Round(size.x*mul));
  342. cells.y=Max(1, DivRound(elms, cells.x));
  343. }else
  344. {
  345. cells.y=Max(1, Round(size.y*mul));
  346. cells.x=Max(1, DivRound(elms, cells.y));
  347. }
  348. set(rect, cells);
  349. }
  350. VecI2 Rects::coords(C Vec2 &pos)C
  351. {
  352. VecI2 O=Trunc((pos-rect.min)/size); // use 'Trunc' because it's faster and we're not interested in negative indexes
  353. Clamp(O.x, 0, cells.x-1);
  354. Clamp(O.y, 0, cells.y-1);
  355. return O;
  356. }
  357. RectI Rects::coords(C Rect &rect)C
  358. {
  359. return RectI(coords(rect.min),
  360. coords(rect.max));
  361. }
  362. Rect Rects::getRect(C VecI2 &cell)C
  363. {
  364. Rect O;
  365. O.min=T.rect.min+size*cell;
  366. O.max= O.min+size;
  367. return O;
  368. }
  369. void Rects::draw(C Color &grid_color, C Color &back_color)C
  370. {
  371. if(back_color.a)rect.draw(back_color, true);
  372. if(grid_color.a)
  373. {
  374. VI.color(grid_color);
  375. REP(cells.x+1)
  376. {
  377. Flt x=rect.min.x+i*size.x;
  378. VI.line(Vec2(x, rect.min.y), Vec2(x, rect.max.y));
  379. }
  380. REP(cells.y+1)
  381. {
  382. Flt y=rect.min.y+i*size.y;
  383. VI.line(Vec2(rect.min.x, y), Vec2(rect.max.x, y));
  384. }
  385. VI.end();
  386. }
  387. }
  388. void Rects::draw(C Color &grid_color, C Color &field_color, Index *rect_edge)C
  389. {
  390. if(field_color.a && rect_edge)
  391. {
  392. VI.color(field_color);
  393. FREPD(y, cells.y)
  394. FREPD(x, cells.x)if(rect_edge->group[x+y*cells.x].num)VI.rect(getRect(VecI2(x, y)));
  395. VI.end();
  396. }
  397. draw(grid_color);
  398. }
  399. /******************************************************************************/
  400. Flt Dist(C Vec2 &point, C Rect &rect)
  401. {
  402. if(point.x>rect.max.x) // right
  403. {
  404. if(point.y<rect.min.y)return Dist(point, rect.rd()); // rd corner
  405. if(point.y>rect.max.y)return Dist(point, rect.max ); // ru corner
  406. return point.x-rect.max.x; // r side
  407. }
  408. if(point.x<rect.min.x) // left
  409. {
  410. if(point.y>rect.max.y)return Dist(point, rect.lu()); // lu corner
  411. if(point.y<rect.min.y)return Dist(point, rect.min ); // ld corner
  412. return rect.min.x-point.x; // l side
  413. }
  414. if(point.y>rect.max.y)return point.y-rect.max.y; // u side
  415. if(point.y<rect.min.y)return rect.min.y-point.y; // d side
  416. return 0;
  417. }
  418. Flt Dist(C Vec2 &point, C RectI &rect)
  419. {
  420. if(point.x>rect.max.x) // right
  421. {
  422. if(point.y<rect.min.y)return Dist(point, rect.rd()); // rd corner
  423. if(point.y>rect.max.y)return Dist(point, rect.max ); // ru corner
  424. return point.x-rect.max.x; // r side
  425. }
  426. if(point.x<rect.min.x) // left
  427. {
  428. if(point.y>rect.max.y)return Dist(point, rect.lu()); // lu corner
  429. if(point.y<rect.min.y)return Dist(point, rect.min ); // ld corner
  430. return rect.min.x-point.x; // l side
  431. }
  432. if(point.y>rect.max.y)return point.y-rect.max.y; // u side
  433. if(point.y<rect.min.y)return rect.min.y-point.y; // d side
  434. return 0;
  435. }
  436. Flt Dist2(C Vec2 &point, C Rect &rect)
  437. {
  438. if(point.x>rect.max.x) // right
  439. {
  440. if(point.y<rect.min.y)return Dist2(point, rect.rd()); // rd corner
  441. if(point.y>rect.max.y)return Dist2(point, rect.max ); // ru corner
  442. return Sqr(point.x-rect.max.x); // r side
  443. }
  444. if(point.x<rect.min.x) // left
  445. {
  446. if(point.y>rect.max.y)return Dist2(point, rect.lu()); // lu corner
  447. if(point.y<rect.min.y)return Dist2(point, rect.min ); // ld corner
  448. return Sqr(rect.min.x-point.x); // l side
  449. }
  450. if(point.y>rect.max.y)return Sqr(point.y-rect.max.y); // u side
  451. if(point.y<rect.min.y)return Sqr(rect.min.y-point.y); // d side
  452. return 0;
  453. }
  454. Flt Dist2(C Vec2 &point, C RectI &rect)
  455. {
  456. if(point.x>rect.max.x) // right
  457. {
  458. if(point.y<rect.min.y)return Dist2(point, rect.rd()); // rd corner
  459. if(point.y>rect.max.y)return Dist2(point, rect.max ); // ru corner
  460. return Sqr(point.x-rect.max.x); // r side
  461. }
  462. if(point.x<rect.min.x) // left
  463. {
  464. if(point.y>rect.max.y)return Dist2(point, rect.lu()); // lu corner
  465. if(point.y<rect.min.y)return Dist2(point, rect.min ); // ld corner
  466. return Sqr(rect.min.x-point.x); // l side
  467. }
  468. if(point.y>rect.max.y)return Sqr(point.y-rect.max.y); // u side
  469. if(point.y<rect.min.y)return Sqr(rect.min.y-point.y); // d side
  470. return 0;
  471. }
  472. Flt Dist(C Rect &a, C Rect &b)
  473. {
  474. return Dist(Max(0, Abs(a.centerX()-b.centerX())-(a.w()+b.w())*0.5f),
  475. Max(0, Abs(a.centerY()-b.centerY())-(a.h()+b.h())*0.5f));
  476. }
  477. /******************************************************************************/
  478. Flt Dist2PointSquare(C Vec2 &pos, C Vec2 &square_center, Flt square_radius)
  479. {
  480. return Sqr(Max(Abs(pos.x-square_center.x)-square_radius, 0))
  481. +Sqr(Max(Abs(pos.y-square_center.y)-square_radius, 0));
  482. }
  483. Flt Dist2PointSquare(C Vec2 &pos, C VecI2 &square_center, Flt square_radius)
  484. {
  485. return Sqr(Max(Abs(pos.x-square_center.x)-square_radius, 0))
  486. +Sqr(Max(Abs(pos.y-square_center.y)-square_radius, 0));
  487. }
  488. /******************************************************************************/
  489. Bool Cuts(C Rect &a, C Rect &b)
  490. {
  491. return b.max.x>=a.min.x && b.min.x<=a.max.x
  492. && b.max.y>=a.min.y && b.min.y<=a.max.y;
  493. }
  494. Bool Cuts(C RectI &a, C RectI &b)
  495. {
  496. return b.max.x>=a.min.x && b.min.x<=a.max.x
  497. && b.max.y>=a.min.y && b.min.y<=a.max.y;
  498. }
  499. Bool Cuts(C Edge2 &edge, C Rect &rect)
  500. {
  501. if(Cuts(edge.p[0], rect)
  502. || Cuts(edge.p[1], rect))return true;
  503. if(edge.p[0].x<rect.min.x && edge.p[1].x>=rect.min.x){if(rect.includesY(PointOnPlane(edge.p[0].y, edge.p[1].y, edge.p[0].x-rect.min.x, edge.p[1].x-rect.min.x)))return true;}else
  504. if(edge.p[0].x>rect.max.x && edge.p[1].x<=rect.max.x){if(rect.includesY(PointOnPlane(edge.p[0].y, edge.p[1].y, edge.p[0].x-rect.max.x, edge.p[1].x-rect.max.x)))return true;}
  505. if(edge.p[0].y<rect.min.y && edge.p[1].y>=rect.min.y){if(rect.includesX(PointOnPlane(edge.p[0].x, edge.p[1].x, edge.p[0].y-rect.min.y, edge.p[1].y-rect.min.y)))return true;}else
  506. if(edge.p[0].y>rect.max.y && edge.p[1].y<=rect.max.y){if(rect.includesX(PointOnPlane(edge.p[0].x, edge.p[1].x, edge.p[0].y-rect.max.y, edge.p[1].y-rect.max.y)))return true;}
  507. return false;
  508. }
  509. Bool CutsEps(C Vec2 &point, C Rect &rect)
  510. {
  511. return point.x>=rect.min.x-EPS && point.x<=rect.max.x+EPS
  512. && point.y>=rect.min.y-EPS && point.y<=rect.max.y+EPS;
  513. }
  514. /******************************************************************************/
  515. Bool Inside(C Rect &a, C Rect &b)
  516. {
  517. return a.min.x>=b.min.x && a.max.x<=b.max.x
  518. && a.min.y>=b.min.y && a.max.y<=b.max.y;
  519. }
  520. Bool Inside(C RectI &a, C RectI &b)
  521. {
  522. return a.min.x>=b.min.x && a.max.x<=b.max.x
  523. && a.min.y>=b.min.y && a.max.y<=b.max.y;
  524. }
  525. Bool InsideEps(C Rect &a, C Rect &b)
  526. {
  527. return a.min.x>=b.min.x-EPS && a.max.x<=b.max.x+EPS
  528. && a.min.y>=b.min.y-EPS && a.max.y<=b.max.y+EPS;
  529. }
  530. /******************************************************************************/
  531. Rect Fit(Flt src_aspect, C Rect &dest_rect, FIT_MODE fit)
  532. {
  533. Rect r=dest_rect; Bool mx=(r.min.x>r.max.x); if(mx)Swap(r.min.x, r.max.x); Flt w=r.w();
  534. Bool my=(r.min.y>r.max.y); if(my)Swap(r.min.y, r.max.y); Flt h=r.h(), dest_aspect=w/h;
  535. if(fit==FIT_FULL)fit=((src_aspect>dest_aspect) ? FIT_WIDTH : FIT_HEIGHT);else
  536. if(fit==FIT_FILL)fit=((src_aspect<dest_aspect) ? FIT_WIDTH : FIT_HEIGHT);
  537. if(fit==FIT_WIDTH){Flt size=w/src_aspect, d=(size-h)*0.5f; r.extendY(d);}
  538. else {Flt size=h*src_aspect, d=(size-w)*0.5f; r.extendX(d);}
  539. if(mx)Swap(r.min.x, r.max.x);
  540. if(my)Swap(r.min.y, r.max.y);
  541. return r;
  542. }
  543. /******************************************************************************/
  544. Bool SweepPointRect(C Vec2 &point, C Vec2 &move, C Rect &rect, Flt *hit_frac, Vec2 *hit_normal, Vec2 *hit_pos)
  545. {
  546. if(Cuts(point, rect)){if(hit_frac)*hit_frac=0; if(hit_normal)hit_normal->zero(); if(hit_pos)*hit_pos=point; return true;}
  547. Flt frac;
  548. Vec2 test;
  549. if(point.x<rect.min.x && point.x+move.x>=rect.min.x){frac=(rect.min.x-point.x)/move.x; test.set(rect.min.x, point.y+move.y*frac); if(rect.includesY(test.y)){if(hit_frac)*hit_frac=frac; if(hit_normal)hit_normal->set(-1, 0); if(hit_pos)*hit_pos=test; return true;}}else
  550. if(point.x>rect.max.x && point.x+move.x<=rect.max.x){frac=(rect.max.x-point.x)/move.x; test.set(rect.max.x, point.y+move.y*frac); if(rect.includesY(test.y)){if(hit_frac)*hit_frac=frac; if(hit_normal)hit_normal->set( 1, 0); if(hit_pos)*hit_pos=test; return true;}}
  551. if(point.y<rect.min.y && point.y+move.y>=rect.min.y){frac=(rect.min.y-point.y)/move.y; test.set(point.x+move.x*frac, rect.min.y); if(rect.includesX(test.x)){if(hit_frac)*hit_frac=frac; if(hit_normal)hit_normal->set(0, -1); if(hit_pos)*hit_pos=test; return true;}}else
  552. if(point.y>rect.max.y && point.y+move.y<=rect.max.y){frac=(rect.max.y-point.y)/move.y; test.set(point.x+move.x*frac, rect.max.y); if(rect.includesX(test.x)){if(hit_frac)*hit_frac=frac; if(hit_normal)hit_normal->set(0, 1); if(hit_pos)*hit_pos=test; return true;}}
  553. return false;
  554. }
  555. /******************************************************************************/
  556. namespace RP
  557. {
  558. #include "Rect Packer/Rect.cpp"
  559. #include "Rect Packer/ShelfBinPack.cpp"
  560. #include "Rect Packer/MaxRectsBinPack.cpp"
  561. #include "Rect Packer/GuillotineBinPack.cpp"
  562. //#include "Rect Packer/SkylineBinPack.cpp"
  563. }
  564. /******************************************************************************/
  565. Bool PackRectsKnownLimit(C MemPtr<RectSizeAnchor> &sizes, MemPtr<RectI> rects, C VecI2 &limit, Bool allow_rotate, Int border, Bool align_for_compression, Bool compact_arrangement)
  566. {
  567. MAX(border, 0); if(align_for_compression)border+=3; // when using 'align_for_compression' we need to have at least 3 extra pixels to align the target
  568. Memc<RP::RectSizeIndex> rp_src;
  569. Memc<RP::RectIndex > rp_dest;
  570. rects.setNum(sizes.elms());
  571. if(!compact_arrangement)
  572. { // try "shelf" first, because it's fastest
  573. RP::ShelfBinPack pack(limit.x, limit.y, false, allow_rotate);
  574. FREPA(sizes)
  575. {
  576. C RectSizeAnchor &rsa=sizes[i];
  577. if(rsa.size.x>0 && rsa.size.y>0)
  578. {
  579. RP::Rect rect=pack.Insert(rsa.size.x+border, rsa.size.y+border, RP::ShelfBinPack::ShelfNextFit); if(!rect.width)goto max_rects;
  580. Bool flipped=((rect.width>rect.height)!=(rsa.size.x>rsa.size.y));
  581. if(align_for_compression)
  582. {
  583. VecI2 anchor=rsa.anchor; anchor.x+=rect.x; anchor.y+=rect.y; // final anchor position
  584. rect.x+=Ceil4(anchor.x)-anchor.x; rect.y+=Ceil4(anchor.y)-anchor.y; // offset rectangle so the anchor is 4-pixel aligned
  585. }
  586. rects[i].setLD(rect.x, rect.y, rsa.size.c[flipped], rsa.size.c[!flipped]);
  587. }else
  588. if(!rsa.size.x && !rsa.size.y)rects[i].zero();else return false;
  589. }
  590. return true;
  591. }
  592. max_rects:
  593. { // try "max rects" next, because it has best occupancy rate
  594. RP::MaxRectsBinPack pack(limit.x, limit.y, allow_rotate);
  595. rp_src.setNum(sizes.elms()); REPA(rp_src)
  596. {
  597. C RectSizeAnchor &rsa=sizes[i];
  598. if(rsa.size.x>0 && rsa.size.y>0)
  599. {
  600. RP::RectSizeIndex &rp_s=rp_src[i];
  601. rp_s.width =rsa.size.x+border;
  602. rp_s.height=rsa.size.y+border;
  603. rp_s.index =i;
  604. }else
  605. if(!rsa.size.x && !rsa.size.y){rects[i].zero(); rp_src.remove(i);}else return false;
  606. }
  607. pack.Insert(rp_src, rp_dest, RP::MaxRectsBinPack::RectBestShortSideFit);
  608. if(!rp_src.elms()) // all were processed
  609. {
  610. REPA(rp_dest)
  611. {
  612. RP::RectIndex &rect=rp_dest[i];
  613. RectI &dest=rects [rect.index];
  614. C RectSizeAnchor &rsa=sizes [rect.index];
  615. Bool flipped=((rect.width>rect.height)!=(rsa.size.x>rsa.size.y));
  616. if(align_for_compression)
  617. {
  618. VecI2 anchor=rsa.anchor; anchor.x+=rect.x; anchor.y+=rect.y; // final anchor position
  619. rect.x+=Ceil4(anchor.x)-anchor.x; rect.y+=Ceil4(anchor.y)-anchor.y; // offset rectangle so the anchor is 4-pixel aligned
  620. }
  621. dest.setLD(rect.x, rect.y, rsa.size.c[flipped], rsa.size.c[!flipped]);
  622. }
  623. return true;
  624. }
  625. }
  626. return false;
  627. }
  628. /******************************************************************************/
  629. Bool PackRectsUnknownLimit(C MemPtr<RectSizeAnchor> &sizes, MemPtr<RectI> rects, VecI2 &limit, Bool allow_rotate, Int border, Bool align_for_compression, Bool compact_arrangement, Bool only_square, Int max_size)
  630. {
  631. ULong area=0; REPA(sizes)
  632. {
  633. C RectSizeAnchor &rsa=sizes[i];
  634. area+=ULong(rsa.size.x)*ULong(rsa.size.y);
  635. }
  636. for(Int dim =FloorPow2(SqrtI(area)); dim <=max_size; dim <<=1)
  637. for(Int aspect=(only_square ? 4 : 0) ; aspect< 5; aspect++)
  638. {
  639. limit=dim; switch(aspect)
  640. {
  641. case 0: limit.x>>=2; break; // at 1st attempt try making (limit/4, limit ), as textures should preferrably be taller than wider
  642. case 1: limit.y>>=2; break; // at 2nd attempt try making (limit , limit/4)
  643. case 2: limit.x>>=1; break; // at 3rd attempt try making (limit/2, limit ), as textures should preferrably be taller than wider
  644. case 3: limit.y>>=1; break; // at 4th attempt try making (limit , limit/2)
  645. // at 5th attempt try making (limit , limit )
  646. }
  647. if(PackRectsKnownLimit(sizes, rects, limit, allow_rotate, border, align_for_compression, compact_arrangement))return true;
  648. }
  649. return false;
  650. }
  651. /******************************************************************************/
  652. Bool PackRectsMultiLimit(C MemPtr<RectSizeAnchor> &sizes, MemPtr<RectIndex> rects, MemPtr<VecI2> limits, Bool allow_rotate, Int border, Bool align_for_compression, Bool compact_arrangement, Bool only_square, Int max_size)
  653. {
  654. MAX(border, 0); if(align_for_compression)border+=3; // when using 'align_for_compression' we need to have at least 3 extra pixels to align the target
  655. rects .setNum(sizes.elms());
  656. limits.clear();
  657. Memc<RP::RectSizeIndex> left_best, left, left_all;
  658. Memc<RectIndex> placed_best, placed;
  659. Memc<RP::RectIndex> placed_rp;
  660. left_all.setNum(sizes.elms()); REPA(left_all)
  661. {
  662. C RectSizeAnchor &rsa=sizes[i];
  663. if(rsa.size.x>0 && rsa.size.y>0)
  664. {
  665. RP::RectSizeIndex &l=left_all[i];
  666. l.width =rsa.size.x+border;
  667. l.height=rsa.size.y+border;
  668. l.index =i;
  669. }else
  670. if(!rsa.size.x && !rsa.size.y){RectIndex &r=rects[i]; r.zero(); r.index=0; left_all.remove(i);}else return false;
  671. }
  672. RP::ShelfBinPack shelf;
  673. RP::MaxRectsBinPack max_rects;
  674. for(; left_all.elms(); )
  675. {
  676. left_best.clear();
  677. placed_best.clear();
  678. ULong area_best=0, area=0; REPA(left_all){C RP::RectSizeIndex &l=left_all[i]; area+=ULong(l.width)*ULong(l.height);}
  679. VecI2 limit_best=0;
  680. for(Int dim =Min(FloorPow2(SqrtI(area)), max_size); dim <=max_size; dim <<=1)
  681. for(Int aspect=(only_square ? 2 : 0) ; aspect< 3; aspect++)
  682. {
  683. VecI2 limit=dim; switch(aspect)
  684. {
  685. case 0: limit.x>>=1; break; // at 1st attempt try making (limit/2, limit ), as textures should preferrably be taller than wider
  686. case 1: limit.y>>=1; break; // at 2nd attempt try making (limit , limit/2), in case this fits the parts but above method doesn't
  687. // at 3rd attempt try making (limit , limit )
  688. }
  689. if(!compact_arrangement)
  690. {
  691. // try "shelf"
  692. left=left_all;
  693. placed.clear();
  694. shelf.Init(limit.x, limit.y, false, allow_rotate);
  695. REPA(left)
  696. {
  697. C RP::RectSizeIndex &l=left[i];
  698. RP::Rect rect=shelf.Insert(l.width, l.height, RP::ShelfBinPack::ShelfNextFit);
  699. if(rect.width) // it fits
  700. {
  701. C RectSizeAnchor &rsa =sizes[l.index];
  702. RectIndex &dest=placed.New();
  703. Bool flipped=((rect.width>rect.height)!=(rsa.size.x>rsa.size.y));
  704. if(align_for_compression)
  705. {
  706. VecI2 anchor=rsa.anchor; anchor.x+=rect.x; anchor.y+=rect.y; // final anchor position
  707. rect.x+=Ceil4(anchor.x)-anchor.x; rect.y+=Ceil4(anchor.y)-anchor.y; // offset rectangle so the anchor is 4-pixel aligned
  708. }
  709. dest.index=l.index; // this should be index in 'limits' but for now we're using it as 'sizes' index
  710. dest.setLD(rect.x, rect.y, rsa.size.c[flipped], rsa.size.c[!flipped]);
  711. left.remove(i);
  712. }
  713. }
  714. if(!left.elms()){limit_best=limit; left_all.clear(); Swap(placed, placed_best); goto done;} // finished
  715. area=0; REPA(placed){C RectIndex &r=placed[i]; area+=ULong(r.w())*ULong(r.h());} // check if it's best (covers most area)
  716. if(area>area_best)
  717. {
  718. area_best=area;
  719. limit_best=limit;
  720. Swap(left , left_best);
  721. Swap(placed, placed_best);
  722. }
  723. }
  724. // try "max_rects"
  725. {
  726. left=left_all;
  727. placed .clear();
  728. placed_rp.clear();
  729. max_rects.Init (limit.x, limit.y, allow_rotate);
  730. max_rects.Insert(left, placed_rp, RP::MaxRectsBinPack::RectBestShortSideFit);
  731. REPA(placed_rp)
  732. {
  733. RP::RectIndex &rect=placed_rp[i];
  734. RectIndex &dest=placed.New();
  735. C RectSizeAnchor &rsa =sizes[rect.index];
  736. Bool flipped=((rect.width>rect.height)!=(rsa.size.x>rsa.size.y));
  737. if(align_for_compression)
  738. {
  739. VecI2 anchor=rsa.anchor; anchor.x+=rect.x; anchor.y+=rect.y; // final anchor position
  740. rect.x+=Ceil4(anchor.x)-anchor.x; rect.y+=Ceil4(anchor.y)-anchor.y; // offset rectangle so the anchor is 4-pixel aligned
  741. }
  742. dest.index=rect.index; // this should be index in 'limits' but for now we're using it as 'sizes' index
  743. dest.setLD(rect.x, rect.y, rsa.size.c[flipped], rsa.size.c[!flipped]);
  744. }
  745. if(!left.elms()){limit_best=limit; left_all.clear(); Swap(placed, placed_best); goto done;} // finished
  746. area=0; REPA(placed){C RectIndex &r=placed[i]; area+=ULong(r.w())*ULong(r.h());} // check if it's best (covers most area)
  747. if(area>area_best)
  748. {
  749. area_best=area;
  750. limit_best=limit;
  751. Swap(left , left_best);
  752. Swap(placed, placed_best);
  753. }
  754. }
  755. }
  756. if(!placed_best.elms())return false; // if no elements were placed in this step then fail
  757. Swap(left_all, left_best);
  758. done:
  759. REPA(placed_best)
  760. {
  761. RectIndex &src=placed_best[i], &dest=rects[src.index];
  762. dest=src;
  763. dest.index=limits.elms(); // set index as index in 'limits'
  764. }
  765. limits.add(limit_best);
  766. }
  767. return true;
  768. }
  769. /******************************************************************************/
  770. Bool BestFit(Vec2 *point, Int points, Vec2 &axis)
  771. {
  772. Memt<Vec2> convex_points; CreateConvex2D(convex_points, point, points);
  773. if(convex_points.elms()>1)
  774. {
  775. Flt best_area=FLT_MAX;
  776. C Vec2 &last=convex_points.last();
  777. REPA(convex_points)
  778. {
  779. C Vec2 &p0=convex_points[i], &p1=convex_points[(i+1)%convex_points.elms()];
  780. Vec2 dir=p1-p0; if(dir.normalize())
  781. {
  782. Vec2 perp=Perp(dir);
  783. Rect r; r.setX(Dot(last, dir)).setY(Dot(last, perp));
  784. REP(convex_points.elms()-1)
  785. {
  786. C Vec2 &p=convex_points[i];
  787. r.includeX(Dot(p, dir)).includeY(Dot(p, perp));
  788. }
  789. Flt area=r.area(); if(area<best_area){best_area=area; axis=dir;}
  790. }
  791. }
  792. if(best_area<FLT_MAX)return true;
  793. }
  794. return false;
  795. }
  796. Bool BestFit(VecD2 *point, Int points, VecD2 &axis)
  797. {
  798. Memt<VecD2> convex_points; CreateConvex2D(convex_points, point, points);
  799. if(convex_points.elms()>1)
  800. {
  801. Dbl best_area=DBL_MAX;
  802. C VecD2 &last=convex_points.last();
  803. REPA(convex_points)
  804. {
  805. C VecD2 &p0=convex_points[i], &p1=convex_points[(i+1)%convex_points.elms()];
  806. VecD2 dir=p1-p0; if(dir.normalize())
  807. {
  808. VecD2 perp=Perp(dir);
  809. RectD r; r.setX(Dot(last, dir)).setY(Dot(last, perp));
  810. REP(convex_points.elms()-1)
  811. {
  812. C VecD2 &p=convex_points[i];
  813. r.includeX(Dot(p, dir)).includeY(Dot(p, perp));
  814. }
  815. Dbl area=r.area(); if(area<best_area){best_area=area; axis=dir;}
  816. }
  817. }
  818. if(best_area<DBL_MAX)return true;
  819. }
  820. return false;
  821. }
  822. /******************************************************************************/
  823. }
  824. /******************************************************************************/