Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LineSegment::getIntersection2DSValue incorrect results #1344

Closed
robomic opened this issue Aug 19, 2024 · 0 comments · Fixed by #1353
Closed

LineSegment::getIntersection2DSValue incorrect results #1344

robomic opened this issue Aug 19, 2024 · 0 comments · Fixed by #1353
Assignees

Comments

@robomic
Copy link
Contributor

robomic commented Aug 19, 2024

Describe the bug
LineSegment::getIntersection2DSValue behaves incorrectly (does not return std::nullopt) when provided a point that lies within a vertical strip defined by the segment's endpoints.

Example
This example checks function behavior on numerous points that are disjoint with the segment. It showcases erroneous examples with a red cross.

TEST(LineSegment, getIntersection2DSValue_point_outside)
{
const auto line =
math::geometry::LineSegment(makePoint(-2.0, -2.0, 0.0), makePoint(1.0, 4.0, 0.0));
EXPECT_FALSE(line.getIntersection2DSValue(makePoint(-3.0, 1.0, 0.0), true).has_value());
EXPECT_FALSE(line.getIntersection2DSValue(makePoint(-1.0, 1.0, 0.0), true).has_value());
EXPECT_FALSE(line.getIntersection2DSValue(makePoint(0.0, 1.0, 0.0), true).has_value());
EXPECT_FALSE(line.getIntersection2DSValue(makePoint(2.0, 1.0, 0.0), true).has_value());
EXPECT_FALSE(line.getIntersection2DSValue(makePoint(-0.5, -5.0, 0.0), true).has_value());
EXPECT_FALSE(line.getIntersection2DSValue(makePoint(-0.5, -1.0, 0.0), true).has_value());
EXPECT_FALSE(line.getIntersection2DSValue(makePoint(-0.5, 3.0, 0.0), true).has_value());
EXPECT_FALSE(line.getIntersection2DSValue(makePoint(-0.5, 7.0, 0.0), true).has_value());
EXPECT_FALSE(line.getIntersection2DSValue(makePoint(7.0, 7.0, 0.0), true).has_value());
EXPECT_FALSE(line.getIntersection2DSValue(makePoint(7.0, -7.0, 0.0), true).has_value());
EXPECT_FALSE(line.getIntersection2DSValue(makePoint(-7.0, 7.0, 0.0), true).has_value());
EXPECT_FALSE(line.getIntersection2DSValue(makePoint(-7.0, -7.0, 0.0), true).has_value());
}

  • Green dots mean no intersection; std::nullopt is returned.
  • Red crosses mean an intersection; a value is returned.

image

To Reproduce
Steps to reproduce the behavior:

  1. Switch to this branch, precisely, this commit.
  2. Build and run tests.
  3. See output.

Expected behavior
Function should return std::nullopt when provided with a point that is disjoint (with a tolerance).

Current source code

/**
* @brief Find intersection point of 1 line segment and 1 point.
* @param point point of you want to find intersection.
* @return std::optional<double>
*/
auto LineSegment::getIntersection2DSValue(
const geometry_msgs::msg::Point & point, const bool denormalize_s) const -> std::optional<double>
{
const auto get_s_normalized = [this](const auto & point) -> std::optional<double> {
const auto get_s_from_x = [this](const auto & point) {
const auto s = (point.x - start_point.x) / (end_point.x - start_point.x);
return 0 <= s && s <= 1 ? s : std::optional<double>();
};
const auto get_s_from_y = [this](const auto & point) {
const auto s = (point.y - start_point.y) / (end_point.y - start_point.y);
return 0 <= s && s <= 1 ? s : std::optional<double>();
};
constexpr double epsilon = std::numeric_limits<double>::epsilon();
if (std::abs(end_point.x - start_point.x) <= epsilon) {
if (std::abs(end_point.y - start_point.y) <= epsilon) {
/// @note If start_point and end_point is a same point, checking the point is same as end_point or not.
return (std::abs(end_point.x - point.x) <= epsilon &&
std::abs(end_point.y - point.y) <= epsilon)
? std::optional<double>(0)
: std::optional<double>();
}
/// @note If the line segment is parallel to y axis, calculate s value from y axis value.
return std::abs(point.x - start_point.x) <= epsilon ? get_s_from_y(point)
: std::optional<double>();
}
/// @note If the line segment is not parallel to x and y axis, calculate s value from x axis value.
return get_s_from_x(point);
};
return denormalize_s ? denormalize(get_s_normalized(point)) : get_s_normalized(point);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
1 participant