Rect.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. /*
  2. * ResourceSet.cpp, part of VCMI engine
  3. *
  4. * Authors: listed in file AUTHORS in main folder
  5. *
  6. * License: GNU General Public License v2.0 or later
  7. * Full text of license available in license.txt file, in main folder
  8. *
  9. */
  10. #include "StdInc.h"
  11. #include "Rect.h"
  12. VCMI_LIB_NAMESPACE_BEGIN
  13. /// Returns rect union - rect that covers both this rect and provided rect
  14. Rect Rect::include(const Rect & other) const
  15. {
  16. Point topLeft{
  17. std::min(this->left(), other.left()),
  18. std::min(this->top(), other.top())
  19. };
  20. Point bottomRight{
  21. std::max(this->right(), other.right()),
  22. std::max(this->bottom(), other.bottom())
  23. };
  24. return Rect(topLeft, bottomRight - topLeft);
  25. }
  26. Rect Rect::createCentered( const Point & around, const Point & dimensions )
  27. {
  28. return Rect(around - dimensions/2, dimensions);
  29. }
  30. Rect Rect::createAround(const Rect &r, int width)
  31. {
  32. return Rect(r.x - width, r.y - width, r.w + width * 2, r.h + width * 2);
  33. }
  34. Rect Rect::createCentered( const Rect & rect, const Point & dimensions)
  35. {
  36. return createCentered(rect.center(), dimensions);
  37. }
  38. bool Rect::intersectionTest(const Rect & other) const
  39. {
  40. // this rect is above other rect
  41. if(this->bottom() < other.top())
  42. return false;
  43. // this rect is below other rect
  44. if(this->top() > other.bottom() )
  45. return false;
  46. // this rect is to the left of other rect
  47. if(this->right() < other.left())
  48. return false;
  49. // this rect is to the right of other rect
  50. if(this->left() > other.right())
  51. return false;
  52. return true;
  53. }
  54. /// Algorithm to test whether line segment between points line1-line2 will intersect with
  55. /// rectangle specified by top-left and bottom-right points
  56. /// Note that in order to avoid floating point rounding errors algorithm uses integers with no divisions
  57. bool Rect::intersectionTest(const Point & line1, const Point & line2) const
  58. {
  59. // check whether segment is located to the left of our rect
  60. if (line1.x < left() && line2.x < left())
  61. return false;
  62. // check whether segment is located to the right of our rect
  63. if (line1.x > right() && line2.x > right())
  64. return false;
  65. // check whether segment is located on top of our rect
  66. if (line1.y < top() && line2.y < top())
  67. return false;
  68. // check whether segment is located below of our rect
  69. if (line1.y > bottom() && line2.y > bottom())
  70. return false;
  71. Point vector { line2.x - line1.x, line2.y - line1.y};
  72. // compute position of corners relative to our line
  73. int tlTest = vector.y*topLeft().x - vector.x*topLeft().y + (line2.x*line1.y-line1.x*line2.y);
  74. int trTest = vector.y*bottomRight().x - vector.x*topLeft().y + (line2.x*line1.y-line1.x*line2.y);
  75. int blTest = vector.y*topLeft().x - vector.x*bottomRight().y + (line2.x*line1.y-line1.x*line2.y);
  76. int brTest = vector.y*bottomRight().x - vector.x*bottomRight().y + (line2.x*line1.y-line1.x*line2.y);
  77. // if all points are on the left of our line then there is no intersection
  78. if ( tlTest > 0 && trTest > 0 && blTest > 0 && brTest > 0 )
  79. return false;
  80. // if all points are on the right of our line then there is no intersection
  81. if ( tlTest < 0 && trTest < 0 && blTest < 0 && brTest < 0 )
  82. return false;
  83. // if all previous checks failed, this means that there is an intersection between line and AABB
  84. return true;
  85. }
  86. Rect Rect::intersect(const Rect & other) const
  87. {
  88. if(intersectionTest(other))
  89. {
  90. Point topLeft{
  91. std::max(this->left(), other.left()),
  92. std::max(this->top(), other.top())
  93. };
  94. Point bottomRight{
  95. std::min(this->right(), other.right()),
  96. std::min(this->bottom(), other.bottom())
  97. };
  98. return Rect(topLeft, bottomRight - topLeft);
  99. }
  100. else
  101. {
  102. return Rect();
  103. }
  104. }
  105. VCMI_LIB_NAMESPACE_END