siderust/coordinates/transform/
to_spherical.rs1use crate::units::Degrees;
2use crate::coordinates::{
3 CartesianCoord, SphericalCoord,
4 centers::*, frames::*, SphericalBuilder
5};
6
7impl<Center, Frame> From<&CartesianCoord<Center, Frame>> for SphericalCoord<Center, Frame>
21where
22 Center: ReferenceCenter,
23 Frame: ReferenceFrame,
24 SphericalCoord<Center, Frame>: SphericalBuilder<Center, Frame>,
25{
26 fn from(cart: &CartesianCoord<Center, Frame>) -> Self {
27 let r = cart.distance_from_origin();
28 if r == 0.0 {
29 return SphericalCoord::<Center, Frame>::build(
30 Degrees::new(0.0),
31 Degrees::new(0.0),
32 0.0
33 );
34 }
35
36 let polar = Degrees::new(cart.y().atan2(cart.x()).to_degrees());
37 let azimuth = Degrees::new((cart.z() / r).asin().to_degrees());
38
39 SphericalCoord::<Center, Frame>::build(polar, azimuth, r)
40 }
41}
42
43impl<Center, Frame> CartesianCoord<Center, Frame>
44where
45 Center: ReferenceCenter,
46 Frame: ReferenceFrame,
47 SphericalCoord<Center, Frame>: SphericalBuilder<Center, Frame>,
48{
49 pub fn to_spherical(&self) -> SphericalCoord<Center, Frame> {
51 self.into()
52 }
53
54 pub fn from_spherical(sph: &SphericalCoord<Center, Frame>) -> Self {
56 sph.into()
57 }
58}
59
60#[cfg(test)]
61mod tests {
62 use super::*;
63 use crate::units::Degrees;
64
65 #[test]
66 fn test_cartesian_to_spherical() {
67 let cart = CartesianCoord::<Geocentric, ICRS>::new(1.0, 1.0, 1.0);
68 let sph: SphericalCoord<Geocentric, ICRS> = cart.to_spherical();
69
70 assert!((sph.radial_distance - 1.7320508075688772).abs() < 1e-6);
71 assert!((sph.azimuth - Degrees::new(45.0)).abs() < Degrees::new(1e-6));
72 assert!((sph.polar - Degrees::new(35.26438968275466)).abs() < Degrees::new(1e-6));
73 }
74
75 #[test]
76 fn test_spherical_to_cartesian() {
77 let sph = SphericalCoord::<Geocentric, ICRS>::new(
78 Degrees::new(45.0),
79 Degrees::new(35.26438968275466),
80 1.7320508075688772,
81 );
82 let cart: CartesianCoord<Geocentric, ICRS> = CartesianCoord::from_spherical(&sph);
83
84 assert!((cart.x() - 1.0).abs() < 1e-6);
85 assert!((cart.y() - 1.0).abs() < 1e-6);
86 assert!((cart.z() - 1.0).abs() < 1e-6);
87 }
88
89 #[test]
90 fn test_cartesian_spherical_round_trip() {
91 let cart_original = CartesianCoord::<Geocentric, ICRS>::new(2.0, 3.0, 4.0,);
92 let sph = cart_original.to_spherical();
93 let cart_converted = CartesianCoord::from_spherical(&sph);
94
95 assert!((cart_original.x() - cart_converted.x()).abs() < 1e-6);
96 assert!((cart_original.y() - cart_converted.y()).abs() < 1e-6);
97 assert!((cart_original.z() - cart_converted.z()).abs() < 1e-6);
98 }
99
100 #[test]
101 fn test_spherical_cartesian_round_trip() {
102 let sph_original = SphericalCoord::<Geocentric, ICRS>::new(
103 Degrees::new(30.0),
104 Degrees::new(60.0),
105 5.0,
106 );
107 let cart = CartesianCoord::from_spherical(&sph_original);
108 let sph_converted = cart.to_spherical();
109
110 assert!((sph_original.radial_distance - sph_converted.radial_distance).abs() < 1e-6);
111 assert!((sph_original.azimuth - sph_converted.azimuth).abs() < Degrees::new(1e-6));
112 assert!((sph_original.polar - sph_converted.polar).abs() < Degrees::new(1e-6));
113 }
114}