From 3758efac4cf6bab2dd65e51d26f63c704923e030 Mon Sep 17 00:00:00 2001 From: CLIDragon <84266961+CLIDragon@users.noreply.github.com> Date: Mon, 26 Aug 2024 15:32:02 +1000 Subject: [PATCH 1/2] Add octile distance for tripoints. Part of #74945. This will allow for better vertical pathfinding calculations, allowing flying monsters to actually fly. --- src/coordinates.h | 8 ++++++++ src/line.cpp | 13 +++++++++++++ src/line.h | 3 ++- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/coordinates.h b/src/coordinates.h index db63fd93a0d83..d67a5f7357962 100644 --- a/src/coordinates.h +++ b/src/coordinates.h @@ -840,6 +840,14 @@ inline int octile_dist( const coords::coord_point_ob &loc1 return octile_dist( loc1.raw(), loc2.raw(), multiplier ); } + +template +inline float octile_dist_exact( const coords::coord_point &loc1, + const coords::coord_point &loc2 ) +{ + return octile_dist_exact( loc1.raw(), loc2.raw() ); +} + template direction direction_from( const coords::coord_point_ob &loc1, const coords::coord_point_ob &loc2 ) diff --git a/src/line.cpp b/src/line.cpp index 5cb1f7fee16cb..5eb8899c14b33 100644 --- a/src/line.cpp +++ b/src/line.cpp @@ -284,6 +284,19 @@ float octile_dist_exact( const point &loc1, const point &loc2 ) return d.x + d.y - 2 * mind + mind * M_SQRT2; } +float octile_dist_exact( const tripoint &from, const tripoint &to ) +{ + const tripoint d = ( from - to ).abs(); + const int min = std::min( d.x, std::min( d.y, d.z ) ); + const int max = std::max( d.x, std::max( d.y, d.z ) ); + const int mid = d.x + d.y + d.z - min - max; + + constexpr int one_axis = 1; + constexpr float two_axis = M_SQRT2; + constexpr float three_axis = 1.73205f; + return ( three_axis - two_axis ) * min + ( two_axis - one_axis ) * mid + one_axis * max; +} + units::angle atan2( const point &p ) { return units::atan2( p.y, p.x ); diff --git a/src/line.h b/src/line.h index cb06ee1bbb6dd..0da0ed633d2ff 100644 --- a/src/line.h +++ b/src/line.h @@ -254,9 +254,10 @@ float rl_dist_exact( const tripoint &loc1, const tripoint &loc2 ); int manhattan_dist( const point &loc1, const point &loc2 ); // Travel distance between 2 points on a square grid, assuming diagonal moves -// cost sqrt(2) and cardinal moves cost 1. +// cost sqrt(2) or sqrt(3) and cardinal moves cost 1. int octile_dist( const point &loc1, const point &loc2, int multiplier = 1 ); float octile_dist_exact( const point &loc1, const point &loc2 ); +float octile_dist_exact( const tripoint &from, const tripoint &to ); // get angle of direction represented by point units::angle atan2( const point & ); From 0dc33d64b50f486cfd981c5d5e170fe7741fab78 Mon Sep 17 00:00:00 2001 From: CLIDragon <84266961+CLIDragon@users.noreply.github.com> Date: Thu, 7 Nov 2024 17:59:01 +1000 Subject: [PATCH 2/2] Add tests for octile_dist_exact. --- tests/line_test.cpp | 49 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/tests/line_test.cpp b/tests/line_test.cpp index 59f531570fee6..360809dd63f93 100644 --- a/tests/line_test.cpp +++ b/tests/line_test.cpp @@ -465,3 +465,52 @@ TEST_CASE( "coord_point_line_to_consistency", "[point][coords][line]" ) CHECK( raw_line[i] == coord_line[i].raw() ); } } + +TEST_CASE( "octile_dist_exact_tripoints" ) +{ + constexpr int one_axis = 1; + constexpr float two_axis = M_SQRT2; + constexpr float three_axis = 1.73205f; + constexpr float eps = 0.05f; + + // Check that unit distances are all correct. + CHECK( octile_dist_exact( tripoint{ 0, 0, 0 }, tripoint{ 0, 0, 0 } ) == 0 ); + CHECK_THAT( octile_dist_exact( tripoint{ 0, 0, 0 }, tripoint{ 0, 0, 1 } ), + Catch::Matchers::WithinRel( one_axis, eps ) ); + CHECK_THAT( octile_dist_exact( tripoint{ 0, 0, 0 }, tripoint{ 0, 1, 0 } ), + Catch::Matchers::WithinRel( one_axis, eps ) ); + CHECK_THAT( octile_dist_exact( tripoint{ 0, 0, 0 }, tripoint{ 1, 0, 0 } ), + Catch::Matchers::WithinRel( one_axis, eps ) ); + CHECK_THAT( octile_dist_exact( tripoint{ 10, 30, 20 }, tripoint{ 11, 30, 20 } ), + Catch::Matchers::WithinRel( 1, eps ) ); + CHECK_THAT( octile_dist_exact( tripoint{ 10, 30, 20 }, tripoint{ 10, 31, 20 } ), + Catch::Matchers::WithinRel( 1, eps ) ); + CHECK_THAT( octile_dist_exact( tripoint{ 10, 30, 21 }, tripoint{ 10, 30, 21 } ), + Catch::Matchers::WithinRel( 1, eps ) ); + + // Check that 2d unit distances are correct. + CHECK_THAT( octile_dist_exact( tripoint{ 0, 0, 0 }, tripoint{ 0, 1, 1 } ), + Catch::Matchers::WithinRel( two_axis, eps ) ); + CHECK_THAT( octile_dist_exact( tripoint{ 0, 0, 0 }, tripoint{ 1, 0, 1 } ), + Catch::Matchers::WithinRel( two_axis, eps ) ); + CHECK_THAT( octile_dist_exact( tripoint{ 0, 0, 0 }, tripoint{ 1, 1, 0 } ), + Catch::Matchers::WithinRel( two_axis, eps ) ); + + // Check that 3d unit distances are correct. + CHECK_THAT( octile_dist_exact( tripoint{ 0, 0, 0 }, tripoint{ 1, 1, 1 } ), + Catch::Matchers::WithinRel( three_axis, eps ) ); + CHECK_THAT( octile_dist_exact( tripoint{ 2, 4, 6 }, tripoint{ 3, 5, 7 } ), + Catch::Matchers::WithinRel( three_axis, eps ) ); + CHECK_THAT( octile_dist_exact( tripoint{ 26, 32, 75 }, tripoint{ 27, 33, 76 } ), + Catch::Matchers::WithinRel( three_axis, eps ) ); + + // Check a few non-unit distances. + CHECK_THAT( octile_dist_exact( tripoint{ 0, 0, 0 }, tripoint{ 2, 2, 0 } ), + Catch::Matchers::WithinRel( 2 * two_axis, eps ) ); + CHECK_THAT( octile_dist_exact( tripoint{ 1, 2, 3 }, tripoint{ 4, 1, 2 } ), + Catch::Matchers::WithinRel( 3.316f, eps ) ); + CHECK_THAT( octile_dist_exact( tripoint{ 6, 9, 4 }, tripoint{ 8, 1, 1 } ), + Catch::Matchers::WithinRel( 8.775f, eps ) ); + CHECK_THAT( octile_dist_exact( tripoint{ -3, -6, -2 }, tripoint{ -10, -8, 4 } ), + Catch::Matchers::WithinRel( 9.434f, eps ) ); +}