The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

733 lines
30KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. #ifndef __JUCE_RECTANGLE_JUCEHEADER__
  19. #define __JUCE_RECTANGLE_JUCEHEADER__
  20. #include "juce_Point.h"
  21. class RectangleList;
  22. //==============================================================================
  23. /**
  24. Manages a rectangle and allows geometric operations to be performed on it.
  25. @see RectangleList, Path, Line, Point
  26. */
  27. template <typename ValueType>
  28. class Rectangle
  29. {
  30. public:
  31. //==============================================================================
  32. /** Creates a rectangle of zero size.
  33. The default co-ordinates will be (0, 0, 0, 0).
  34. */
  35. Rectangle() noexcept
  36. : w(), h()
  37. {
  38. }
  39. /** Creates a copy of another rectangle. */
  40. Rectangle (const Rectangle& other) noexcept
  41. : pos (other.pos), w (other.w), h (other.h)
  42. {
  43. }
  44. /** Creates a rectangle with a given position and size. */
  45. Rectangle (const ValueType initialX, const ValueType initialY,
  46. const ValueType width, const ValueType height) noexcept
  47. : pos (initialX, initialY),
  48. w (width), h (height)
  49. {
  50. }
  51. /** Creates a rectangle with a given size, and a position of (0, 0). */
  52. Rectangle (const ValueType width, const ValueType height) noexcept
  53. : w (width), h (height)
  54. {
  55. }
  56. /** Creates a Rectangle from the positions of two opposite corners. */
  57. Rectangle (const Point<ValueType>& corner1, const Point<ValueType>& corner2) noexcept
  58. : pos (jmin (corner1.x, corner2.x),
  59. jmin (corner1.y, corner2.y)),
  60. w (corner1.x - corner2.x),
  61. h (corner1.y - corner2.y)
  62. {
  63. if (w < ValueType()) w = -w;
  64. if (h < ValueType()) h = -h;
  65. }
  66. /** Creates a Rectangle from a set of left, right, top, bottom coordinates.
  67. The right and bottom values must be larger than the left and top ones, or the resulting
  68. rectangle will have a negative size.
  69. */
  70. static Rectangle leftTopRightBottom (const ValueType left, const ValueType top,
  71. const ValueType right, const ValueType bottom) noexcept
  72. {
  73. return Rectangle (left, top, right - left, bottom - top);
  74. }
  75. Rectangle& operator= (const Rectangle& other) noexcept
  76. {
  77. pos = other.pos;
  78. w = other.w; h = other.h;
  79. return *this;
  80. }
  81. /** Destructor. */
  82. ~Rectangle() noexcept {}
  83. //==============================================================================
  84. /** Returns true if the rectangle's width and height are both zero or less */
  85. bool isEmpty() const noexcept { return w <= ValueType() || h <= ValueType(); }
  86. /** Returns the x co-ordinate of the rectangle's left-hand-side. */
  87. inline ValueType getX() const noexcept { return pos.x; }
  88. /** Returns the y co-ordinate of the rectangle's top edge. */
  89. inline ValueType getY() const noexcept { return pos.y; }
  90. /** Returns the width of the rectangle. */
  91. inline ValueType getWidth() const noexcept { return w; }
  92. /** Returns the height of the rectangle. */
  93. inline ValueType getHeight() const noexcept { return h; }
  94. /** Returns the x co-ordinate of the rectangle's right-hand-side. */
  95. inline ValueType getRight() const noexcept { return pos.x + w; }
  96. /** Returns the y co-ordinate of the rectangle's bottom edge. */
  97. inline ValueType getBottom() const noexcept { return pos.y + h; }
  98. /** Returns the x co-ordinate of the rectangle's centre. */
  99. ValueType getCentreX() const noexcept { return pos.x + w / (ValueType) 2; }
  100. /** Returns the y co-ordinate of the rectangle's centre. */
  101. ValueType getCentreY() const noexcept { return pos.y + h / (ValueType) 2; }
  102. /** Returns the centre point of the rectangle. */
  103. Point<ValueType> getCentre() const noexcept { return Point<ValueType> (pos.x + w / (ValueType) 2,
  104. pos.y + h / (ValueType) 2); }
  105. /** Returns the aspect ratio of the rectangle's width / height.
  106. If widthOverHeight is true, it returns width / height; if widthOverHeight is false,
  107. it returns height / width. */
  108. ValueType getAspectRatio (const bool widthOverHeight = true) const noexcept { return widthOverHeight ? w / h : h / w; }
  109. //==============================================================================
  110. /** Returns the rectangle's top-left position as a Point. */
  111. const Point<ValueType>& getPosition() const noexcept { return pos; }
  112. /** Changes the position of the rectangle's top-left corner (leaving its size unchanged). */
  113. void setPosition (const Point<ValueType>& newPos) noexcept { pos = newPos; }
  114. /** Changes the position of the rectangle's top-left corner (leaving its size unchanged). */
  115. void setPosition (const ValueType newX, const ValueType newY) noexcept { pos.setXY (newX, newY); }
  116. /** Returns a rectangle with the same size as this one, but a new position. */
  117. Rectangle withPosition (const ValueType newX, const ValueType newY) const noexcept { return Rectangle (newX, newY, w, h); }
  118. /** Returns a rectangle with the same size as this one, but a new position. */
  119. Rectangle withPosition (const Point<ValueType>& newPos) const noexcept { return Rectangle (newPos.x, newPos.y, w, h); }
  120. /** Returns the rectangle's top-left position as a Point. */
  121. const Point<ValueType>& getTopLeft() const noexcept { return pos; }
  122. /** Returns the rectangle's top-right position as a Point. */
  123. Point<ValueType> getTopRight() const noexcept { return Point<ValueType> (pos.x + w, pos.y); }
  124. /** Returns the rectangle's bottom-left position as a Point. */
  125. Point<ValueType> getBottomLeft() const noexcept { return Point<ValueType> (pos.x, pos.y + h); }
  126. /** Returns the rectangle's bottom-right position as a Point. */
  127. Point<ValueType> getBottomRight() const noexcept { return Point<ValueType> (pos.x + w, pos.y + h); }
  128. /** Changes the rectangle's size, leaving the position of its top-left corner unchanged. */
  129. void setSize (const ValueType newWidth, const ValueType newHeight) noexcept { w = newWidth; h = newHeight; }
  130. /** Returns a rectangle with the same position as this one, but a new size. */
  131. Rectangle withSize (const ValueType newWidth, const ValueType newHeight) const noexcept { return Rectangle (pos.x, pos.y, newWidth, newHeight); }
  132. /** Changes all the rectangle's co-ordinates. */
  133. void setBounds (const ValueType newX, const ValueType newY,
  134. const ValueType newWidth, const ValueType newHeight) noexcept
  135. {
  136. pos.x = newX; pos.y = newY; w = newWidth; h = newHeight;
  137. }
  138. /** Changes the rectangle's X coordinate */
  139. void setX (const ValueType newX) noexcept { pos.x = newX; }
  140. /** Changes the rectangle's Y coordinate */
  141. void setY (const ValueType newY) noexcept { pos.y = newY; }
  142. /** Changes the rectangle's width */
  143. void setWidth (const ValueType newWidth) noexcept { w = newWidth; }
  144. /** Changes the rectangle's height */
  145. void setHeight (const ValueType newHeight) noexcept { h = newHeight; }
  146. /** Returns a rectangle which has the same size and y-position as this one, but with a different x-position. */
  147. Rectangle withX (const ValueType newX) const noexcept { return Rectangle (newX, pos.y, w, h); }
  148. /** Returns a rectangle which has the same size and x-position as this one, but with a different y-position. */
  149. Rectangle withY (const ValueType newY) const noexcept { return Rectangle (pos.x, newY, w, h); }
  150. /** Returns a rectangle which has the same position and height as this one, but with a different width. */
  151. Rectangle withWidth (const ValueType newWidth) const noexcept { return Rectangle (pos.x, pos.y, newWidth, h); }
  152. /** Returns a rectangle which has the same position and width as this one, but with a different height. */
  153. Rectangle withHeight (const ValueType newHeight) const noexcept { return Rectangle (pos.x, pos.y, w, newHeight); }
  154. /** Moves the x position, adjusting the width so that the right-hand edge remains in the same place.
  155. If the x is moved to be on the right of the current right-hand edge, the width will be set to zero.
  156. @see withLeft
  157. */
  158. void setLeft (const ValueType newLeft) noexcept
  159. {
  160. w = jmax (ValueType(), pos.x + w - newLeft);
  161. pos.x = newLeft;
  162. }
  163. /** Returns a new rectangle with a different x position, but the same right-hand edge as this one.
  164. If the new x is beyond the right of the current right-hand edge, the width will be set to zero.
  165. @see setLeft
  166. */
  167. Rectangle withLeft (const ValueType newLeft) const noexcept { return Rectangle (newLeft, pos.y, jmax (ValueType(), pos.x + w - newLeft), h); }
  168. /** Moves the y position, adjusting the height so that the bottom edge remains in the same place.
  169. If the y is moved to be below the current bottom edge, the height will be set to zero.
  170. @see withTop
  171. */
  172. void setTop (const ValueType newTop) noexcept
  173. {
  174. h = jmax (ValueType(), pos.y + h - newTop);
  175. pos.y = newTop;
  176. }
  177. /** Returns a new rectangle with a different y position, but the same bottom edge as this one.
  178. If the new y is beyond the bottom of the current rectangle, the height will be set to zero.
  179. @see setTop
  180. */
  181. Rectangle withTop (const ValueType newTop) const noexcept { return Rectangle (pos.x, newTop, w, jmax (ValueType(), pos.y + h - newTop)); }
  182. /** Adjusts the width so that the right-hand edge of the rectangle has this new value.
  183. If the new right is below the current X value, the X will be pushed down to match it.
  184. @see getRight, withRight
  185. */
  186. void setRight (const ValueType newRight) noexcept
  187. {
  188. pos.x = jmin (pos.x, newRight);
  189. w = newRight - pos.x;
  190. }
  191. /** Returns a new rectangle with a different right-hand edge position, but the same left-hand edge as this one.
  192. If the new right edge is below the current left-hand edge, the width will be set to zero.
  193. @see setRight
  194. */
  195. Rectangle withRight (const ValueType newRight) const noexcept { return Rectangle (jmin (pos.x, newRight), pos.y, jmax (ValueType(), newRight - pos.x), h); }
  196. /** Adjusts the height so that the bottom edge of the rectangle has this new value.
  197. If the new bottom is lower than the current Y value, the Y will be pushed down to match it.
  198. @see getBottom, withBottom
  199. */
  200. void setBottom (const ValueType newBottom) noexcept
  201. {
  202. pos.y = jmin (pos.y, newBottom);
  203. h = newBottom - pos.y;
  204. }
  205. /** Returns a new rectangle with a different bottom edge position, but the same top edge as this one.
  206. If the new y is beyond the bottom of the current rectangle, the height will be set to zero.
  207. @see setBottom
  208. */
  209. Rectangle withBottom (const ValueType newBottom) const noexcept { return Rectangle (pos.x, jmin (pos.y, newBottom), w, jmax (ValueType(), newBottom - pos.y)); }
  210. //==============================================================================
  211. /** Moves the rectangle's position by adding amount to its x and y co-ordinates. */
  212. void translate (const ValueType deltaX,
  213. const ValueType deltaY) noexcept
  214. {
  215. pos.x += deltaX;
  216. pos.y += deltaY;
  217. }
  218. /** Returns a rectangle which is the same as this one moved by a given amount. */
  219. Rectangle translated (const ValueType deltaX,
  220. const ValueType deltaY) const noexcept
  221. {
  222. return Rectangle (pos.x + deltaX, pos.y + deltaY, w, h);
  223. }
  224. /** Returns a rectangle which is the same as this one moved by a given amount. */
  225. Rectangle operator+ (const Point<ValueType>& deltaPosition) const noexcept
  226. {
  227. return Rectangle (pos.x + deltaPosition.x, pos.y + deltaPosition.y, w, h);
  228. }
  229. /** Moves this rectangle by a given amount. */
  230. Rectangle& operator+= (const Point<ValueType>& deltaPosition) noexcept
  231. {
  232. pos += deltaPosition;
  233. return *this;
  234. }
  235. /** Returns a rectangle which is the same as this one moved by a given amount. */
  236. Rectangle operator- (const Point<ValueType>& deltaPosition) const noexcept
  237. {
  238. return Rectangle (pos.x - deltaPosition.x, pos.y - deltaPosition.y, w, h);
  239. }
  240. /** Moves this rectangle by a given amount. */
  241. Rectangle& operator-= (const Point<ValueType>& deltaPosition) noexcept
  242. {
  243. pos -= deltaPosition;
  244. return *this;
  245. }
  246. /** Expands the rectangle by a given amount.
  247. Effectively, its new size is (x - deltaX, y - deltaY, w + deltaX * 2, h + deltaY * 2).
  248. @see expanded, reduce, reduced
  249. */
  250. void expand (const ValueType deltaX,
  251. const ValueType deltaY) noexcept
  252. {
  253. const ValueType nw = jmax (ValueType(), w + deltaX * 2);
  254. const ValueType nh = jmax (ValueType(), h + deltaY * 2);
  255. setBounds (pos.x - deltaX, pos.y - deltaY, nw, nh);
  256. }
  257. /** Returns a rectangle that is larger than this one by a given amount.
  258. Effectively, the rectangle returned is (x - deltaX, y - deltaY, w + deltaX * 2, h + deltaY * 2).
  259. @see expand, reduce, reduced
  260. */
  261. Rectangle expanded (const ValueType deltaX,
  262. const ValueType deltaY) const noexcept
  263. {
  264. const ValueType nw = jmax (ValueType(), w + deltaX * 2);
  265. const ValueType nh = jmax (ValueType(), h + deltaY * 2);
  266. return Rectangle (pos.x - deltaX, pos.y - deltaY, nw, nh);
  267. }
  268. /** Shrinks the rectangle by a given amount.
  269. Effectively, its new size is (x + deltaX, y + deltaY, w - deltaX * 2, h - deltaY * 2).
  270. @see reduced, expand, expanded
  271. */
  272. void reduce (const ValueType deltaX,
  273. const ValueType deltaY) noexcept
  274. {
  275. expand (-deltaX, -deltaY);
  276. }
  277. /** Returns a rectangle that is smaller than this one by a given amount.
  278. Effectively, the rectangle returned is (x + deltaX, y + deltaY, w - deltaX * 2, h - deltaY * 2).
  279. @see reduce, expand, expanded
  280. */
  281. Rectangle reduced (const ValueType deltaX,
  282. const ValueType deltaY) const noexcept
  283. {
  284. return expanded (-deltaX, -deltaY);
  285. }
  286. /** Removes a strip from the top of this rectangle, reducing this rectangle
  287. by the specified amount and returning the section that was removed.
  288. E.g. if this rectangle is (100, 100, 300, 300) and amountToRemove is 50, this will
  289. return (100, 100, 300, 50) and leave this rectangle as (100, 150, 300, 250).
  290. If amountToRemove is greater than the height of this rectangle, it'll be clipped to
  291. that value.
  292. */
  293. Rectangle removeFromTop (const ValueType amountToRemove) noexcept
  294. {
  295. const Rectangle r (pos.x, pos.y, w, jmin (amountToRemove, h));
  296. pos.y += r.h; h -= r.h;
  297. return r;
  298. }
  299. /** Removes a strip from the left-hand edge of this rectangle, reducing this rectangle
  300. by the specified amount and returning the section that was removed.
  301. E.g. if this rectangle is (100, 100, 300, 300) and amountToRemove is 50, this will
  302. return (100, 100, 50, 300) and leave this rectangle as (150, 100, 250, 300).
  303. If amountToRemove is greater than the width of this rectangle, it'll be clipped to
  304. that value.
  305. */
  306. Rectangle removeFromLeft (const ValueType amountToRemove) noexcept
  307. {
  308. const Rectangle r (pos.x, pos.y, jmin (amountToRemove, w), h);
  309. pos.x += r.w; w -= r.w;
  310. return r;
  311. }
  312. /** Removes a strip from the right-hand edge of this rectangle, reducing this rectangle
  313. by the specified amount and returning the section that was removed.
  314. E.g. if this rectangle is (100, 100, 300, 300) and amountToRemove is 50, this will
  315. return (250, 100, 50, 300) and leave this rectangle as (100, 100, 250, 300).
  316. If amountToRemove is greater than the width of this rectangle, it'll be clipped to
  317. that value.
  318. */
  319. Rectangle removeFromRight (ValueType amountToRemove) noexcept
  320. {
  321. amountToRemove = jmin (amountToRemove, w);
  322. const Rectangle r (pos.x + w - amountToRemove, pos.y, amountToRemove, h);
  323. w -= amountToRemove;
  324. return r;
  325. }
  326. /** Removes a strip from the bottom of this rectangle, reducing this rectangle
  327. by the specified amount and returning the section that was removed.
  328. E.g. if this rectangle is (100, 100, 300, 300) and amountToRemove is 50, this will
  329. return (100, 250, 300, 50) and leave this rectangle as (100, 100, 300, 250).
  330. If amountToRemove is greater than the height of this rectangle, it'll be clipped to
  331. that value.
  332. */
  333. Rectangle removeFromBottom (ValueType amountToRemove) noexcept
  334. {
  335. amountToRemove = jmin (amountToRemove, h);
  336. const Rectangle r (pos.x, pos.y + h - amountToRemove, w, amountToRemove);
  337. h -= amountToRemove;
  338. return r;
  339. }
  340. //==============================================================================
  341. /** Returns true if the two rectangles are identical. */
  342. bool operator== (const Rectangle& other) const noexcept
  343. {
  344. return pos == other.pos && w == other.w && h == other.h;
  345. }
  346. /** Returns true if the two rectangles are not identical. */
  347. bool operator!= (const Rectangle& other) const noexcept
  348. {
  349. return pos != other.pos || w != other.w || h != other.h;
  350. }
  351. /** Returns true if this co-ordinate is inside the rectangle. */
  352. bool contains (const ValueType xCoord, const ValueType yCoord) const noexcept
  353. {
  354. return xCoord >= pos.x && yCoord >= pos.y && xCoord < pos.x + w && yCoord < pos.y + h;
  355. }
  356. /** Returns true if this co-ordinate is inside the rectangle. */
  357. bool contains (const Point<ValueType>& point) const noexcept
  358. {
  359. return point.x >= pos.x && point.y >= pos.y && point.x < pos.x + w && point.y < pos.y + h;
  360. }
  361. /** Returns true if this other rectangle is completely inside this one. */
  362. bool contains (const Rectangle& other) const noexcept
  363. {
  364. return pos.x <= other.pos.x && pos.y <= other.pos.y
  365. && pos.x + w >= other.pos.x + other.w && pos.y + h >= other.pos.y + other.h;
  366. }
  367. /** Returns the nearest point to the specified point that lies within this rectangle. */
  368. Point<ValueType> getConstrainedPoint (const Point<ValueType>& point) const noexcept
  369. {
  370. return Point<ValueType> (jlimit (pos.x, pos.x + w, point.x),
  371. jlimit (pos.y, pos.y + h, point.y));
  372. }
  373. /** Returns true if any part of another rectangle overlaps this one. */
  374. bool intersects (const Rectangle& other) const noexcept
  375. {
  376. return pos.x + w > other.pos.x
  377. && pos.y + h > other.pos.y
  378. && pos.x < other.pos.x + other.w
  379. && pos.y < other.pos.y + other.h
  380. && w > ValueType() && h > ValueType();
  381. }
  382. /** Returns the region that is the overlap between this and another rectangle.
  383. If the two rectangles don't overlap, the rectangle returned will be empty.
  384. */
  385. Rectangle getIntersection (const Rectangle& other) const noexcept
  386. {
  387. const ValueType nx = jmax (pos.x, other.pos.x);
  388. const ValueType ny = jmax (pos.y, other.pos.y);
  389. const ValueType nw = jmin (pos.x + w, other.pos.x + other.w) - nx;
  390. const ValueType nh = jmin (pos.y + h, other.pos.y + other.h) - ny;
  391. if (nw >= ValueType() && nh >= ValueType())
  392. return Rectangle (nx, ny, nw, nh);
  393. return Rectangle();
  394. }
  395. /** Clips a rectangle so that it lies only within this one.
  396. This is a non-static version of intersectRectangles().
  397. Returns false if the two regions didn't overlap.
  398. */
  399. bool intersectRectangle (ValueType& otherX, ValueType& otherY, ValueType& otherW, ValueType& otherH) const noexcept
  400. {
  401. const ValueType maxX (jmax (otherX, pos.x));
  402. otherW = jmin (otherX + otherW, pos.x + w) - maxX;
  403. if (otherW > ValueType())
  404. {
  405. const ValueType maxY (jmax (otherY, pos.y));
  406. otherH = jmin (otherY + otherH, pos.y + h) - maxY;
  407. if (otherH > ValueType())
  408. {
  409. otherX = maxX; otherY = maxY;
  410. return true;
  411. }
  412. }
  413. return false;
  414. }
  415. /** Returns the smallest rectangle that contains both this one and the one passed-in.
  416. If either this or the other rectangle are empty, they will not be counted as
  417. part of the resulting region.
  418. */
  419. Rectangle getUnion (const Rectangle& other) const noexcept
  420. {
  421. if (other.isEmpty()) return *this;
  422. if (isEmpty()) return other;
  423. const ValueType newX = jmin (pos.x, other.pos.x);
  424. const ValueType newY = jmin (pos.y, other.pos.y);
  425. return Rectangle (newX, newY,
  426. jmax (pos.x + w, other.pos.x + other.w) - newX,
  427. jmax (pos.y + h, other.pos.y + other.h) - newY);
  428. }
  429. /** If this rectangle merged with another one results in a simple rectangle, this
  430. will set this rectangle to the result, and return true.
  431. Returns false and does nothing to this rectangle if the two rectangles don't overlap,
  432. or if they form a complex region.
  433. */
  434. bool enlargeIfAdjacent (const Rectangle& other) noexcept
  435. {
  436. if (pos.x == other.pos.x && getRight() == other.getRight()
  437. && (other.getBottom() >= pos.y && other.pos.y <= getBottom()))
  438. {
  439. const ValueType newY = jmin (pos.y, other.pos.y);
  440. h = jmax (getBottom(), other.getBottom()) - newY;
  441. pos.y = newY;
  442. return true;
  443. }
  444. else if (pos.y == other.pos.y && getBottom() == other.getBottom()
  445. && (other.getRight() >= pos.x && other.pos.x <= getRight()))
  446. {
  447. const ValueType newX = jmin (pos.x, other.pos.x);
  448. w = jmax (getRight(), other.getRight()) - newX;
  449. pos.x = newX;
  450. return true;
  451. }
  452. return false;
  453. }
  454. /** If after removing another rectangle from this one the result is a simple rectangle,
  455. this will set this object's bounds to be the result, and return true.
  456. Returns false and does nothing to this rectangle if the two rectangles don't overlap,
  457. or if removing the other one would form a complex region.
  458. */
  459. bool reduceIfPartlyContainedIn (const Rectangle& other) noexcept
  460. {
  461. int inside = 0;
  462. const ValueType otherR (other.getRight());
  463. if (pos.x >= other.pos.x && pos.x < otherR) inside = 1;
  464. const ValueType otherB (other.getBottom());
  465. if (pos.y >= other.pos.y && pos.y < otherB) inside |= 2;
  466. const ValueType r (pos.x + w);
  467. if (r >= other.pos.x && r < otherR) inside |= 4;
  468. const ValueType b (pos.y + h);
  469. if (b >= other.pos.y && b < otherB) inside |= 8;
  470. switch (inside)
  471. {
  472. case 1 + 2 + 8: w = r - otherR; pos.x = otherR; return true;
  473. case 1 + 2 + 4: h = b - otherB; pos.y = otherB; return true;
  474. case 2 + 4 + 8: w = other.pos.x - pos.x; return true;
  475. case 1 + 4 + 8: h = other.pos.y - pos.y; return true;
  476. }
  477. return false;
  478. }
  479. /** Returns the smallest rectangle that can contain the shape created by applying
  480. a transform to this rectangle.
  481. This should only be used on floating point rectangles.
  482. */
  483. Rectangle transformed (const AffineTransform& transform) const noexcept
  484. {
  485. float x1 = pos.x, y1 = pos.y;
  486. float x2 = pos.x + w, y2 = pos.y;
  487. float x3 = pos.x, y3 = pos.y + h;
  488. float x4 = x2, y4 = y3;
  489. transform.transformPoints (x1, y1, x2, y2);
  490. transform.transformPoints (x3, y3, x4, y4);
  491. const float rx = jmin (x1, x2, x3, x4);
  492. const float ry = jmin (y1, y2, y3, y4);
  493. return Rectangle (rx, ry,
  494. jmax (x1, x2, x3, x4) - rx,
  495. jmax (y1, y2, y3, y4) - ry);
  496. }
  497. /** Returns the smallest integer-aligned rectangle that completely contains this one.
  498. This is only relevent for floating-point rectangles, of course.
  499. @see toFloat()
  500. */
  501. Rectangle<int> getSmallestIntegerContainer() const noexcept
  502. {
  503. const int x1 = static_cast <int> (std::floor (static_cast<float> (pos.x)));
  504. const int y1 = static_cast <int> (std::floor (static_cast<float> (pos.y)));
  505. const int x2 = static_cast <int> (std::ceil (static_cast<float> (pos.x + w)));
  506. const int y2 = static_cast <int> (std::ceil (static_cast<float> (pos.y + h)));
  507. return Rectangle<int> (x1, y1, x2 - x1, y2 - y1);
  508. }
  509. /** Returns the smallest Rectangle that can contain a set of points. */
  510. static Rectangle findAreaContainingPoints (const Point<ValueType>* const points, const int numPoints) noexcept
  511. {
  512. if (numPoints == 0)
  513. return Rectangle();
  514. ValueType minX (points[0].x);
  515. ValueType maxX (minX);
  516. ValueType minY (points[0].y);
  517. ValueType maxY (minY);
  518. for (int i = 1; i < numPoints; ++i)
  519. {
  520. minX = jmin (minX, points[i].x);
  521. maxX = jmax (maxX, points[i].x);
  522. minY = jmin (minY, points[i].y);
  523. maxY = jmax (maxY, points[i].y);
  524. }
  525. return Rectangle (minX, minY, maxX - minX, maxY - minY);
  526. }
  527. /** Casts this rectangle to a Rectangle<float>.
  528. Obviously this is mainly useful for rectangles that use integer types.
  529. @see getSmallestIntegerContainer
  530. */
  531. Rectangle<float> toFloat() const noexcept
  532. {
  533. return Rectangle<float> (static_cast<float> (pos.x), static_cast<float> (pos.y),
  534. static_cast<float> (w), static_cast<float> (h));
  535. }
  536. //==============================================================================
  537. /** Static utility to intersect two sets of rectangular co-ordinates.
  538. Returns false if the two regions didn't overlap.
  539. @see intersectRectangle
  540. */
  541. static bool intersectRectangles (ValueType& x1, ValueType& y1, ValueType& w1, ValueType& h1,
  542. const ValueType x2, const ValueType y2, const ValueType w2, const ValueType h2) noexcept
  543. {
  544. const ValueType x (jmax (x1, x2));
  545. w1 = jmin (x1 + w1, x2 + w2) - x;
  546. if (w1 > ValueType())
  547. {
  548. const ValueType y (jmax (y1, y2));
  549. h1 = jmin (y1 + h1, y2 + h2) - y;
  550. if (h1 > ValueType())
  551. {
  552. x1 = x; y1 = y;
  553. return true;
  554. }
  555. }
  556. return false;
  557. }
  558. //==============================================================================
  559. /** Creates a string describing this rectangle.
  560. The string will be of the form "x y width height", e.g. "100 100 400 200".
  561. Coupled with the fromString() method, this is very handy for things like
  562. storing rectangles (particularly component positions) in XML attributes.
  563. @see fromString
  564. */
  565. String toString() const
  566. {
  567. String s;
  568. s.preallocateBytes (32);
  569. s << pos.x << ' ' << pos.y << ' ' << w << ' ' << h;
  570. return s;
  571. }
  572. /** Parses a string containing a rectangle's details.
  573. The string should contain 4 integer tokens, in the form "x y width height". They
  574. can be comma or whitespace separated.
  575. This method is intended to go with the toString() method, to form an easy way
  576. of saving/loading rectangles as strings.
  577. @see toString
  578. */
  579. static Rectangle fromString (const String& stringVersion)
  580. {
  581. StringArray toks;
  582. toks.addTokens (stringVersion.trim(), ",; \t\r\n", String::empty);
  583. return Rectangle (toks[0].trim().getIntValue(),
  584. toks[1].trim().getIntValue(),
  585. toks[2].trim().getIntValue(),
  586. toks[3].trim().getIntValue());
  587. }
  588. private:
  589. friend class RectangleList;
  590. Point<ValueType> pos;
  591. ValueType w, h;
  592. };
  593. #endif // __JUCE_RECTANGLE_JUCEHEADER__