summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--game/geoData.cpp2
-rw-r--r--lib/maths.h30
-rw-r--r--test/test-maths.cpp32
3 files changed, 35 insertions, 29 deletions
diff --git a/game/geoData.cpp b/game/geoData.cpp
index 37abc4c..45e6590 100644
--- a/game/geoData.cpp
+++ b/game/geoData.cpp
@@ -324,7 +324,7 @@ GeoData::walkUntil(const PointFace & from, GlobalPosition2D to, GlobalPosition2D
const auto e2 = point(to_vertex_handle(opposite_halfedge_handle(next)));
if (const auto intersect = arc.crossesLineAt(e1, e2)) {
step.exitHalfedge = next;
- step.exitPosition = intersect.value();
+ step.exitPosition = intersect.value().first;
break;
}
}
diff --git a/lib/maths.h b/lib/maths.h
index f43321a..671313d 100644
--- a/lib/maths.h
+++ b/lib/maths.h
@@ -48,7 +48,7 @@ template<typename T, glm::qualifier Q = glm::defaultp> struct ArcSegment : publi
PointType ep1;
RelativeDistance radius;
- [[nodiscard]] constexpr std::optional<glm::vec<2, T, Q>> crossesLineAt(
+ [[nodiscard]] constexpr std::optional<std::pair<glm::vec<2, T, Q>, Angle>> crossesLineAt(
const glm::vec<2, T, Q> & lineStart, const glm::vec<2, T, Q> & lineEnd) const;
[[nodiscard]] constexpr bool
@@ -502,7 +502,7 @@ constexpr ArcSegment<T, Q>::ArcSegment(PointType centre, PointType ep0, PointTyp
}
template<typename T, glm::qualifier Q>
-[[nodiscard]] constexpr std::optional<glm::vec<2, T, Q>>
+[[nodiscard]] constexpr std::optional<std::pair<glm::vec<2, T, Q>, Angle>>
ArcSegment<T, Q>::crossesLineAt(const glm::vec<2, T, Q> & lineStart, const glm::vec<2, T, Q> & lineEnd) const
{
// Based on formulas from https://mathworld.wolfram.com/Circle-LineIntersection.html
@@ -519,23 +519,23 @@ ArcSegment<T, Q>::crossesLineAt(const glm::vec<2, T, Q> & lineStart, const glm::
const auto rootDiscriminant = std::sqrt(discriminant);
const auto drdr = lineLen * lineLen;
const RelativeDistance sgn = (lineDiff.y < 0 ? -1 : 1);
- std::array points {
- RelativePosition2D {((determinant * lineDiff.y) + sgn * lineDiff.x * rootDiscriminant),
- ((-determinant * lineDiff.x) + std::abs(lineDiff.y) * rootDiscriminant)}
- / drdr,
- RelativePosition2D {((determinant * lineDiff.y) - sgn * lineDiff.x * rootDiscriminant),
- ((-determinant * lineDiff.x) - std::abs(lineDiff.y) * rootDiscriminant)}
- / drdr,
- };
+ std::array<std::pair<RelativePosition2D, Angle>, 2> points;
+ std::ranges::transform(std::initializer_list {1, -1}, points.begin(), [&](RelativeDistance N) {
+ const auto point = RelativePosition2D {((determinant * lineDiff.y) + sgn * lineDiff.x * rootDiscriminant * N),
+ ((-determinant * lineDiff.x) + std::abs(lineDiff.y) * rootDiscriminant * N)}
+ / drdr;
+ return std::make_pair(point, vector_yaw(point));
+ });
const auto end
= std::remove_if(points.begin(), points.end(), [this, lineRelStart, lineDiff, drdr](const auto point) {
- const auto dot = glm::dot(lineDiff, point - lineRelStart);
- return !angleWithinArc(vector_yaw(point)) || dot < 0 || dot > drdr;
- });
+ const auto dot = glm::dot(lineDiff, point.first - lineRelStart);
+ return !angleWithinArc(point.second) || dot < 0 || dot > drdr;
+ });
if (points.begin() == end) {
return std::nullopt;
}
- return centre + *std::ranges::min_element(points.begin(), end, {}, [lineRelStart](const auto point) {
- return glm::distance(lineRelStart, point);
+ const auto first = *std::ranges::min_element(points.begin(), end, {}, [lineRelStart](const auto point) {
+ return glm::distance(lineRelStart, point.first);
});
+ return std::make_pair(centre + first.first, first.second);
}
diff --git a/test/test-maths.cpp b/test/test-maths.cpp
index aa2b9c8..5906757 100644
--- a/test/test-maths.cpp
+++ b/test/test-maths.cpp
@@ -376,33 +376,39 @@ BOOST_AUTO_TEST_CASE(triangle3d_helpers)
BOOST_CHECK_CLOSE(t.area(), 12.5F, 0.01F);
}
+using ArcLineIntersectExp = std::pair<GlobalPosition2D, Angle>;
using ArcLineIntersectData = std::tuple<GlobalPosition2D, GlobalPosition2D, GlobalPosition2D, GlobalPosition2D,
- GlobalPosition2D, std::optional<GlobalPosition2D>>;
+ GlobalPosition2D, std::optional<ArcLineIntersectExp>>;
BOOST_DATA_TEST_CASE(arcline_intersection,
boost::unit_test::data::make<ArcLineIntersectData>({
{{0, 0}, {0, 100}, {100, 0}, {200, 0}, {0, 200}, std::nullopt},
{{0, 0}, {0, 100}, {100, 0}, {0, 0}, {10, 10}, std::nullopt},
- {{0, 0}, {0, 100}, {100, 0}, {0, 0}, {100, 100}, GlobalPosition2D {71, 71}},
- {{15, 27}, {15, 127}, {115, 27}, {15, 27}, {115, 127}, GlobalPosition2D {86, 98}},
+ {{0, 0}, {0, 100}, {100, 0}, {0, 0}, {100, 100}, ArcLineIntersectExp {{71, 71}, quarter_pi}},
+ {{15, 27}, {15, 127}, {115, 27}, {15, 27}, {115, 127}, ArcLineIntersectExp {{86, 98}, quarter_pi}},
{{0, 0}, {0, 100}, {100, 0}, {0, 0}, {-100, -100}, std::nullopt},
- {{0, 0}, {0, 100}, {100, 0}, {-10, 125}, {125, -10}, GlobalPosition2D {16, 99}},
- {{0, 0}, {0, 100}, {100, 0}, {125, -10}, {-10, 125}, GlobalPosition2D {99, 16}},
- {{0, 0}, {0, 100}, {100, 0}, {10, 125}, {125, -10}, GlobalPosition2D {38, 93}},
- {{0, 0}, {0, 100}, {100, 0}, {12, 80}, {125, -10}, GlobalPosition2D {99, 10}},
- {{0, 0}, {0, 100}, {100, 0}, {40, 80}, {125, -10}, GlobalPosition2D {98, 18}},
+ {{0, 0}, {0, 100}, {100, 0}, {-10, 125}, {125, -10}, ArcLineIntersectExp {{16, 99}, 0.164F}},
+ {{0, 0}, {0, 100}, {100, 0}, {125, -10}, {-10, 125}, ArcLineIntersectExp {{99, 16}, 1.407F}},
+ {{0, 0}, {0, 100}, {100, 0}, {10, 125}, {125, -10}, ArcLineIntersectExp {{38, 93}, 0.385F}},
+ {{0, 0}, {0, 100}, {100, 0}, {12, 80}, {125, -10}, ArcLineIntersectExp {{99, 10}, 1.467F}},
+ {{0, 0}, {0, 100}, {100, 0}, {40, 80}, {125, -10}, ArcLineIntersectExp {{98, 18}, 1.387F}},
{{0, 0}, {0, 100}, {100, 0}, {40, 80}, {80, 20}, std::nullopt},
- {{0, 0}, {0, 100}, {100, 0}, {40, 80}, {80, 80}, GlobalPosition2D {60, 80}},
- {{0, 0}, {0, 100}, {100, 0}, {80, 40}, {80, 80}, GlobalPosition2D {80, 60}},
+ {{0, 0}, {0, 100}, {100, 0}, {40, 80}, {80, 80}, ArcLineIntersectExp {{60, 80}, 0.6435F}},
+ {{0, 0}, {0, 100}, {100, 0}, {80, 40}, {80, 80}, ArcLineIntersectExp {{80, 60}, 0.9273F}},
{{310002000, 490203000}, {310202000, 490203000}, {310002000, 490003000}, {310200000, 490150000},
- {310150000, 490150000}, GlobalPosition2D {310194850, 490150000}},
+ {310150000, 490150000}, ArcLineIntersectExp {{310194850, 490150000}, 1.839F}},
}),
- centre, arcStart, arcEnd, lineStart, lineEnd, intersection)
+ centre, arcStart, arcEnd, lineStart, lineEnd, expected)
{
const ArcSegment arc {centre, arcStart, arcEnd};
BOOST_TEST_INFO(arc.first);
BOOST_TEST_INFO(arc.second);
BOOST_TEST_INFO(arc.length());
- BOOST_CHECK_EQUAL(arc.crossesLineAt(lineStart, lineEnd), intersection);
+ const auto intersection = arc.crossesLineAt(lineStart, lineEnd);
+ BOOST_REQUIRE_EQUAL(expected.has_value(), intersection.has_value());
+ if (expected.has_value()) {
+ BOOST_CHECK_EQUAL(expected->first, intersection->first);
+ BOOST_CHECK_CLOSE(expected->second, intersection->second, 1.F);
+ }
}