diff --git a/swiftnav/src/reference_frame.rs b/swiftnav/src/reference_frame/mod.rs similarity index 80% rename from swiftnav/src/reference_frame.rs rename to swiftnav/src/reference_frame/mod.rs index bdb18e8..4acf08a 100644 --- a/swiftnav/src/reference_frame.rs +++ b/swiftnav/src/reference_frame/mod.rs @@ -78,14 +78,36 @@ use crate::coords::{Coordinate, ECEF}; use std::fmt; use strum::{Display, EnumIter, EnumString}; +mod params; + /// Reference Frames #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, EnumString, Display, EnumIter)] #[strum(serialize_all = "UPPERCASE")] pub enum ReferenceFrame { + ITRF88, + ITRF89, + ITRF90, + ITRF91, + ITRF92, + ITRF93, + ITRF94, + ITRF96, + ITRF97, + ITRF2000, + ITRF2005, ITRF2008, ITRF2014, ITRF2020, - ETRF2008, + ETRF89, + ETRF90, + ETRF91, + ETRF92, + ETRF93, + ETRF94, + ETRF96, + ETRF97, + ETRF2000, + ETRF2005, ETRF2014, ETRF2020, /// i.e. NAD83(2011) @@ -95,6 +117,9 @@ pub enum ReferenceFrame { #[allow(non_camel_case_types)] #[strum(to_string = "NAD83(CSRS)", serialize = "NAD83_CSRS")] NAD83_CSRS, + #[allow(non_camel_case_types)] + #[strum(to_string = "DREF91(R2016)", serialize = "DREF91_R2016")] + DREF91_R2016, } /// 15-parameter Helmert transformation parameters @@ -112,7 +137,7 @@ pub enum ReferenceFrame { /// the scaling is in parts per billion. We also follow the /// IERS convention for the sign of the rotation terms. #[derive(Debug, PartialEq, PartialOrd, Clone, Copy)] -struct TimeDependentHelmertParams { +pub struct TimeDependentHelmertParams { tx: f64, tx_dot: f64, ty: f64, @@ -136,7 +161,7 @@ impl TimeDependentHelmertParams { const ROTATE_SCALE: f64 = (std::f64::consts::PI / 180.0) * (0.001 / 3600.0); /// Reverses the transformation. Since this is a linear transformation we simply negate all terms - fn invert(&mut self) { + pub fn invert(&mut self) { self.tx *= -1.0; self.tx_dot *= -1.0; self.ty *= -1.0; @@ -154,7 +179,7 @@ impl TimeDependentHelmertParams { } /// Apply the transformation on a position at a specific epoch - fn transform_position(&self, position: &ECEF, epoch: f64) -> ECEF { + pub fn transform_position(&self, position: &ECEF, epoch: f64) -> ECEF { let dt = epoch - self.epoch; let tx = (self.tx + self.tx_dot * dt) * Self::TRANSLATE_SCALE; let ty = (self.ty + self.ty_dot * dt) * Self::TRANSLATE_SCALE; @@ -172,7 +197,7 @@ impl TimeDependentHelmertParams { } /// Apply the transformation on a velocity at a specific position - fn transform_velocity(&self, velocity: &ECEF, position: &ECEF) -> ECEF { + pub fn transform_velocity(&self, velocity: &ECEF, position: &ECEF) -> ECEF { let tx = self.tx_dot * Self::TRANSLATE_SCALE; let ty = self.ty_dot * Self::TRANSLATE_SCALE; let tz = self.tz_dot * Self::TRANSLATE_SCALE; @@ -192,9 +217,9 @@ impl TimeDependentHelmertParams { /// A transformation from one reference frame to another. #[derive(Debug, PartialEq, PartialOrd, Clone, Copy)] pub struct Transformation { - from: ReferenceFrame, - to: ReferenceFrame, - params: TimeDependentHelmertParams, + pub from: ReferenceFrame, + pub to: ReferenceFrame, + pub params: TimeDependentHelmertParams, } impl Transformation { @@ -250,7 +275,7 @@ pub fn get_transformation( from: ReferenceFrame, to: ReferenceFrame, ) -> Result { - TRANSFORMATIONS + params::TRANSFORMATIONS .iter() .find(|t| (t.from == from && t.to == to) || (t.from == to && t.to == from)) .map(|t| { @@ -263,198 +288,6 @@ pub fn get_transformation( .ok_or(TransformationNotFound(from, to)) } -const TRANSFORMATIONS: [Transformation; 9] = [ - Transformation { - from: ReferenceFrame::ITRF2020, - to: ReferenceFrame::ITRF2014, - params: TimeDependentHelmertParams { - tx: -1.4, - tx_dot: 0.0, - ty: -0.9, - ty_dot: -0.1, - tz: 1.4, - tz_dot: 0.2, - s: -0.42, - s_dot: 0.0, - rx: 0.0, - rx_dot: 0.0, - ry: 0.0, - ry_dot: 0.0, - rz: 0.0, - rz_dot: 0.0, - epoch: 2015.0, - }, - }, - Transformation { - from: ReferenceFrame::ITRF2020, - to: ReferenceFrame::ITRF2008, - params: TimeDependentHelmertParams { - tx: 0.2, - tx_dot: 0.0, - ty: 1.0, - ty_dot: -0.1, - tz: 3.3, - tz_dot: 0.1, - s: -0.29, - s_dot: 0.03, - rx: 0.0, - rx_dot: 0.0, - ry: 0.0, - ry_dot: 0.0, - rz: 0.0, - rz_dot: 0.0, - epoch: 2015.0, - }, - }, - Transformation { - from: ReferenceFrame::ITRF2020, - to: ReferenceFrame::ETRF2020, - params: TimeDependentHelmertParams { - tx: 0.0, - tx_dot: 0.0, - ty: 0.0, - ty_dot: 0.0, - tz: 0.0, - tz_dot: 0.0, - s: 0.0, - s_dot: 0.0, - rx: 0.0, - rx_dot: 0.086, - ry: 0.0, - ry_dot: 0.519, - rz: 0.0, - rz_dot: -0.753, - epoch: 1989.0, - }, - }, - Transformation { - from: ReferenceFrame::ITRF2020, - to: ReferenceFrame::ETRF2014, - params: TimeDependentHelmertParams { - tx: -1.4, - tx_dot: 0.0, - ty: -0.9, - ty_dot: -0.1, - tz: 1.4, - tz_dot: 0.2, - s: -0.42, - s_dot: 0.0, - rx: 2.21, - rx_dot: 0.085, - ry: 13.806, - ry_dot: 0.531, - rz: -20.02, - rz_dot: -0.77, - epoch: 2015.0, - }, - }, - Transformation { - from: ReferenceFrame::ITRF2014, - to: ReferenceFrame::NAD83_2011, - params: TimeDependentHelmertParams { - tx: 1005.30, - tx_dot: 0.79, - ty: -1909.21, - ty_dot: -0.60, - tz: -541.57, - tz_dot: -1.44, - s: 0.36891, - s_dot: -0.07201, - rx: -26.78138, - rx_dot: -0.06667, - ry: 0.42027, - ry_dot: 0.75744, - rz: -10.93206, - rz_dot: 0.05133, - epoch: 2010.0, - }, - }, - Transformation { - from: ReferenceFrame::ITRF2014, - to: ReferenceFrame::ETRF2014, - params: TimeDependentHelmertParams { - tx: 0.0, - tx_dot: 0.0, - ty: 0.0, - ty_dot: 0.0, - tz: 0.0, - tz_dot: 0.0, - s: 0.0, - s_dot: 0.0, - rx: 0.0, - rx_dot: 0.085, - ry: 0.0, - ry_dot: 0.531, - rz: 0.0, - rz_dot: -0.770, - epoch: 1989.0, - }, - }, - Transformation { - from: ReferenceFrame::ITRF2008, - to: ReferenceFrame::NAD83_CSRS, - params: TimeDependentHelmertParams { - tx: 1003.70, - tx_dot: 0.79, - ty: -1911.11, - ty_dot: -0.60, - tz: -543.97, - tz_dot: -1.34, - s: 0.38891, - s_dot: -0.10201, - rx: -26.78138, - rx_dot: -0.06667, - ry: 0.42027, - ry_dot: 0.75744, - rz: -10.93206, - rz_dot: 0.05133, - epoch: 2010.0, - }, - }, - Transformation { - from: ReferenceFrame::ITRF2014, - to: ReferenceFrame::NAD83_CSRS, - params: TimeDependentHelmertParams { - tx: 1005.30, - tx_dot: 0.79, - ty: -1909.21, - ty_dot: -0.60, - tz: -541.57, - tz_dot: -1.44, - s: 0.36891, - s_dot: -0.07201, - rx: -26.78138, - rx_dot: -0.06667, - ry: 0.42027, - ry_dot: 0.75744, - rz: -10.93206, - rz_dot: 0.05133, - epoch: 2010.0, - }, - }, - Transformation { - from: ReferenceFrame::ITRF2020, - to: ReferenceFrame::NAD83_CSRS, - params: TimeDependentHelmertParams { - tx: 1003.90, - tx_dot: 0.79, - ty: -1909.61, - ty_dot: -0.70, - tz: -541.17, - tz_dot: -1.24, - s: -0.05109, - s_dot: -0.07201, - rx: -26.78138, - rx_dot: -0.06667, - ry: 0.42027, - ry_dot: 0.75744, - rz: -10.93206, - rz_dot: 0.05133, - epoch: 2010.0, - }, - }, -]; - #[cfg(test)] mod tests { use super::*; @@ -463,6 +296,61 @@ mod tests { #[test] fn reference_frame_strings() { + assert_eq!(ReferenceFrame::ITRF88.to_string(), "ITRF88"); + assert_eq!( + ReferenceFrame::from_str("ITRF88"), + Ok(ReferenceFrame::ITRF88) + ); + assert_eq!(ReferenceFrame::ITRF89.to_string(), "ITRF89"); + assert_eq!( + ReferenceFrame::from_str("ITRF89"), + Ok(ReferenceFrame::ITRF89) + ); + assert_eq!(ReferenceFrame::ITRF90.to_string(), "ITRF90"); + assert_eq!( + ReferenceFrame::from_str("ITRF90"), + Ok(ReferenceFrame::ITRF90) + ); + assert_eq!(ReferenceFrame::ITRF91.to_string(), "ITRF91"); + assert_eq!( + ReferenceFrame::from_str("ITRF91"), + Ok(ReferenceFrame::ITRF91) + ); + assert_eq!(ReferenceFrame::ITRF92.to_string(), "ITRF92"); + assert_eq!( + ReferenceFrame::from_str("ITRF92"), + Ok(ReferenceFrame::ITRF92) + ); + assert_eq!(ReferenceFrame::ITRF93.to_string(), "ITRF93"); + assert_eq!( + ReferenceFrame::from_str("ITRF93"), + Ok(ReferenceFrame::ITRF93) + ); + assert_eq!(ReferenceFrame::ITRF94.to_string(), "ITRF94"); + assert_eq!( + ReferenceFrame::from_str("ITRF94"), + Ok(ReferenceFrame::ITRF94) + ); + assert_eq!(ReferenceFrame::ITRF96.to_string(), "ITRF96"); + assert_eq!( + ReferenceFrame::from_str("ITRF96"), + Ok(ReferenceFrame::ITRF96) + ); + assert_eq!(ReferenceFrame::ITRF97.to_string(), "ITRF97"); + assert_eq!( + ReferenceFrame::from_str("ITRF97"), + Ok(ReferenceFrame::ITRF97) + ); + assert_eq!(ReferenceFrame::ITRF2000.to_string(), "ITRF2000"); + assert_eq!( + ReferenceFrame::from_str("ITRF2000"), + Ok(ReferenceFrame::ITRF2000) + ); + assert_eq!(ReferenceFrame::ITRF2005.to_string(), "ITRF2005"); + assert_eq!( + ReferenceFrame::from_str("ITRF2005"), + Ok(ReferenceFrame::ITRF2005) + ); assert_eq!(ReferenceFrame::ITRF2008.to_string(), "ITRF2008"); assert_eq!( ReferenceFrame::from_str("ITRF2008"), @@ -478,10 +366,55 @@ mod tests { ReferenceFrame::from_str("ITRF2020"), Ok(ReferenceFrame::ITRF2020) ); - assert_eq!(ReferenceFrame::ETRF2008.to_string(), "ETRF2008"); + assert_eq!(ReferenceFrame::ETRF89.to_string(), "ETRF89"); + assert_eq!( + ReferenceFrame::from_str("ETRF89"), + Ok(ReferenceFrame::ETRF89) + ); + assert_eq!(ReferenceFrame::ETRF90.to_string(), "ETRF90"); + assert_eq!( + ReferenceFrame::from_str("ETRF90"), + Ok(ReferenceFrame::ETRF90) + ); + assert_eq!(ReferenceFrame::ETRF91.to_string(), "ETRF91"); + assert_eq!( + ReferenceFrame::from_str("ETRF91"), + Ok(ReferenceFrame::ETRF91) + ); + assert_eq!(ReferenceFrame::ETRF92.to_string(), "ETRF92"); + assert_eq!( + ReferenceFrame::from_str("ETRF92"), + Ok(ReferenceFrame::ETRF92) + ); + assert_eq!(ReferenceFrame::ETRF93.to_string(), "ETRF93"); + assert_eq!( + ReferenceFrame::from_str("ETRF93"), + Ok(ReferenceFrame::ETRF93) + ); + assert_eq!(ReferenceFrame::ETRF94.to_string(), "ETRF94"); + assert_eq!( + ReferenceFrame::from_str("ETRF94"), + Ok(ReferenceFrame::ETRF94) + ); + assert_eq!(ReferenceFrame::ETRF96.to_string(), "ETRF96"); + assert_eq!( + ReferenceFrame::from_str("ETRF96"), + Ok(ReferenceFrame::ETRF96) + ); + assert_eq!(ReferenceFrame::ETRF97.to_string(), "ETRF97"); + assert_eq!( + ReferenceFrame::from_str("ETRF97"), + Ok(ReferenceFrame::ETRF97) + ); + assert_eq!(ReferenceFrame::ETRF2000.to_string(), "ETRF2000"); + assert_eq!( + ReferenceFrame::from_str("ETRF2000"), + Ok(ReferenceFrame::ETRF2000) + ); + assert_eq!(ReferenceFrame::ETRF2005.to_string(), "ETRF2005"); assert_eq!( - ReferenceFrame::from_str("ETRF2008"), - Ok(ReferenceFrame::ETRF2008) + ReferenceFrame::from_str("ETRF2005"), + Ok(ReferenceFrame::ETRF2005) ); assert_eq!(ReferenceFrame::ETRF2014.to_string(), "ETRF2014"); assert_eq!( diff --git a/swiftnav/src/reference_frame/params.rs b/swiftnav/src/reference_frame/params.rs new file mode 100644 index 0000000..f245215 --- /dev/null +++ b/swiftnav/src/reference_frame/params.rs @@ -0,0 +1,655 @@ +use super::{ReferenceFrame, TimeDependentHelmertParams, Transformation}; + +pub const TRANSFORMATIONS: [Transformation; 31] = [ + Transformation { + from: ReferenceFrame::ITRF2020, + to: ReferenceFrame::ITRF2014, + params: TimeDependentHelmertParams { + tx: -1.4, + tx_dot: 0.0, + ty: -0.9, + ty_dot: -0.1, + tz: 1.4, + tz_dot: 0.2, + s: -0.42, + s_dot: 0.0, + rx: 0.0, + rx_dot: 0.0, + ry: 0.0, + ry_dot: 0.0, + rz: 0.0, + rz_dot: 0.0, + epoch: 2015.0, + }, + }, + Transformation { + from: ReferenceFrame::ITRF2020, + to: ReferenceFrame::ITRF2008, + params: TimeDependentHelmertParams { + tx: 0.2, + tx_dot: 0.0, + ty: 1.0, + ty_dot: -0.1, + tz: 3.3, + tz_dot: 0.1, + s: -0.29, + s_dot: 0.03, + rx: 0.0, + rx_dot: 0.0, + ry: 0.0, + ry_dot: 0.0, + rz: 0.0, + rz_dot: 0.0, + epoch: 2015.0, + }, + }, + Transformation { + from: ReferenceFrame::ITRF2020, + to: ReferenceFrame::ITRF2005, + params: TimeDependentHelmertParams { + tx: 2.7, + tx_dot: 0.3, + ty: 0.1, + ty_dot: -0.1, + tz: -1.4, + tz_dot: 0.1, + s: 0.65, + s_dot: 0.03, + rx: 0.0, + rx_dot: 0.0, + ry: 0.0, + ry_dot: 0.0, + rz: 0.0, + rz_dot: 0.0, + epoch: 2015.0, + }, + }, + Transformation { + from: ReferenceFrame::ITRF2020, + to: ReferenceFrame::ITRF2000, + params: TimeDependentHelmertParams { + tx: -0.2, + tx_dot: 0.1, + ty: 0.8, + ty_dot: 0.0, + tz: -34.2, + tz_dot: -1.7, + s: 2.25, + s_dot: 0.11, + rx: 0.0, + rx_dot: 0.0, + ry: 0.0, + ry_dot: 0.0, + rz: 0.0, + rz_dot: 0.0, + epoch: 2015.0, + }, + }, + Transformation { + from: ReferenceFrame::ITRF2020, + to: ReferenceFrame::ITRF97, + params: TimeDependentHelmertParams { + tx: 6.5, + tx_dot: 0.1, + ty: -3.9, + ty_dot: -0.6, + tz: -77.9, + tz_dot: -3.1, + s: 3.98, + s_dot: 0.12, + rx: 0.0, + rx_dot: 0.0, + ry: 0.0, + ry_dot: 0.0, + rz: 0.36, + rz_dot: 0.02, + epoch: 2015.0, + }, + }, + Transformation { + from: ReferenceFrame::ITRF2020, + to: ReferenceFrame::ITRF96, + params: TimeDependentHelmertParams { + tx: 6.5, + tx_dot: 0.1, + ty: -3.9, + ty_dot: -0.6, + tz: -77.9, + tz_dot: -3.1, + s: 3.98, + s_dot: 0.12, + rx: 0.0, + rx_dot: 0.0, + ry: 0.0, + ry_dot: 0.0, + rz: 0.36, + rz_dot: 0.02, + epoch: 2015.0, + }, + }, + Transformation { + from: ReferenceFrame::ITRF2020, + to: ReferenceFrame::ITRF94, + params: TimeDependentHelmertParams { + tx: 6.5, + tx_dot: 0.1, + ty: -3.9, + ty_dot: -0.6, + tz: -77.9, + tz_dot: -3.1, + s: 3.98, + s_dot: 0.12, + rx: 0.0, + rx_dot: 0.0, + ry: 0.0, + ry_dot: 0.0, + rz: 0.36, + rz_dot: 0.02, + epoch: 2015.0, + }, + }, + Transformation { + from: ReferenceFrame::ITRF2020, + to: ReferenceFrame::ITRF93, + params: TimeDependentHelmertParams { + tx: -65.8, + tx_dot: -2.8, + ty: 1.9, + ty_dot: -0.2, + tz: -71.3, + tz_dot: -2.3, + s: 4.47, + s_dot: 0.12, + rx: -3.36, + rx_dot: -0.11, + ry: -4.33, + ry_dot: -0.19, + rz: 0.75, + rz_dot: 0.07, + epoch: 2015.0, + }, + }, + Transformation { + from: ReferenceFrame::ITRF2020, + to: ReferenceFrame::ITRF92, + params: TimeDependentHelmertParams { + tx: 14.5, + tx_dot: 0.1, + ty: -1.9, + ty_dot: -0.6, + tz: -85.9, + tz_dot: -3.1, + s: 3.27, + s_dot: 0.12, + rx: 0.00, + rx_dot: 0.00, + ry: 0.00, + ry_dot: 0.00, + rz: 0.36, + rz_dot: 0.02, + epoch: 2015.0, + }, + }, + Transformation { + from: ReferenceFrame::ITRF2020, + to: ReferenceFrame::ITRF91, + params: TimeDependentHelmertParams { + tx: 26.5, + tx_dot: 0.1, + ty: 12.1, + ty_dot: -0.6, + tz: -91.9, + tz_dot: -3.1, + s: 4.67, + s_dot: 0.12, + rx: 0.00, + rx_dot: 0.00, + ry: 0.00, + ry_dot: 0.00, + rz: 0.36, + rz_dot: 0.02, + epoch: 2015.0, + }, + }, + Transformation { + from: ReferenceFrame::ITRF2020, + to: ReferenceFrame::ITRF90, + params: TimeDependentHelmertParams { + tx: 24.5, + tx_dot: 0.1, + ty: 8.1, + ty_dot: -0.6, + tz: -107.9, + tz_dot: -3.1, + s: 4.97, + s_dot: 0.12, + rx: 0.00, + rx_dot: 0.00, + ry: 0.00, + ry_dot: 0.00, + rz: 0.36, + rz_dot: 0.02, + epoch: 2015.0, + }, + }, + Transformation { + from: ReferenceFrame::ITRF2020, + to: ReferenceFrame::ITRF89, + params: TimeDependentHelmertParams { + tx: 29.5, + tx_dot: 0.1, + ty: 32.1, + ty_dot: -0.6, + tz: -145.9, + tz_dot: -3.1, + s: 8.37, + s_dot: 0.12, + rx: 0.00, + rx_dot: 0.00, + ry: 0.00, + ry_dot: 0.00, + rz: 0.36, + rz_dot: 0.02, + epoch: 2015.0, + }, + }, + Transformation { + from: ReferenceFrame::ITRF2020, + to: ReferenceFrame::ITRF88, + params: TimeDependentHelmertParams { + tx: 24.5, + tx_dot: 0.1, + ty: -3.9, + ty_dot: -0.6, + tz: -169.9, + tz_dot: -3.1, + s: 11.47, + s_dot: 0.12, + rx: 0.10, + rx_dot: 0.00, + ry: 0.00, + ry_dot: 0.00, + rz: 0.36, + rz_dot: 0.02, + epoch: 2015.0, + }, + }, + Transformation { + from: ReferenceFrame::ITRF2020, + to: ReferenceFrame::ETRF2020, + params: TimeDependentHelmertParams { + tx: 0.0, + tx_dot: 0.0, + ty: 0.0, + ty_dot: 0.0, + tz: 0.0, + tz_dot: 0.0, + s: 0.0, + s_dot: 0.0, + rx: 0.0, + rx_dot: 0.086, + ry: 0.0, + ry_dot: 0.519, + rz: 0.0, + rz_dot: -0.753, + epoch: 1989.0, + }, + }, + Transformation { + from: ReferenceFrame::ITRF2014, + to: ReferenceFrame::ETRF2014, + params: TimeDependentHelmertParams { + tx: 0.0, + tx_dot: 0.0, + ty: 0.0, + ty_dot: 0.0, + tz: 0.0, + tz_dot: 0.0, + s: 0.0, + s_dot: 0.0, + rx: 0.0, + rx_dot: 0.085, + ry: 0.0, + ry_dot: 0.531, + rz: 0.0, + rz_dot: -0.770, + epoch: 1989.0, + }, + }, + Transformation { + from: ReferenceFrame::ITRF2005, + to: ReferenceFrame::ETRF2005, + params: TimeDependentHelmertParams { + tx: 56.0, + tx_dot: 0.0, + ty: 48.0, + ty_dot: 0.0, + tz: -37.0, + tz_dot: 0.0, + s: 0.0, + s_dot: 0.0, + rx: 0.0, + rx_dot: 0.054, + ry: 0.0, + ry_dot: 0.518, + rz: 0.0, + rz_dot: -0.781, + epoch: 1989.0, + }, + }, + Transformation { + from: ReferenceFrame::ITRF2000, + to: ReferenceFrame::ETRF2000, + params: TimeDependentHelmertParams { + tx: 54.0, + tx_dot: 0.0, + ty: 51.0, + ty_dot: 0.0, + tz: -48.0, + tz_dot: 0.0, + s: 0.0, + s_dot: 0.0, + rx: 0.0, + rx_dot: 0.081, + ry: 0.0, + ry_dot: 0.490, + rz: 0.0, + rz_dot: -0.792, + epoch: 1989.0, + }, + }, + Transformation { + from: ReferenceFrame::ITRF97, + to: ReferenceFrame::ETRF97, + params: TimeDependentHelmertParams { + tx: 41.0, + tx_dot: 0.0, + ty: 41.0, + ty_dot: 0.0, + tz: -49.0, + tz_dot: 0.0, + s: 0.0, + s_dot: 0.0, + rx: 0.0, + rx_dot: 0.200, + ry: 0.0, + ry_dot: 0.500, + rz: 0.0, + rz_dot: -0.650, + epoch: 1989.0, + }, + }, + Transformation { + from: ReferenceFrame::ITRF96, + to: ReferenceFrame::ETRF96, + params: TimeDependentHelmertParams { + tx: 41.0, + tx_dot: 0.0, + ty: 41.0, + ty_dot: 0.0, + tz: -49.0, + tz_dot: 0.0, + s: 0.0, + s_dot: 0.0, + rx: 0.0, + rx_dot: 0.200, + ry: 0.0, + ry_dot: 0.500, + rz: 0.0, + rz_dot: -0.650, + epoch: 1989.0, + }, + }, + Transformation { + from: ReferenceFrame::ITRF94, + to: ReferenceFrame::ETRF94, + params: TimeDependentHelmertParams { + tx: 41.0, + tx_dot: 0.0, + ty: 41.0, + ty_dot: 0.0, + tz: -49.0, + tz_dot: 0.0, + s: 0.0, + s_dot: 0.0, + rx: 0.0, + rx_dot: 0.200, + ry: 0.0, + ry_dot: 0.500, + rz: 0.0, + rz_dot: -0.650, + epoch: 1989.0, + }, + }, + Transformation { + from: ReferenceFrame::ITRF93, + to: ReferenceFrame::ETRF93, + params: TimeDependentHelmertParams { + tx: 19.0, + tx_dot: 0.0, + ty: 53.0, + ty_dot: 0.0, + tz: -21.0, + tz_dot: 0.0, + s: 0.0, + s_dot: 0.0, + rx: 0.0, + rx_dot: 0.320, + ry: 0.0, + ry_dot: 0.780, + rz: 0.0, + rz_dot: -0.670, + epoch: 1989.0, + }, + }, + Transformation { + from: ReferenceFrame::ITRF92, + to: ReferenceFrame::ETRF92, + params: TimeDependentHelmertParams { + tx: 38.0, + tx_dot: 0.0, + ty: 40.0, + ty_dot: 0.0, + tz: -37.0, + tz_dot: 0.0, + s: 0.0, + s_dot: 0.0, + rx: 0.0, + rx_dot: 0.210, + ry: 0.0, + ry_dot: 0.520, + rz: 0.0, + rz_dot: -0.680, + epoch: 1989.0, + }, + }, + Transformation { + from: ReferenceFrame::ITRF91, + to: ReferenceFrame::ETRF91, + params: TimeDependentHelmertParams { + tx: 21.0, + tx_dot: 0.0, + ty: 25.0, + ty_dot: 0.0, + tz: -37.0, + tz_dot: 0.0, + s: 0.0, + s_dot: 0.0, + rx: 0.0, + rx_dot: 0.210, + ry: 0.0, + ry_dot: 0.520, + rz: 0.0, + rz_dot: -0.680, + epoch: 1989.0, + }, + }, + Transformation { + from: ReferenceFrame::ITRF90, + to: ReferenceFrame::ETRF90, + params: TimeDependentHelmertParams { + tx: 19.0, + tx_dot: 0.0, + ty: 28.0, + ty_dot: 0.0, + tz: -23.0, + tz_dot: 0.0, + s: 0.0, + s_dot: 0.0, + rx: 0.0, + rx_dot: 0.110, + ry: 0.0, + ry_dot: 0.570, + rz: 0.0, + rz_dot: -0.710, + epoch: 1989.0, + }, + }, + Transformation { + from: ReferenceFrame::ITRF89, + to: ReferenceFrame::ETRF89, + params: TimeDependentHelmertParams { + tx: 0.0, + tx_dot: 0.0, + ty: 0.0, + ty_dot: 0.0, + tz: 0.0, + tz_dot: 0.0, + s: 0.0, + s_dot: 0.0, + rx: 0.0, + rx_dot: 0.110, + ry: 0.0, + ry_dot: 0.570, + rz: 0.0, + rz_dot: -0.710, + epoch: 1989.0, + }, + }, + Transformation { + from: ReferenceFrame::ITRF2014, + to: ReferenceFrame::NAD83_2011, + params: TimeDependentHelmertParams { + tx: 1005.30, + tx_dot: 0.79, + ty: -1909.21, + ty_dot: -0.60, + tz: -541.57, + tz_dot: -1.44, + s: 0.36891, + s_dot: -0.07201, + rx: -26.78138, + rx_dot: -0.06667, + ry: 0.42027, + ry_dot: 0.75744, + rz: -10.93206, + rz_dot: 0.05133, + epoch: 2010.0, + }, + }, + Transformation { + from: ReferenceFrame::ITRF2014, + to: ReferenceFrame::ETRF2014, + params: TimeDependentHelmertParams { + tx: 0.0, + tx_dot: 0.0, + ty: 0.0, + ty_dot: 0.0, + tz: 0.0, + tz_dot: 0.0, + s: 0.0, + s_dot: 0.0, + rx: 0.0, + rx_dot: 0.085, + ry: 0.0, + ry_dot: 0.531, + rz: 0.0, + rz_dot: -0.770, + epoch: 1989.0, + }, + }, + Transformation { + from: ReferenceFrame::ITRF2008, + to: ReferenceFrame::NAD83_CSRS, + params: TimeDependentHelmertParams { + tx: 1003.70, + tx_dot: 0.79, + ty: -1911.11, + ty_dot: -0.60, + tz: -543.97, + tz_dot: -1.34, + s: 0.38891, + s_dot: -0.10201, + rx: -26.78138, + rx_dot: -0.06667, + ry: 0.42027, + ry_dot: 0.75744, + rz: -10.93206, + rz_dot: 0.05133, + epoch: 2010.0, + }, + }, + Transformation { + from: ReferenceFrame::ITRF2014, + to: ReferenceFrame::NAD83_CSRS, + params: TimeDependentHelmertParams { + tx: 1005.30, + tx_dot: 0.79, + ty: -1909.21, + ty_dot: -0.60, + tz: -541.57, + tz_dot: -1.44, + s: 0.36891, + s_dot: -0.07201, + rx: -26.78138, + rx_dot: -0.06667, + ry: 0.42027, + ry_dot: 0.75744, + rz: -10.93206, + rz_dot: 0.05133, + epoch: 2010.0, + }, + }, + Transformation { + from: ReferenceFrame::ITRF2020, + to: ReferenceFrame::NAD83_CSRS, + params: TimeDependentHelmertParams { + tx: 1003.90, + tx_dot: 0.79, + ty: -1909.61, + ty_dot: -0.70, + tz: -541.17, + tz_dot: -1.24, + s: -0.05109, + s_dot: -0.07201, + rx: -26.78138, + rx_dot: -0.06667, + ry: 0.42027, + ry_dot: 0.75744, + rz: -10.93206, + rz_dot: 0.05133, + epoch: 2010.0, + }, + }, + Transformation { + from: ReferenceFrame::ITRF2020, + to: ReferenceFrame::DREF91_R2016, + params: TimeDependentHelmertParams { + tx: -3.0821, + tx_dot: -20.3181, + ty: 95.0769, + ty_dot: -20.3593, + tz: -73.5435, + tz_dot: 23.6394, + s: 7.4874, + s_dot: -0.3306, + rx: 2.5445, + rx_dot: -0.5966, + ry: 17.6078, + ry_dot: 1.4967, + rz: -27.6123, + rz_dot: -0.5284, + epoch: 2021.0, + }, + }, +]; diff --git a/swiftnav/tests/reference_frames.rs b/swiftnav/tests/reference_frames.rs index 2a23548..13e5329 100644 --- a/swiftnav/tests/reference_frames.rs +++ b/swiftnav/tests/reference_frames.rs @@ -118,17 +118,17 @@ fn euref_etrf2020() { #[test] fn euref_etrf2014() { let initial_coords = Coordinate::new( - ReferenceFrame::ITRF2020, + ReferenceFrame::ITRF2014, ECEF::new(4027894.006, 307045.600, 4919474.910), Some(ECEF::new(0.01, 0.2, 0.030)), make_epoch(2000), ); let transformation = - get_transformation(ReferenceFrame::ITRF2020, ReferenceFrame::ETRF2014).unwrap(); + get_transformation(ReferenceFrame::ITRF2014, ReferenceFrame::ETRF2014).unwrap(); let result_coords = transformation.transform(&initial_coords); - assert_float_eq!(result_coords.position().x(), 4027894.1548, abs <= 0.0001); - assert_float_eq!(result_coords.position().y(), 307045.4128, abs <= 0.0001); - assert_float_eq!(result_coords.position().z(), 4919474.7937, abs <= 0.0001); + assert_float_eq!(result_coords.position().x(), 4027894.1579, abs <= 0.0001); + assert_float_eq!(result_coords.position().y(), 307045.4123, abs <= 0.0001); + assert_float_eq!(result_coords.position().z(), 4919474.7973, abs <= 0.0001); assert!(result_coords.velocity().is_some()); assert_float_eq!( result_coords.velocity().as_ref().unwrap().x(), @@ -142,13 +142,363 @@ fn euref_etrf2014() { ); assert_float_eq!( result_coords.velocity().as_ref().unwrap().z(), - 0.0200, + 0.0198, abs <= 0.1 ); assert_eq!(result_coords.epoch(), make_epoch(2000)); assert_eq!(result_coords.reference_frame(), ReferenceFrame::ETRF2014); } +/// Truth data obtained from https://www.epncb.oma.be/_productsservices/coord_trans/ +#[test] +fn euref_etrf2005() { + let initial_coords = Coordinate::new( + ReferenceFrame::ITRF2005, + ECEF::new(4027894.006, 307045.600, 4919474.910), + Some(ECEF::new(0.01, 0.2, 0.030)), + make_epoch(2000), + ); + let transformation = + get_transformation(ReferenceFrame::ITRF2005, ReferenceFrame::ETRF2005).unwrap(); + let result_coords = transformation.transform(&initial_coords); + assert_float_eq!(result_coords.position().x(), 4027894.2107, abs <= 0.0001); + assert_float_eq!(result_coords.position().y(), 307045.4661, abs <= 0.0001); + assert_float_eq!(result_coords.position().z(), 4919474.7626, abs <= 0.0001); + assert!(result_coords.velocity().is_some()); + assert_float_eq!( + result_coords.velocity().as_ref().unwrap().x(), + 0.0235, + abs <= 0.1 + ); + assert_float_eq!( + result_coords.velocity().as_ref().unwrap().y(), + 0.1835, + abs <= 0.1 + ); + assert_float_eq!( + result_coords.velocity().as_ref().unwrap().z(), + 0.0200, + abs <= 0.1 + ); + assert_eq!(result_coords.epoch(), make_epoch(2000)); + assert_eq!(result_coords.reference_frame(), ReferenceFrame::ETRF2005); +} + +/// Truth data obtained from https://www.epncb.oma.be/_productsservices/coord_trans/ +#[test] +fn euref_etrf2000() { + let initial_coords = Coordinate::new( + ReferenceFrame::ITRF2000, + ECEF::new(4027894.006, 307045.600, 4919474.910), + Some(ECEF::new(0.01, 0.2, 0.030)), + make_epoch(2000), + ); + let transformation = + get_transformation(ReferenceFrame::ITRF2000, ReferenceFrame::ETRF2000).unwrap(); + let result_coords = transformation.transform(&initial_coords); + assert_float_eq!(result_coords.position().x(), 4027894.2015, abs <= 0.0001); + assert_float_eq!(result_coords.position().y(), 307045.4596, abs <= 0.0001); + assert_float_eq!(result_coords.position().z(), 4919474.7581, abs <= 0.0001); + assert!(result_coords.velocity().is_some()); + assert_float_eq!( + result_coords.velocity().as_ref().unwrap().x(), + 0.0229, + abs <= 0.1 + ); + assert_float_eq!( + result_coords.velocity().as_ref().unwrap().y(), + 0.1826, + abs <= 0.1 + ); + assert_float_eq!( + result_coords.velocity().as_ref().unwrap().z(), + 0.0206, + abs <= 0.1 + ); + assert_eq!(result_coords.epoch(), make_epoch(2000)); + assert_eq!(result_coords.reference_frame(), ReferenceFrame::ETRF2000); +} + +/// Truth data obtained from https://www.epncb.oma.be/_productsservices/coord_trans/ +#[test] +fn euref_etrf97() { + let initial_coords = Coordinate::new( + ReferenceFrame::ITRF97, + ECEF::new(4027894.006, 307045.600, 4919474.910), + Some(ECEF::new(0.01, 0.2, 0.030)), + make_epoch(2000), + ); + let transformation = + get_transformation(ReferenceFrame::ITRF97, ReferenceFrame::ETRF97).unwrap(); + let result_coords = transformation.transform(&initial_coords); + assert_float_eq!(result_coords.position().x(), 4027894.1888, abs <= 0.0001); + assert_float_eq!(result_coords.position().y(), 307045.4489, abs <= 0.0001); + assert_float_eq!(result_coords.position().z(), 4919474.7569, abs <= 0.0001); + assert!(result_coords.velocity().is_some()); + assert_float_eq!( + result_coords.velocity().as_ref().unwrap().x(), + 0.0229, + abs <= 0.1 + ); + assert_float_eq!( + result_coords.velocity().as_ref().unwrap().y(), + 0.1825, + abs <= 0.1 + ); + assert_float_eq!( + result_coords.velocity().as_ref().unwrap().z(), + 0.0205, + abs <= 0.1 + ); + assert_eq!(result_coords.epoch(), make_epoch(2000)); + assert_eq!(result_coords.reference_frame(), ReferenceFrame::ETRF97); +} + +/// Truth data obtained from https://www.epncb.oma.be/_productsservices/coord_trans/ +#[test] +fn euref_etrf96() { + let initial_coords = Coordinate::new( + ReferenceFrame::ITRF96, + ECEF::new(4027894.006, 307045.600, 4919474.910), + Some(ECEF::new(0.01, 0.2, 0.030)), + make_epoch(2000), + ); + let transformation = + get_transformation(ReferenceFrame::ITRF96, ReferenceFrame::ETRF96).unwrap(); + let result_coords = transformation.transform(&initial_coords); + assert_float_eq!(result_coords.position().x(), 4027894.1888, abs <= 0.0001); + assert_float_eq!(result_coords.position().y(), 307045.4489, abs <= 0.0001); + assert_float_eq!(result_coords.position().z(), 4919474.7569, abs <= 0.0001); + assert!(result_coords.velocity().is_some()); + assert_float_eq!( + result_coords.velocity().as_ref().unwrap().x(), + 0.0229, + abs <= 0.1 + ); + assert_float_eq!( + result_coords.velocity().as_ref().unwrap().y(), + 0.1825, + abs <= 0.1 + ); + assert_float_eq!( + result_coords.velocity().as_ref().unwrap().z(), + 0.0205, + abs <= 0.1 + ); + assert_eq!(result_coords.epoch(), make_epoch(2000)); + assert_eq!(result_coords.reference_frame(), ReferenceFrame::ETRF96); +} + +/// Truth data obtained from https://www.epncb.oma.be/_productsservices/coord_trans/ +#[test] +fn euref_etrf94() { + let initial_coords = Coordinate::new( + ReferenceFrame::ITRF94, + ECEF::new(4027894.006, 307045.600, 4919474.910), + Some(ECEF::new(0.01, 0.2, 0.030)), + make_epoch(2000), + ); + let transformation = + get_transformation(ReferenceFrame::ITRF94, ReferenceFrame::ETRF94).unwrap(); + let result_coords = transformation.transform(&initial_coords); + assert_float_eq!(result_coords.position().x(), 4027894.1888, abs <= 0.0001); + assert_float_eq!(result_coords.position().y(), 307045.4489, abs <= 0.0001); + assert_float_eq!(result_coords.position().z(), 4919474.7569, abs <= 0.0001); + assert!(result_coords.velocity().is_some()); + assert_float_eq!( + result_coords.velocity().as_ref().unwrap().x(), + 0.0229, + abs <= 0.1 + ); + assert_float_eq!( + result_coords.velocity().as_ref().unwrap().y(), + 0.1825, + abs <= 0.1 + ); + assert_float_eq!( + result_coords.velocity().as_ref().unwrap().z(), + 0.0205, + abs <= 0.1 + ); + assert_eq!(result_coords.epoch(), make_epoch(2000)); + assert_eq!(result_coords.reference_frame(), ReferenceFrame::ETRF94); +} + +/// Truth data obtained from https://www.epncb.oma.be/_productsservices/coord_trans/ +#[test] +fn euref_etrf93() { + let initial_coords = Coordinate::new( + ReferenceFrame::ITRF93, + ECEF::new(4027894.006, 307045.600, 4919474.910), + Some(ECEF::new(0.01, 0.2, 0.030)), + make_epoch(2000), + ); + let transformation = + get_transformation(ReferenceFrame::ITRF93, ReferenceFrame::ETRF93).unwrap(); + let result_coords = transformation.transform(&initial_coords); + assert_float_eq!(result_coords.position().x(), 4027894.2406, abs <= 0.0001); + assert_float_eq!(result_coords.position().y(), 307045.4251, abs <= 0.0001); + assert_float_eq!(result_coords.position().z(), 4919474.7267, abs <= 0.0001); + assert!(result_coords.velocity().is_some()); + assert_float_eq!( + result_coords.velocity().as_ref().unwrap().x(), + 0.0296, + abs <= 0.1 + ); + assert_float_eq!( + result_coords.velocity().as_ref().unwrap().y(), + 0.1793, + abs <= 0.1 + ); + assert_float_eq!( + result_coords.velocity().as_ref().unwrap().z(), + 0.0152, + abs <= 0.1 + ); + assert_eq!(result_coords.epoch(), make_epoch(2000)); + assert_eq!(result_coords.reference_frame(), ReferenceFrame::ETRF93); +} + +/// Truth data obtained from https://www.epncb.oma.be/_productsservices/coord_trans/ +#[test] +fn euref_etrf92() { + let initial_coords = Coordinate::new( + ReferenceFrame::ITRF92, + ECEF::new(4027894.006, 307045.600, 4919474.910), + Some(ECEF::new(0.01, 0.2, 0.030)), + make_epoch(2000), + ); + let transformation = + get_transformation(ReferenceFrame::ITRF92, ReferenceFrame::ETRF92).unwrap(); + let result_coords = transformation.transform(&initial_coords); + assert_float_eq!(result_coords.position().x(), 4027894.1916, abs <= 0.0001); + assert_float_eq!(result_coords.position().y(), 307045.4388, abs <= 0.0001); + assert_float_eq!(result_coords.position().z(), 4919474.7647, abs <= 0.0001); + assert!(result_coords.velocity().is_some()); + assert_float_eq!( + result_coords.velocity().as_ref().unwrap().x(), + 0.0234, + abs <= 0.1 + ); + assert_float_eq!( + result_coords.velocity().as_ref().unwrap().y(), + 0.1817, + abs <= 0.1 + ); + assert_float_eq!( + result_coords.velocity().as_ref().unwrap().z(), + 0.0202, + abs <= 0.1 + ); + assert_eq!(result_coords.epoch(), make_epoch(2000)); + assert_eq!(result_coords.reference_frame(), ReferenceFrame::ETRF92); +} + +/// Truth data obtained from https://www.epncb.oma.be/_productsservices/coord_trans/ +#[test] +fn euref_etrf91() { + let initial_coords = Coordinate::new( + ReferenceFrame::ITRF91, + ECEF::new(4027894.006, 307045.600, 4919474.910), + Some(ECEF::new(0.01, 0.2, 0.030)), + make_epoch(2000), + ); + let transformation = + get_transformation(ReferenceFrame::ITRF91, ReferenceFrame::ETRF91).unwrap(); + let result_coords = transformation.transform(&initial_coords); + assert_float_eq!(result_coords.position().x(), 4027894.1746, abs <= 0.0001); + assert_float_eq!(result_coords.position().y(), 307045.4238, abs <= 0.0001); + assert_float_eq!(result_coords.position().z(), 4919474.7647, abs <= 0.0001); + assert!(result_coords.velocity().is_some()); + assert_float_eq!( + result_coords.velocity().as_ref().unwrap().x(), + 0.0234, + abs <= 0.1 + ); + assert_float_eq!( + result_coords.velocity().as_ref().unwrap().y(), + 0.1817, + abs <= 0.1 + ); + assert_float_eq!( + result_coords.velocity().as_ref().unwrap().z(), + 0.0202, + abs <= 0.1 + ); + assert_eq!(result_coords.epoch(), make_epoch(2000)); + assert_eq!(result_coords.reference_frame(), ReferenceFrame::ETRF91); +} + +/// Truth data obtained from https://www.epncb.oma.be/_productsservices/coord_trans/ +#[test] +fn euref_etrf90() { + let initial_coords = Coordinate::new( + ReferenceFrame::ITRF90, + ECEF::new(4027894.006, 307045.600, 4919474.910), + Some(ECEF::new(0.01, 0.2, 0.030)), + make_epoch(2000), + ); + let transformation = + get_transformation(ReferenceFrame::ITRF90, ReferenceFrame::ETRF90).unwrap(); + let result_coords = transformation.transform(&initial_coords); + assert_float_eq!(result_coords.position().x(), 4027894.1862, abs <= 0.0001); + assert_float_eq!(result_coords.position().y(), 307045.4466, abs <= 0.0001); + assert_float_eq!(result_coords.position().z(), 4919474.7664, abs <= 0.0001); + assert!(result_coords.velocity().is_some()); + assert_float_eq!( + result_coords.velocity().as_ref().unwrap().x(), + 0.0247, + abs <= 0.1 + ); + assert_float_eq!( + result_coords.velocity().as_ref().unwrap().y(), + 0.1835, + abs <= 0.1 + ); + assert_float_eq!( + result_coords.velocity().as_ref().unwrap().z(), + 0.0190, + abs <= 0.1 + ); + assert_eq!(result_coords.epoch(), make_epoch(2000)); + assert_eq!(result_coords.reference_frame(), ReferenceFrame::ETRF90); +} + +/// Truth data obtained from https://www.epncb.oma.be/_productsservices/coord_trans/ +#[test] +fn euref_etrf89() { + let initial_coords = Coordinate::new( + ReferenceFrame::ITRF89, + ECEF::new(4027894.006, 307045.600, 4919474.910), + Some(ECEF::new(0.01, 0.2, 0.030)), + make_epoch(2000), + ); + let transformation = + get_transformation(ReferenceFrame::ITRF89, ReferenceFrame::ETRF89).unwrap(); + let result_coords = transformation.transform(&initial_coords); + assert_float_eq!(result_coords.position().x(), 4027894.1672, abs <= 0.0001); + assert_float_eq!(result_coords.position().y(), 307045.4186, abs <= 0.0001); + assert_float_eq!(result_coords.position().z(), 4919474.7894, abs <= 0.0001); + assert!(result_coords.velocity().is_some()); + assert_float_eq!( + result_coords.velocity().as_ref().unwrap().x(), + 0.0247, + abs <= 0.1 + ); + assert_float_eq!( + result_coords.velocity().as_ref().unwrap().y(), + 0.1835, + abs <= 0.1 + ); + assert_float_eq!( + result_coords.velocity().as_ref().unwrap().z(), + 0.0190, + abs <= 0.1 + ); + assert_eq!(result_coords.epoch(), make_epoch(2000)); + assert_eq!(result_coords.reference_frame(), ReferenceFrame::ETRF89); +} + /// Truth data obtained from https://www.epncb.oma.be/_productsservices/coord_trans/ #[test] fn euref_etrf2014_reverse() { @@ -159,11 +509,11 @@ fn euref_etrf2014_reverse() { make_epoch(2000), ); let transformation = - get_transformation(ReferenceFrame::ETRF2014, ReferenceFrame::ITRF2020).unwrap(); + get_transformation(ReferenceFrame::ETRF2014, ReferenceFrame::ITRF2014).unwrap(); let result_coords = transformation.transform(&initial_coords); - assert_float_eq!(result_coords.position().x(), 4027893.8572, abs <= 0.0001); - assert_float_eq!(result_coords.position().y(), 307045.7872, abs <= 0.0001); - assert_float_eq!(result_coords.position().z(), 4919475.0263, abs <= 0.0001); + assert_float_eq!(result_coords.position().x(), 4027893.8541, abs <= 0.0001); + assert_float_eq!(result_coords.position().y(), 307045.7877, abs <= 0.0001); + assert_float_eq!(result_coords.position().z(), 4919475.0227, abs <= 0.0001); assert!(result_coords.velocity().is_some()); assert_float_eq!( result_coords.velocity().as_ref().unwrap().x(), @@ -172,16 +522,16 @@ fn euref_etrf2014_reverse() { ); assert_float_eq!( result_coords.velocity().as_ref().unwrap().y(), - 0.2172, + 0.2171, abs <= 0.1 ); assert_float_eq!( result_coords.velocity().as_ref().unwrap().z(), - 0.0400, + 0.0402, abs <= 0.1 ); assert_eq!(result_coords.epoch(), make_epoch(2000)); - assert_eq!(result_coords.reference_frame(), ReferenceFrame::ITRF2020); + assert_eq!(result_coords.reference_frame(), ReferenceFrame::ITRF2014); } /// Truth data obtained from https://www.epncb.oma.be/_productsservices/coord_trans/ @@ -221,19 +571,19 @@ fn euref_adjust_epoch() { #[test] fn euref_complete_transform() { let initial_coords = Coordinate::new( - ReferenceFrame::ITRF2020, + ReferenceFrame::ITRF2014, ECEF::new(4027894.006, 307045.600, 4919474.910), Some(ECEF::new(0.01, 0.2, 0.030)), make_epoch(2000), ); let transformation = - get_transformation(ReferenceFrame::ITRF2020, ReferenceFrame::ETRF2014).unwrap(); + get_transformation(ReferenceFrame::ITRF2014, ReferenceFrame::ETRF2014).unwrap(); // Test adjusting the epoch first then transforming let result_coords = transformation.transform(&initial_coords.adjust_epoch(&make_epoch(2008))); - assert_float_eq!(result_coords.position().x(), 4027894.3453, abs <= 0.0001); - assert_float_eq!(result_coords.position().y(), 307046.8755, abs <= 0.0001); - assert_float_eq!(result_coords.position().z(), 4919474.9533, abs <= 0.0001); + assert_float_eq!(result_coords.position().x(), 4027894.3484, abs <= 0.0001); + assert_float_eq!(result_coords.position().y(), 307046.8758, abs <= 0.0001); + assert_float_eq!(result_coords.position().z(), 4919474.9554, abs <= 0.0001); assert!(result_coords.velocity().is_some()); assert_float_eq!( result_coords.velocity().as_ref().unwrap().x(), @@ -242,12 +592,12 @@ fn euref_complete_transform() { ); assert_float_eq!( result_coords.velocity().as_ref().unwrap().y(), - 0.1828, + 0.1829, abs <= 0.1 ); assert_float_eq!( result_coords.velocity().as_ref().unwrap().z(), - 0.0200, + 0.0198, abs <= 0.1 ); assert_eq!(result_coords.epoch(), make_epoch(2008)); @@ -257,9 +607,9 @@ fn euref_complete_transform() { let result_coords = transformation .transform(&initial_coords) .adjust_epoch(&make_epoch(2008)); - assert_float_eq!(result_coords.position().x(), 4027894.3453, abs <= 0.0001); - assert_float_eq!(result_coords.position().y(), 307046.8755, abs <= 0.0001); - assert_float_eq!(result_coords.position().z(), 4919474.9533, abs <= 0.0001); + assert_float_eq!(result_coords.position().x(), 4027894.3484, abs <= 0.0001); + assert_float_eq!(result_coords.position().y(), 307046.8758, abs <= 0.0001); + assert_float_eq!(result_coords.position().z(), 4919474.9554, abs <= 0.0001); assert!(result_coords.velocity().is_some()); assert_float_eq!( result_coords.velocity().as_ref().unwrap().x(), @@ -268,12 +618,12 @@ fn euref_complete_transform() { ); assert_float_eq!( result_coords.velocity().as_ref().unwrap().y(), - 0.1828, + 0.1829, abs <= 0.1 ); assert_float_eq!( result_coords.velocity().as_ref().unwrap().z(), - 0.0200, + 0.0198, abs <= 0.1 ); assert_eq!(result_coords.epoch(), make_epoch(2008)); @@ -477,3 +827,30 @@ fn trx_nad83_csrs_adjust_epoch() { assert_eq!(result_coords.epoch(), make_epoch(2010)); assert_eq!(result_coords.reference_frame(), ReferenceFrame::NAD83_CSRS); } + +/// Truth data obtained from https://www.adv-online.de/AdV-Produkte/Integrierter-geodaetischer-Raumbezug/Transformationsparameter/ +#[test] +fn dref91_r2016() { + let initial_coords: Coordinate = Coordinate::new( + ReferenceFrame::ITRF2020, + ECEF::new(3842152.805, 563402.164, 5042888.600), + None, + UtcTime::from_date(2023, 02, 22, 0, 0, 0.).to_gps_hardcoded(), + ); + let transformation = + get_transformation(ReferenceFrame::ITRF2020, ReferenceFrame::DREF91_R2016).unwrap(); + let result_coords = transformation.transform(&initial_coords); + assert_float_eq!(result_coords.position().x(), 3842153.3718, abs <= 0.0001); + assert_float_eq!(result_coords.position().y(), 563401.6528, abs <= 0.0001); + assert_float_eq!(result_coords.position().z(), 5042888.2271, abs <= 0.0001); + assert!(result_coords.velocity().is_none()); + assert_float_eq!( + result_coords.epoch().to_fractional_year_hardcoded(), + 2023.15, + abs <= 0.01 + ); + assert_eq!( + result_coords.reference_frame(), + ReferenceFrame::DREF91_R2016 + ); +}