|
38 | 38 | //! * "Transformation from Cartesian to Geodetic Coordinates Accelerated by |
39 | 39 | //! Halley’s Method", T. Fukushima (2006), Journal of Geodesy. |
40 | 40 | use crate::c_bindings; |
41 | | -use std::marker::PhantomData; |
42 | | -/// Tag trait for denoting ways of representing angles |
43 | | -pub trait Angle {} |
44 | 41 |
|
45 | | -/// Tag type for denoting angles in units of degrees |
46 | | -pub struct Degrees {} |
47 | | -impl Angle for Degrees {} |
48 | | - |
49 | | -/// Tag type for denoting angles in units of radians |
50 | | -pub struct Radians {} |
51 | | -impl Angle for Radians {} |
52 | | - |
53 | | -/// WGS84 geodetic coordinates (Latitude, Longitude, Height). |
| 42 | +/// WGS84 geodetic coordinates (Latitude, Longitude, Height) |
54 | 43 | /// |
55 | 44 | /// Internally stored as an array of 3 [f64](std::f64) values: latitude, longitude (both in the given angular units) and height above the geoid in meters |
56 | 45 | #[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] |
57 | | -pub struct LLH<T: Angle>([f64; 3], PhantomData<T>); |
| 46 | +pub struct LLHDegrees([f64; 3]); |
58 | 47 |
|
59 | | -impl<T: Angle> LLH<T> { |
60 | | - pub fn new(lat: f64, lon: f64, height: f64) -> LLH<T> { |
61 | | - LLH([lat, lon, height], PhantomData) |
| 48 | +impl LLHDegrees { |
| 49 | + pub fn new(lat: f64, lon: f64, height: f64) -> LLHDegrees { |
| 50 | + LLHDegrees([lat, lon, height]) |
62 | 51 | } |
63 | 52 |
|
64 | | - pub fn from_array(array: &[f64; 3]) -> LLH<T> { |
65 | | - LLH(*array, PhantomData) |
| 53 | + pub fn from_array(array: &[f64; 3]) -> LLHDegrees { |
| 54 | + LLHDegrees(*array) |
66 | 55 | } |
67 | 56 |
|
68 | 57 | pub fn as_ptr(&self) -> *const [f64; 3] { |
@@ -92,62 +81,144 @@ impl<T: Angle> LLH<T> { |
92 | 81 | pub fn height(&self) -> f64 { |
93 | 82 | self.0[2] |
94 | 83 | } |
95 | | -} |
96 | 84 |
|
97 | | -impl LLH<Radians> { |
98 | | - /// Converts a LLH position from radians to degrees. The position doesn't change, |
| 85 | + /// Converts a LLH position from degrees to radians. The position doesn't change, |
99 | 86 | /// just the representation of the angular values. |
100 | | - pub fn to_degrees(&self) -> LLH<Degrees> { |
101 | | - let mut deg = LLH::<Degrees>::from_array(&[0.0; 3]); |
102 | | - unsafe { c_bindings::llhrad2deg(self.as_ptr(), deg.as_mut_ptr()) }; |
103 | | - deg |
| 87 | + pub fn to_radians(&self) -> LLHRadians { |
| 88 | + let mut rad = LLHRadians::default(); |
| 89 | + unsafe { c_bindings::llhdeg2rad(self.as_ptr(), rad.as_mut_ptr()) }; |
| 90 | + rad |
104 | 91 | } |
105 | 92 |
|
106 | 93 | /// Converts from WGS84 geodetic coordinates (latitude, longitude and height) |
107 | 94 | /// into WGS84 Earth Centered, Earth Fixed Cartesian (ECEF) coordinates |
108 | 95 | /// (X, Y and Z). |
109 | 96 | pub fn to_ecef(&self) -> ECEF { |
110 | | - let mut ecef = ECEF::from_array(&[0.0; 3]); |
111 | | - unsafe { c_bindings::wgsllh2ecef(self.as_ptr(), ecef.as_mut_ptr()) }; |
112 | | - ecef |
| 97 | + self.to_radians().to_ecef() |
113 | 98 | } |
114 | 99 | } |
115 | 100 |
|
116 | | -impl LLH<Degrees> { |
117 | | - /// Converts a LLH position from degrees to radians. The position doesn't change, |
| 101 | +impl Default for LLHDegrees { |
| 102 | + fn default() -> LLHDegrees { |
| 103 | + LLHDegrees::new(0., 0., 0.) |
| 104 | + } |
| 105 | +} |
| 106 | + |
| 107 | +impl AsRef<[f64; 3]> for LLHDegrees { |
| 108 | + fn as_ref(&self) -> &[f64; 3] { |
| 109 | + &self.0 |
| 110 | + } |
| 111 | +} |
| 112 | + |
| 113 | +impl AsMut<[f64; 3]> for LLHDegrees { |
| 114 | + fn as_mut(&mut self) -> &mut [f64; 3] { |
| 115 | + &mut self.0 |
| 116 | + } |
| 117 | +} |
| 118 | + |
| 119 | +impl From<LLHDegrees> for LLHRadians { |
| 120 | + fn from(deg: LLHDegrees) -> LLHRadians { |
| 121 | + deg.to_radians() |
| 122 | + } |
| 123 | +} |
| 124 | + |
| 125 | +impl From<ECEF> for LLHRadians { |
| 126 | + fn from(ecef: ECEF) -> LLHRadians { |
| 127 | + ecef.to_llh() |
| 128 | + } |
| 129 | +} |
| 130 | + |
| 131 | +/// WGS84 geodetic coordinates (Latitude, Longitude, Height). |
| 132 | +/// |
| 133 | +/// Internally stored as an array of 3 [f64](std::f64) values: latitude, longitude (both in the given angular units) and height above the geoid in meters |
| 134 | +#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] |
| 135 | +pub struct LLHRadians([f64; 3]); |
| 136 | + |
| 137 | +impl LLHRadians { |
| 138 | + pub fn new(lat: f64, lon: f64, height: f64) -> LLHRadians { |
| 139 | + LLHRadians([lat, lon, height]) |
| 140 | + } |
| 141 | + |
| 142 | + pub fn from_array(array: &[f64; 3]) -> LLHRadians { |
| 143 | + LLHRadians(*array) |
| 144 | + } |
| 145 | + |
| 146 | + pub fn as_ptr(&self) -> *const [f64; 3] { |
| 147 | + &self.0 |
| 148 | + } |
| 149 | + |
| 150 | + pub fn as_mut_ptr(&mut self) -> *mut [f64; 3] { |
| 151 | + &mut self.0 |
| 152 | + } |
| 153 | + |
| 154 | + pub fn as_array_ref(&self) -> &[f64; 3] { |
| 155 | + &self.0 |
| 156 | + } |
| 157 | + |
| 158 | + pub fn as_mut_array_ref(&mut self) -> &mut [f64; 3] { |
| 159 | + &mut self.0 |
| 160 | + } |
| 161 | + |
| 162 | + pub fn latitude(&self) -> f64 { |
| 163 | + self.0[0] |
| 164 | + } |
| 165 | + |
| 166 | + pub fn longitude(&self) -> f64 { |
| 167 | + self.0[1] |
| 168 | + } |
| 169 | + |
| 170 | + pub fn height(&self) -> f64 { |
| 171 | + self.0[2] |
| 172 | + } |
| 173 | + |
| 174 | + /// Converts a LLH position from radians to degrees. The position doesn't change, |
118 | 175 | /// just the representation of the angular values. |
119 | | - pub fn to_radians(&self) -> LLH<Radians> { |
120 | | - let mut rad = LLH::<Radians>::from_array(&[0.0; 3]); |
121 | | - unsafe { c_bindings::llhdeg2rad(self.as_ptr(), rad.as_mut_ptr()) }; |
122 | | - rad |
| 176 | + pub fn to_degrees(&self) -> LLHDegrees { |
| 177 | + let mut deg = LLHDegrees::default(); |
| 178 | + unsafe { c_bindings::llhrad2deg(self.as_ptr(), deg.as_mut_ptr()) }; |
| 179 | + deg |
123 | 180 | } |
124 | 181 |
|
125 | 182 | /// Converts from WGS84 geodetic coordinates (latitude, longitude and height) |
126 | 183 | /// into WGS84 Earth Centered, Earth Fixed Cartesian (ECEF) coordinates |
127 | 184 | /// (X, Y and Z). |
128 | 185 | pub fn to_ecef(&self) -> ECEF { |
129 | | - self.to_radians().to_ecef() |
| 186 | + let mut ecef = ECEF::default(); |
| 187 | + unsafe { c_bindings::wgsllh2ecef(self.as_ptr(), ecef.as_mut_ptr()) }; |
| 188 | + ecef |
130 | 189 | } |
131 | 190 | } |
132 | 191 |
|
133 | | -impl<T: Angle> Default for LLH<T> { |
134 | | - fn default() -> Self { |
135 | | - Self::new(0., 0., 0.) |
| 192 | +impl Default for LLHRadians { |
| 193 | + fn default() -> LLHRadians { |
| 194 | + LLHRadians::new(0., 0., 0.) |
136 | 195 | } |
137 | 196 | } |
138 | 197 |
|
139 | | -impl<T: Angle> AsRef<[f64; 3]> for LLH<T> { |
| 198 | +impl AsRef<[f64; 3]> for LLHRadians { |
140 | 199 | fn as_ref(&self) -> &[f64; 3] { |
141 | 200 | &self.0 |
142 | 201 | } |
143 | 202 | } |
144 | 203 |
|
145 | | -impl<T: Angle> AsMut<[f64; 3]> for LLH<T> { |
| 204 | +impl AsMut<[f64; 3]> for LLHRadians { |
146 | 205 | fn as_mut(&mut self) -> &mut [f64; 3] { |
147 | 206 | &mut self.0 |
148 | 207 | } |
149 | 208 | } |
150 | 209 |
|
| 210 | +impl From<LLHRadians> for LLHDegrees { |
| 211 | + fn from(rad: LLHRadians) -> LLHDegrees { |
| 212 | + rad.to_degrees() |
| 213 | + } |
| 214 | +} |
| 215 | + |
| 216 | +impl From<ECEF> for LLHDegrees { |
| 217 | + fn from(ecef: ECEF) -> LLHDegrees { |
| 218 | + ecef.to_llh().to_degrees() |
| 219 | + } |
| 220 | +} |
| 221 | + |
151 | 222 | /// WGS84 Earth Centered, Earth Fixed (ECEF) Cartesian coordinates (X, Y, Z). |
152 | 223 | /// |
153 | 224 | /// Internally stored as an array of 3 [f64](std::f64) values: x, y, z all in meters |
@@ -194,8 +265,8 @@ impl ECEF { |
194 | 265 | /// Converts from WGS84 Earth Centered, Earth Fixed (ECEF) Cartesian |
195 | 266 | /// coordinates (X, Y and Z) into WGS84 geodetic coordinates (latitude, |
196 | 267 | /// longitude and height). |
197 | | - pub fn to_llh(&self) -> LLH<Radians> { |
198 | | - let mut llh = LLH::<Radians>::from_array(&[0.0; 3]); |
| 268 | + pub fn to_llh(&self) -> LLHRadians { |
| 269 | + let mut llh = LLHRadians::from_array(&[0.0; 3]); |
199 | 270 | unsafe { c_bindings::wgsecef2llh(self.as_ptr(), llh.as_mut_ptr()) }; |
200 | 271 | llh |
201 | 272 | } |
@@ -266,32 +337,32 @@ mod tests { |
266 | 337 |
|
267 | 338 | #[test] |
268 | 339 | fn llhrad2deg() { |
269 | | - let zeros = LLH::<Radians>::from_array(&[0.0; 3]); |
| 340 | + let zeros = LLHRadians::from_array(&[0.0; 3]); |
270 | 341 |
|
271 | 342 | let deg = zeros.to_degrees(); |
272 | 343 | assert_eq!(0.0, deg.latitude()); |
273 | 344 | assert_eq!(0.0, deg.longitude()); |
274 | 345 | assert_eq!(0.0, deg.height()); |
275 | 346 |
|
276 | | - let swift_home = LLH::<Degrees>::from_array(&[37.779804, -122.391751, 60.0]); |
| 347 | + let swift_home = LLHDegrees::from_array(&[37.779804, -122.391751, 60.0]); |
277 | 348 | let rads = swift_home.to_radians(); |
278 | 349 |
|
279 | 350 | assert!((rads.latitude() - 0.659381970558).abs() < MAX_ANGLE_ERROR_RAD); |
280 | 351 | assert!((rads.longitude() + 2.136139032231).abs() < MAX_ANGLE_ERROR_RAD); |
281 | 352 | assert!(rads.height() == swift_home.height()); |
282 | 353 | } |
283 | 354 |
|
284 | | - const LLH_VALUES: [LLH<Radians>; 10] = [ |
285 | | - LLH::<Radians>([0.0, 0.0, 0.0], PhantomData), /* On the Equator and Prime Meridian. */ |
286 | | - LLH::<Radians>([0.0, 180.0 * D2R, 0.0], PhantomData), /* On the Equator. */ |
287 | | - LLH::<Radians>([0.0, 90.0 * D2R, 0.0], PhantomData), /* On the Equator. */ |
288 | | - LLH::<Radians>([0.0, -90.0 * D2R, 0.0], PhantomData), /* On the Equator. */ |
289 | | - LLH::<Radians>([90.0 * D2R, 0.0, 0.0], PhantomData), /* North pole. */ |
290 | | - LLH::<Radians>([-90.0 * D2R, 0.0, 0.0], PhantomData), /* South pole. */ |
291 | | - LLH::<Radians>([90.0 * D2R, 0.0, 22.0], PhantomData), /* 22m above the north pole. */ |
292 | | - LLH::<Radians>([-90.0 * D2R, 0.0, 22.0], PhantomData), /* 22m above the south pole. */ |
293 | | - LLH::<Radians>([0.0, 0.0, 22.0], PhantomData), /* 22m above the Equator and Prime Meridian. */ |
294 | | - LLH::<Radians>([0.0, 180.0 * D2R, 22.0], PhantomData), /* 22m above the Equator. */ |
| 355 | + const LLH_VALUES: [LLHRadians; 10] = [ |
| 356 | + LLHRadians([0.0, 0.0, 0.0]), /* On the Equator and Prime Meridian. */ |
| 357 | + LLHRadians([0.0, 180.0 * D2R, 0.0]), /* On the Equator. */ |
| 358 | + LLHRadians([0.0, 90.0 * D2R, 0.0]), /* On the Equator. */ |
| 359 | + LLHRadians([0.0, -90.0 * D2R, 0.0]), /* On the Equator. */ |
| 360 | + LLHRadians([90.0 * D2R, 0.0, 0.0]), /* North pole. */ |
| 361 | + LLHRadians([-90.0 * D2R, 0.0, 0.0]), /* South pole. */ |
| 362 | + LLHRadians([90.0 * D2R, 0.0, 22.0]), /* 22m above the north pole. */ |
| 363 | + LLHRadians([-90.0 * D2R, 0.0, 22.0]), /* 22m above the south pole. */ |
| 364 | + LLHRadians([0.0, 0.0, 22.0]), /* 22m above the Equator and Prime Meridian. */ |
| 365 | + LLHRadians([0.0, 180.0 * D2R, 22.0]), /* 22m above the Equator. */ |
295 | 366 | ]; |
296 | 367 |
|
297 | 368 | /* Semi-major axis. */ |
|
0 commit comments