mobility: Fix Rectangle::GetClosestSideOrCorner

When the tested position was outside the rectangle at a distance greater than the width/height of the rectangle, it would be incorrectly matched
This commit is contained in:
Gabriel Ferreira
2025-04-11 11:19:01 +02:00
parent aef171c305
commit b812e472a0
2 changed files with 64 additions and 31 deletions

View File

@@ -52,12 +52,28 @@ Rectangle::IsOnTheBorder(const Vector& position) const
Rectangle::Side
Rectangle::GetClosestSideOrCorner(const Vector& position) const
{
std::array<double, 4> distanceFromBorders{
std::abs(position.x - this->xMin), // left border
std::abs(this->xMax - position.x), // right border
std::abs(position.y - this->yMin), // bottom border
std::abs(this->yMax - position.y), // top border
};
std::array<double, 4> distanceFromBorders;
if (IsInside(position))
{
distanceFromBorders = {
std::abs(position.x - this->xMin), // left border
std::abs(this->xMax - position.x), // right border
std::abs(position.y - this->yMin), // bottom border
std::abs(this->yMax - position.y) // top border
};
}
else
{
const auto yMid = (yMax + yMin) / 2;
const auto xMid = (xMax + xMin) / 2;
distanceFromBorders = {
CalculateDistance(position, Vector(xMin, yMid, position.z)), // left border
CalculateDistance(position, Vector(xMax, yMid, position.z)), // right border
CalculateDistance(position, Vector(xMid, yMin, position.z)), // bottom border
CalculateDistance(position, Vector(xMid, yMax, position.z)) // top border
};
}
uint8_t flags = 0;
double minDist = std::numeric_limits<double>::max();
for (int i = 0; i < 4; i++)
@@ -85,22 +101,12 @@ Rectangle::GetClosestSideOrCorner(const Vector& position) const
side = TOPSIDE;
break;
case 0b0011:
// Opposing sides are equally distant, so we need to check the other two
// We also need to check if we're inside or outside.
// Opposing sides are equally distant, so we choose top
side = TOPSIDE;
if (!IsInside(position))
{
side = (distanceFromBorders[0] > distanceFromBorders[1]) ? RIGHTSIDE : LEFTSIDE;
}
break;
case 0b1100:
// Opposing sides are equally distant, so we need to check the other two
// We also need to check if we're inside or outside.
// Opposing sides are equally distant, so choose right
side = RIGHTSIDE;
if (!IsInside(position))
{
side = (distanceFromBorders[2] > distanceFromBorders[3]) ? TOPSIDE : BOTTOMSIDE;
}
break;
case 0b0001:
case 0b1101:

View File

@@ -87,22 +87,29 @@ RectangleClosestBorderTestSuite::RectangleClosestBorderTestSuite()
// Rectangle in the positive x-plane to check the intersection with.
Rectangle rectangle = Rectangle(0.0, 10.0, 0.0, 10.0);
/* 2 3 4
* +----------------------------+ (10,10)
* | 11 16 12 |
* | |
* | |
* 1 | 15 18 17 | 5
* | |
* | |
* | 10 14 13 |
* +----------------------------+
* 9 7
* (0,0)
/* 23 24
* 20
* :
* :
* 2 3 4
* +----------------------------+ (10,10)
* | 11 16 12 |
* | |
* | |
* 19 .... 1 | 15 18 17 | 5 .... 21
* | |
* | |
* | 10 14 13 |
* +----------------------------+
* 9 7
* (0,0)
*
*
*
* 8
* 8
* :
* :
* 26 22 25
*/
// Left side (1 and 15)
AddTestCase(new RectangleClosestBorderTestCase(-5, 5, rectangle, Rectangle::LEFTSIDE),
@@ -147,6 +154,26 @@ RectangleClosestBorderTestSuite::RectangleClosestBorderTestSuite()
// Central position (18)
AddTestCase(new RectangleClosestBorderTestCase(5, 5, rectangle, Rectangle::TOPSIDE),
TestCase::Duration::QUICK);
// For coordinates to left, top, right, bottom (19, 20, 21, 22)
AddTestCase(new RectangleClosestBorderTestCase(-30, 5, rectangle, Rectangle::LEFTSIDE),
TestCase::Duration::QUICK);
AddTestCase(new RectangleClosestBorderTestCase(5, 30, rectangle, Rectangle::TOPSIDE),
TestCase::Duration::QUICK);
AddTestCase(new RectangleClosestBorderTestCase(30, 5, rectangle, Rectangle::RIGHTSIDE),
TestCase::Duration::QUICK);
AddTestCase(new RectangleClosestBorderTestCase(5, -30, rectangle, Rectangle::BOTTOMSIDE),
TestCase::Duration::QUICK);
// For coordinates to left-top, right-top, right-bottom, left-bottom diagonals (23, 24, 25, 26)
AddTestCase(new RectangleClosestBorderTestCase(-30, 40, rectangle, Rectangle::TOPLEFTCORNER),
TestCase::Duration::QUICK);
AddTestCase(new RectangleClosestBorderTestCase(40, 40, rectangle, Rectangle::TOPRIGHTCORNER),
TestCase::Duration::QUICK);
AddTestCase(
new RectangleClosestBorderTestCase(40, -30, rectangle, Rectangle::BOTTOMRIGHTCORNER),
TestCase::Duration::QUICK);
AddTestCase(
new RectangleClosestBorderTestCase(-30, -30, rectangle, Rectangle::BOTTOMLEFTCORNER),
TestCase::Duration::QUICK);
}
/**