--- a/src/cylinder.rs Fri Dec 06 14:27:14 2024 -0500 +++ b/src/cylinder.rs Fri Dec 06 14:57:11 2024 -0500 @@ -23,12 +23,14 @@ } impl CylCoords { + /// Convert to cartesian coordinates. #[inline] pub fn to_cartesian(&self) -> Loc<f64, 3> { let &CylCoords{r, angle, z} = self; [r * angle.cos(), r * angle.sin(), z].into() } + /// Form cylindrical coordinates from cartesian coordinates. #[inline] #[allow(dead_code)] pub fn from_cartesian(coords : Loc<f64, 3>) -> Self { @@ -131,6 +133,7 @@ pub angle : Angle } +/// Calculates the difference between two angles, normalised to [–π, π]. #[inline] fn anglediff(mut φ1 : f64, mut φ2 : f64) -> f64 { let π = f64::PI; @@ -152,6 +155,7 @@ } } +/// Normalises an angle to [0, 2π]. #[inline] pub fn normalise_angle(φ : f64) -> f64 { let π = f64::PI; @@ -209,7 +213,7 @@ } -/// Point on a [`Cylinder`] +/// Point on some [`Cylinder`] #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum Point { Top(CapPoint), @@ -226,16 +230,20 @@ Side, } +/// Point on a specific [`Cylinder`] #[derive(Clone, Debug, PartialEq)] pub struct OnCylinder<'a> { + /// Face and coordinates of the point + point : Point, + /// The specific cylinder the `point` lies on. cylinder : &'a Cylinder, - point : Point, } /// Cylinder configuration #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct CylinderConfig { + /// Number of Newton iterates two take to solve geodesics. pub newton_iters : usize, } @@ -270,6 +278,7 @@ } impl Point { + /// Returns the face of the point fn face(&self) -> Face { match *self { Point::Top(..) => Face::Top, @@ -290,6 +299,8 @@ // Tangent vector type Tangent = Loc<f64, 2>; +/// Goes through list of potential tangents (corresponding to several geodesics taking +/// different paths), and retuns the shortest tangent vector and the corresponding length. #[inline] fn best_tangent<I>(tangents : I) -> (Tangent, f64) where I : IntoIterator<Item = Tangent> { @@ -305,6 +316,7 @@ (b, a) } +/// Indicates whether the `a` and `b` are a distance of less than [`f64::EPSILON`]. #[inline] fn indistinguishable(a : f64, b : f64) -> bool { a > b - f64::EPSILON && a < b + f64::EPSILON @@ -320,11 +332,13 @@ } } + /// Returns the z coordinate of the top (cap) of the cylinder. #[inline] pub fn top_z(&self) -> f64 { self.height / 2.0 } + /// Returns the z coordinate of the bottom (cap) of the cylinder. #[inline] pub fn bottom_z(&self) -> f64 { -self.height / 2.0 @@ -332,7 +346,7 @@ /// Find angle where a geodesic from `side` to `(cap, z)` crosses the cap edge. /// - /// Uses `newton_sym1x1`. + /// Uses [`newton_sym1x1`]. fn side_cap_crossing( &self, side : &SidePoint, @@ -372,7 +386,7 @@ /// Find angles where the geodesic passing through a cap at height `z` from `side1` to `side2` /// crosses the cap edge. **Panics if `side2.angle < side1.angle`.** /// - /// Uses `newton_sym2x2`. + /// Uses [`newton_sym2x2`]. fn side_cap_side_crossing( &self, side1 : &SidePoint, @@ -415,7 +429,7 @@ /// to `cap2` at height `z_2` crosses the cap edges. /// **Panics if `cap2.angle < cap1.angle`.** /// - /// Uses `newton_sym2x2`. + /// Uses [`newton_sym2x2`]. fn cap_side_cap_crossing( &self, cap1 : &CapPoint, z_1 : f64, @@ -480,6 +494,9 @@ (normalise_angle(φ_1 + α_1), normalise_angle(φ_2 - α_2)) } + /// Calculates the log between points on a `cap` and a `side` of the cylinder, in this direction. + /// The `z` coordinate of the cap and an indication whether it is a `top` or bottom cap must + /// also be given. fn cap_side_log( &self, cap : &CapPoint, (z, top) : (f64, bool), @@ -514,6 +531,9 @@ } } + /// Calculates the log between points on a `side` and a `cap` of the cylinder, in this direction. + /// The `z` coordinate of the cap and an indication whether it is a `top` or bottom cap must + /// also be given. fn side_cap_log( &self, side : &SidePoint, @@ -547,6 +567,9 @@ } } + /// Calculates the log between points on two sides of the cylinder, assuming the corresonding + /// geodesic crosses a cap at height `z`. The `top` parameter indicates whether this is a + /// top cap. fn side_cap_side_log( &self, side1 : &SidePoint, @@ -596,6 +619,9 @@ } } + /// Calculates the log between points on two caps of the cylinder, assuming the corresonding + /// geodesic crosses the side. The heights of the caps and indications whether they are + /// top caps, must also be given. fn cap_side_cap_log( &self, cap1 : &CapPoint, (z1, top1) : (f64, bool), @@ -644,7 +670,7 @@ } } - /// Calculates both the logarithmic map and distance to another point + /// Calculates both the logarithmic map and distance between two points. fn log_dist(&self, source : &Point, destination : &Point) -> (Tangent, f64) { use Point::*; match (source, destination) { @@ -706,6 +732,9 @@ } } + /// Calculates the exponential map of `point` in the direction `t` until the next edge. + /// If `t` was fully exhausted before reaching an edge, the second return value is [`None`], + /// otherwise it is a [`Some`] of the remaining tangent, translated at the returned point. #[allow(unreachable_code)] #[allow(unused_variables)] fn partial_exp(&self, point : Point, t : Tangent) -> (Point, Option<Tangent>) { @@ -751,6 +780,7 @@ } } + /// Calculates the exponential map from `point` in the direction of `tangent`. fn exp(&self, point : &Point, tangent : &Tangent) -> Point { let mut p = *point; let mut t = *tangent; @@ -931,8 +961,9 @@ config : CylinderConfig { newton_iters : 20 }, }; + /// Tests for correct distance calculation beween two points on the same cap. #[test] - fn intra_cap_log_dist() { + fn intra_cap_dist() { let π = f64::PI; let p1 = CYL.on_top(0.0, 0.5); let p2 = CYL.on_top(π, 0.5); @@ -943,8 +974,9 @@ check_distance!(p3.dist_to(&p1), 0.5_f64.sqrt()); } + /// Tests for correct distance calculation beween two points on the side. #[test] - fn intra_side_log_dist() { + fn intra_side_dist() { let π = f64::PI; let p1 = CYL.on_side(0.0, 0.0); let p2 = CYL.on_side(0.0, 0.4); @@ -954,8 +986,10 @@ check_distance!(p1.dist_to(&p3), π/2.0*CYL.radius); } + /// Tests for correct distance calculation beween two points on the side, when the corresponding + /// minimal geodesic has to cross a cap. #[test] - fn intra_side_over_cap_log_dist() { + fn intra_side_over_cap_dist() { let π = f64::PI; let off = 0.05; let z = CYL.top_z() - off; @@ -965,8 +999,9 @@ check_distance!(p1.dist_to(&p2), 2.0 * (CYL.radius + off)); } + /// Tests for correct distance calculation between points on top and bottom caps. #[test] - fn top_bottom_log_dist() { + fn top_bottom_dist() { let π = f64::PI; let p1 = CYL.on_top(0.0, 0.0); let p2 = CYL.on_bottom(0.0, 0.0); @@ -981,14 +1016,16 @@ check_distance!(p1.dist_to(&p3), 2.0 * CYL.radius + CYL.height); } + /// Test for correct distance calculation between points on the side and a cap. #[test] - fn top_side_log_dist() { + fn top_side_dist() { let p1 = CYL.on_top(0.0, 0.0); let p2 = CYL.on_side(0.0, 0.0); check_distance!(p1.dist_to(&p2), CYL.radius + CYL.height / 2.0); } + /// Tests for correct tangent calculation from a cap to the side. #[test] fn cap_side_partial_exp() { let π = f64::PI; @@ -1023,6 +1060,7 @@ } } + /// Tests for correct tangent calculation from the side to a cap. #[test] fn side_top_exp() { let π = f64::PI;