|
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