Skip to content

Commit 70f2054

Browse files
committed
Split out LLH coordinate types into separate structs using radians and degrees
1 parent 58d621c commit 70f2054

File tree

1 file changed

+126
-55
lines changed

1 file changed

+126
-55
lines changed

src/coords.rs

Lines changed: 126 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -38,31 +38,20 @@
3838
//! * "Transformation from Cartesian to Geodetic Coordinates Accelerated by
3939
//! Halley’s Method", T. Fukushima (2006), Journal of Geodesy.
4040
use crate::c_bindings;
41-
use std::marker::PhantomData;
42-
/// Tag trait for denoting ways of representing angles
43-
pub trait Angle {}
4441

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)
5443
///
5544
/// 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
5645
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
57-
pub struct LLH<T: Angle>([f64; 3], PhantomData<T>);
46+
pub struct LLHDegrees([f64; 3]);
5847

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])
6251
}
6352

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)
6655
}
6756

6857
pub fn as_ptr(&self) -> *const [f64; 3] {
@@ -92,62 +81,144 @@ impl<T: Angle> LLH<T> {
9281
pub fn height(&self) -> f64 {
9382
self.0[2]
9483
}
95-
}
9684

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,
9986
/// 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
10491
}
10592

10693
/// Converts from WGS84 geodetic coordinates (latitude, longitude and height)
10794
/// into WGS84 Earth Centered, Earth Fixed Cartesian (ECEF) coordinates
10895
/// (X, Y and Z).
10996
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()
11398
}
11499
}
115100

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,
118175
/// 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
123180
}
124181

125182
/// Converts from WGS84 geodetic coordinates (latitude, longitude and height)
126183
/// into WGS84 Earth Centered, Earth Fixed Cartesian (ECEF) coordinates
127184
/// (X, Y and Z).
128185
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
130189
}
131190
}
132191

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.)
136195
}
137196
}
138197

139-
impl<T: Angle> AsRef<[f64; 3]> for LLH<T> {
198+
impl AsRef<[f64; 3]> for LLHRadians {
140199
fn as_ref(&self) -> &[f64; 3] {
141200
&self.0
142201
}
143202
}
144203

145-
impl<T: Angle> AsMut<[f64; 3]> for LLH<T> {
204+
impl AsMut<[f64; 3]> for LLHRadians {
146205
fn as_mut(&mut self) -> &mut [f64; 3] {
147206
&mut self.0
148207
}
149208
}
150209

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+
151222
/// WGS84 Earth Centered, Earth Fixed (ECEF) Cartesian coordinates (X, Y, Z).
152223
///
153224
/// Internally stored as an array of 3 [f64](std::f64) values: x, y, z all in meters
@@ -194,8 +265,8 @@ impl ECEF {
194265
/// Converts from WGS84 Earth Centered, Earth Fixed (ECEF) Cartesian
195266
/// coordinates (X, Y and Z) into WGS84 geodetic coordinates (latitude,
196267
/// 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]);
199270
unsafe { c_bindings::wgsecef2llh(self.as_ptr(), llh.as_mut_ptr()) };
200271
llh
201272
}
@@ -266,32 +337,32 @@ mod tests {
266337

267338
#[test]
268339
fn llhrad2deg() {
269-
let zeros = LLH::<Radians>::from_array(&[0.0; 3]);
340+
let zeros = LLHRadians::from_array(&[0.0; 3]);
270341

271342
let deg = zeros.to_degrees();
272343
assert_eq!(0.0, deg.latitude());
273344
assert_eq!(0.0, deg.longitude());
274345
assert_eq!(0.0, deg.height());
275346

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]);
277348
let rads = swift_home.to_radians();
278349

279350
assert!((rads.latitude() - 0.659381970558).abs() < MAX_ANGLE_ERROR_RAD);
280351
assert!((rads.longitude() + 2.136139032231).abs() < MAX_ANGLE_ERROR_RAD);
281352
assert!(rads.height() == swift_home.height());
282353
}
283354

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. */
295366
];
296367

297368
/* Semi-major axis. */

0 commit comments

Comments
 (0)