From 09dbb2125c7051d40d9c0ae68f4a93f19c0e182d Mon Sep 17 00:00:00 2001 From: Pandicon <70060103+Pandicon@users.noreply.github.com> Date: Wed, 2 Oct 2024 21:29:13 +0200 Subject: [PATCH 1/3] Add a function to get the distance between two points --- src/point.rs | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/point.rs b/src/point.rs index 15e311c..81fc350 100644 --- a/src/point.rs +++ b/src/point.rs @@ -92,6 +92,15 @@ impl SphericalPoint { (1.0 - cos_angle) < tolerance.powi(2) } + /// Calculates the angular distance between the points + /// + /// If you need to sort points by distance, but do not need the actual angular values for each of them, consider using `SphericalPoint::minus_cotan_distance` + pub fn distance(&self, other: &Self) -> f32 { + let angle_sin = self.cartesian().cross(&other.cartesian()).magnitude(); + let angle_cos = self.cartesian().dot(&other.cartesian()); + angle_sin.atan2(angle_cos) + } + /// Calculates `-1/tan(distance between points)` /// /// Useful when sorting points based on distance without needing to know the actual distance as it avoid inverse trigonometric functions. `-1/tan(x)` is increasing for `0 < x < pi`, which is (more than) the needed range @@ -207,4 +216,29 @@ mod tests { } } } + + #[test] + fn distance() { + let tolerance = 10e-6; + + let point_1_1 = SphericalPoint::new(0.0, 0.0); + let point_1_2 = SphericalPoint::new(0.0, PI / 2.0); + let distance_1 = PI / 2.0; + assert!((point_1_1.distance(&point_1_2) - distance_1).abs() < tolerance); + + let point_2_1 = SphericalPoint::new(0.0, 0.0); + let point_2_2 = SphericalPoint::new(PI / 2.0, 0.0); + let distance_2 = PI / 2.0; + assert!((point_2_1.distance(&point_2_2) - distance_2).abs() < tolerance); + + let point_3_1 = SphericalPoint::new(PI / 3.0, PI / 6.0); + let point_3_2 = SphericalPoint::new(PI / 3.0 + PI, -PI / 6.0); + let distance_3 = PI; + assert!((point_3_1.distance(&point_3_2) - distance_3).abs() < tolerance); + + let point_4_1 = SphericalPoint::new(PI / 3.0, PI / 6.0); + let point_4_2 = SphericalPoint::new(250.0 * PI / 180.0, -25.0 * PI / 180.0); + let distance_4 = 169.824266 * PI / 180.0; + assert!((point_4_1.distance(&point_4_2) - distance_4).abs() < tolerance); + } } From 3110f74be394555d57c5038ac4e4b0625f254e94 Mon Sep 17 00:00:00 2001 From: Pandicon <70060103+Pandicon@users.noreply.github.com> Date: Wed, 2 Oct 2024 21:30:43 +0200 Subject: [PATCH 2/3] Change the status of Points implementation in README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e16ef05..320136e 100644 --- a/README.md +++ b/README.md @@ -48,11 +48,11 @@ State key: | Feature | State | |----------------------------------------------------------------------------------------------------------|:-----:| -| **Points** | 🟡 | +| **Points** | 🟢 | | Spherical ↔ Cartesian conversion | 🟢 | | (Approximate) equality check | 🟢 | | Distance between points (metric) | 🟢 | -| Distance between points (angular value) | 🔴 | +| Distance between points (angular value) | 🟢 | | **Great circles** | 🟡 | | Construction from two points | 🟢 | | Construction from an arc | 🟢 | From 15c0d865c14fcef5a948310ca902788f458958d8 Mon Sep 17 00:00:00 2001 From: Pandicon <70060103+Pandicon@users.noreply.github.com> Date: Wed, 2 Oct 2024 22:00:31 +0200 Subject: [PATCH 3/3] Fix the cargo clippy complaint and add a test case There were no tests covering distances below pi/2 radians --- src/point.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/point.rs b/src/point.rs index 81fc350..66b78ab 100644 --- a/src/point.rs +++ b/src/point.rs @@ -238,7 +238,13 @@ mod tests { let point_4_1 = SphericalPoint::new(PI / 3.0, PI / 6.0); let point_4_2 = SphericalPoint::new(250.0 * PI / 180.0, -25.0 * PI / 180.0); - let distance_4 = 169.824266 * PI / 180.0; + let distance_4 = 169.82426 * PI / 180.0; assert!((point_4_1.distance(&point_4_2) - distance_4).abs() < tolerance); + + let point_5_1 = SphericalPoint::new(PI / 12.0, PI / 9.0); + let point_5_2 = SphericalPoint::new(PI / 4.0, -PI / 15.0); + println!("{}", point_5_1.distance(&point_5_2)); + let distance_5 = 43.53911 * PI / 180.0; + assert!((point_5_1.distance(&point_5_2) - distance_5).abs() < tolerance); } }