123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147 |
- /*
- * Rect.cpp, part of VCMI engine
- *
- * Authors: listed in file AUTHORS in main folder
- *
- * License: GNU General Public License v2.0 or later
- * Full text of license available in license.txt file, in main folder
- *
- */
- #include "StdInc.h"
- #include "Rect.h"
- #include "int3.h"
- VCMI_LIB_NAMESPACE_BEGIN
- Point::Point(const int3 & a)
- : x(a.x)
- , y(a.y)
- {
- }
- /// Returns rect union - rect that covers both this rect and provided rect
- Rect Rect::include(const Rect & other) const
- {
- Point topLeft{
- std::min(this->left(), other.left()),
- std::min(this->top(), other.top())
- };
- Point bottomRight{
- std::max(this->right(), other.right()),
- std::max(this->bottom(), other.bottom())
- };
- return Rect(topLeft, bottomRight - topLeft);
- }
- Rect Rect::createCentered( const Point & around, const Point & dimensions )
- {
- return Rect(around - dimensions/2, dimensions);
- }
- Rect Rect::createAround(const Rect &r, int width)
- {
- return Rect(r.x - width, r.y - width, r.w + width * 2, r.h + width * 2);
- }
- Rect Rect::createCentered( const Rect & rect, const Point & dimensions)
- {
- return createCentered(rect.center(), dimensions);
- }
- bool Rect::intersectionTest(const Rect & other) const
- {
- // this rect is above other rect
- if(this->bottom() < other.top())
- return false;
- // this rect is below other rect
- if(this->top() > other.bottom() )
- return false;
- // this rect is to the left of other rect
- if(this->right() < other.left())
- return false;
- // this rect is to the right of other rect
- if(this->left() > other.right())
- return false;
- return true;
- }
- /// Algorithm to test whether line segment between points line1-line2 will intersect with
- /// rectangle specified by top-left and bottom-right points
- /// Note that in order to avoid floating point rounding errors algorithm uses integers with no divisions
- bool Rect::intersectionTest(const Point & line1, const Point & line2) const
- {
- // check whether segment is located to the left of our rect
- if (line1.x < left() && line2.x < left())
- return false;
- // check whether segment is located to the right of our rect
- if (line1.x > right() && line2.x > right())
- return false;
- // check whether segment is located on top of our rect
- if (line1.y < top() && line2.y < top())
- return false;
- // check whether segment is located below of our rect
- if (line1.y > bottom() && line2.y > bottom())
- return false;
- Point vector { line2.x - line1.x, line2.y - line1.y};
- // compute position of corners relative to our line
- int tlTest = vector.y*topLeft().x - vector.x*topLeft().y + (line2.x*line1.y-line1.x*line2.y);
- int trTest = vector.y*bottomRight().x - vector.x*topLeft().y + (line2.x*line1.y-line1.x*line2.y);
- int blTest = vector.y*topLeft().x - vector.x*bottomRight().y + (line2.x*line1.y-line1.x*line2.y);
- int brTest = vector.y*bottomRight().x - vector.x*bottomRight().y + (line2.x*line1.y-line1.x*line2.y);
- // if all points are on the left of our line then there is no intersection
- if ( tlTest > 0 && trTest > 0 && blTest > 0 && brTest > 0 )
- return false;
- // if all points are on the right of our line then there is no intersection
- if ( tlTest < 0 && trTest < 0 && blTest < 0 && brTest < 0 )
- return false;
- // if all previous checks failed, this means that there is an intersection between line and AABB
- return true;
- }
- Rect Rect::intersect(const Rect & other) const
- {
- if(intersectionTest(other))
- {
- Point topLeft{
- std::max(this->left(), other.left()),
- std::max(this->top(), other.top())
- };
- Point bottomRight{
- std::min(this->right(), other.right()),
- std::min(this->bottom(), other.bottom())
- };
- return Rect(topLeft, bottomRight - topLeft);
- }
- else
- {
- return Rect();
- }
- }
- int Rect::distanceTo(const Point & target) const
- {
- int distanceX = std::max({left() - target.x, 0, target.x - right()});
- int distanceY = std::max({top() - target.y, 0, target.y - bottom()});
- return Point(distanceX, distanceY).length();
- }
- VCMI_LIB_NAMESPACE_END
|