From 646b276a9ba766a7e2acfe2d35e83228afc0d1f7 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 9 Jun 2025 23:26:52 +0100 Subject: Handle edge cases ...where extending a network results in something that can be a straight or collapsed into a single arc from a bi-arc. --- lib/maths.cpp | 9 +++++++++ lib/maths.h | 32 +++++++++++++++----------------- 2 files changed, 24 insertions(+), 17 deletions(-) (limited to 'lib') diff --git a/lib/maths.cpp b/lib/maths.cpp index 000cea7..7dd313e 100644 --- a/lib/maths.cpp +++ b/lib/maths.cpp @@ -1,5 +1,6 @@ #include "maths.h" #include +#include #include #include #include @@ -32,6 +33,7 @@ static_assert(pow(3, 1) == 3); static_assert(pow(3, 2) == 9); static_assert(pow(pi, 3) == 31.006278991699219F); +#ifndef __clang__ static_assert(!linesIntersectAt({0, 10}, {10, 10}, {10, 0}, {0, 0}).has_value()); static_assert(*linesIntersectAt({0, 0}, {10, 10}, {10, 0}, {0, 10}) == GlobalPosition2D {5, 5}); static_assert(*linesIntersectAt({300'000'000, 400'000'00}, {300'010'000, 400'010'00}, {310'010'000, 410'000'00}, @@ -43,6 +45,13 @@ constexpr auto EAST2D = RelativePosition2D(east); static_assert(!linesIntersectAtDirs({0, 0}, NORTH2D, {10, 10}, NORTH2D).has_value()); static_assert(linesIntersectAtDirs({0, 0}, NORTH2D, {10, 10}, EAST2D) == GlobalPosition2D {0, 10}); static_assert(linesIntersectAtDirs({0, 0}, EAST2D, {10, 10}, NORTH2D) == GlobalPosition2D {10, 0}); + +static_assert(find_arc_centre({0, 0}, -NORTH2D, {10, 10}) == std::make_pair({10, 0}, 10.F)); +static_assert(find_arc_centre({20, 0}, -NORTH2D, {10, 10}) == std::make_pair({10, 0}, -10.F)); +static_assert(find_arc_centre({10, 0}, -NORTH2D, {10, 10}).second == 0.F); +static_assert(isWithinLimit(find_arc_centre({0, 0}, pi + quarter_pi, {1000, 1000}).second, 0.F, 0.1F)); +#endif + // NOLINTEND(readability-magic-numbers) float diff --git a/lib/maths.h b/lib/maths.h index 93a4322..09af048 100644 --- a/lib/maths.h +++ b/lib/maths.h @@ -427,38 +427,36 @@ linesIntersectAt(const glm::vec<2, T, Q> Aabs, const glm::vec<2, T, Q> Babs, con template constexpr auto EPSILON = 0.0001F; template -auto +[[nodiscard]] constexpr auto isWithinLimit(T lhs, T rhs, T limit = EPSILON) { return std::abs(lhs - rhs) <= limit; } -template -std::pair, bool> -find_arc_centre(glm::vec<2, T, Q> start, Angle entrys, glm::vec<2, T, Q> end, Angle entrye) +template +constexpr std::pair, D> +find_arc_centre(glm::vec<2, T, Q> start, glm::vec<2, D, Q> entrys, glm::vec<2, T, Q> end) { if (start == end) { - return {start, false}; + return {start, 0}; } - return find_arc_centre(start, sincos(entrys + half_pi), end, sincos(entrye - half_pi)); + const auto diffEnds = difference(end, start); + const auto offset = entrys.x * diffEnds.y - entrys.y * diffEnds.x; + if (offset == 0.F) { + return {start, offset}; + } + const auto midEnds = start + ((end - start) / 2); + const auto centre = linesIntersectAtDirs(start, vector_normal(entrys), midEnds, vector_normal(diffEnds)); + return {*centre, offset}; } template -std::pair, bool> +constexpr std::pair, float> find_arc_centre(glm::vec<2, T, Q> start, Angle entrys, glm::vec<2, T, Q> end) { - if (start == end) { - return {start, false}; - } - const auto startNormal = vector_normal(sincos(entrys) * 10'000.F); - const auto diffEnds = difference(end, start); - const auto midEnds = start + ((end - start) / 2); - const auto diffNormal = vector_normal(diffEnds); - const auto centre = linesIntersectAt(start, start + startNormal, midEnds, midEnds + diffNormal); - return {*centre, normalize(vector_yaw(diffEnds) - entrys) < 0}; + return find_arc_centre(start, sincos(entrys), end); } - template auto midpoint(const std::pair & v) -- cgit v1.2.3