Rect.cpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. /*
  2. * Rect.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. #include "int3.h"
  13. VCMI_LIB_NAMESPACE_BEGIN
  14. Point::Point(const int3 & a)
  15. : x(a.x)
  16. , y(a.y)
  17. {
  18. }
  19. /// Returns rect union - rect that covers both this rect and provided rect
  20. Rect Rect::include(const Rect & other) const
  21. {
  22. Point topLeft{
  23. std::min(this->left(), other.left()),
  24. std::min(this->top(), other.top())
  25. };
  26. Point bottomRight{
  27. std::max(this->right(), other.right()),
  28. std::max(this->bottom(), other.bottom())
  29. };
  30. return Rect(topLeft, bottomRight - topLeft);
  31. }
  32. Rect Rect::createCentered( const Point & around, const Point & dimensions )
  33. {
  34. return Rect(around - dimensions/2, dimensions);
  35. }
  36. Rect Rect::createAround(const Rect &r, int width)
  37. {
  38. return Rect(r.x - width, r.y - width, r.w + width * 2, r.h + width * 2);
  39. }
  40. Rect Rect::createCentered( const Rect & rect, const Point & dimensions)
  41. {
  42. return createCentered(rect.center(), dimensions);
  43. }
  44. bool Rect::intersectionTest(const Rect & other) const
  45. {
  46. // this rect is above other rect
  47. if(this->bottom() < other.top())
  48. return false;
  49. // this rect is below other rect
  50. if(this->top() > other.bottom() )
  51. return false;
  52. // this rect is to the left of other rect
  53. if(this->right() < other.left())
  54. return false;
  55. // this rect is to the right of other rect
  56. if(this->left() > other.right())
  57. return false;
  58. return true;
  59. }
  60. /// Algorithm to test whether line segment between points line1-line2 will intersect with
  61. /// rectangle specified by top-left and bottom-right points
  62. /// Note that in order to avoid floating point rounding errors algorithm uses integers with no divisions
  63. bool Rect::intersectionTest(const Point & line1, const Point & line2) const
  64. {
  65. // check whether segment is located to the left of our rect
  66. if (line1.x < left() && line2.x < left())
  67. return false;
  68. // check whether segment is located to the right of our rect
  69. if (line1.x > right() && line2.x > right())
  70. return false;
  71. // check whether segment is located on top of our rect
  72. if (line1.y < top() && line2.y < top())
  73. return false;
  74. // check whether segment is located below of our rect
  75. if (line1.y > bottom() && line2.y > bottom())
  76. return false;
  77. Point vector { line2.x - line1.x, line2.y - line1.y};
  78. // compute position of corners relative to our line
  79. int tlTest = vector.y*topLeft().x - vector.x*topLeft().y + (line2.x*line1.y-line1.x*line2.y);
  80. int trTest = vector.y*bottomRight().x - vector.x*topLeft().y + (line2.x*line1.y-line1.x*line2.y);
  81. int blTest = vector.y*topLeft().x - vector.x*bottomRight().y + (line2.x*line1.y-line1.x*line2.y);
  82. int brTest = vector.y*bottomRight().x - vector.x*bottomRight().y + (line2.x*line1.y-line1.x*line2.y);
  83. // if all points are on the left of our line then there is no intersection
  84. if ( tlTest > 0 && trTest > 0 && blTest > 0 && brTest > 0 )
  85. return false;
  86. // if all points are on the right of our line then there is no intersection
  87. if ( tlTest < 0 && trTest < 0 && blTest < 0 && brTest < 0 )
  88. return false;
  89. // if all previous checks failed, this means that there is an intersection between line and AABB
  90. return true;
  91. }
  92. Rect Rect::intersect(const Rect & other) const
  93. {
  94. if(intersectionTest(other))
  95. {
  96. Point topLeft{
  97. std::max(this->left(), other.left()),
  98. std::max(this->top(), other.top())
  99. };
  100. Point bottomRight{
  101. std::min(this->right(), other.right()),
  102. std::min(this->bottom(), other.bottom())
  103. };
  104. return Rect(topLeft, bottomRight - topLeft);
  105. }
  106. else
  107. {
  108. return Rect();
  109. }
  110. }
  111. int Rect::distanceTo(const Point & target) const
  112. {
  113. int distanceX = std::max({left() - target.x, 0, target.x - right()});
  114. int distanceY = std::max({top() - target.y, 0, target.y - bottom()});
  115. return Point(distanceX, distanceY).length();
  116. }
  117. VCMI_LIB_NAMESPACE_END