diff --git a/swiftnav/src/math.rs b/swiftnav/src/math.rs index f66099a..47977fb 100644 --- a/swiftnav/src/math.rs +++ b/swiftnav/src/math.rs @@ -29,6 +29,7 @@ pub(crate) const fn compile_time_max_u16(a: u16, b: u16) -> u16 { /// /// # Panics /// +/// - This function will panic if the given number is NOT between 0.0 and 1.0. /// - This function will panic if the computation does not converge within 100 iterations. /// /// # Notes @@ -37,6 +38,11 @@ pub(crate) const fn compile_time_max_u16(a: u16, b: u16) -> u16 { /// - The algorithm iteratively refines the approximation of the square root until the result stabilizes. #[expect(clippy::many_single_char_names, reason = "It's math, whatyagonnado?")] pub(crate) const fn compile_time_sqrt(s: f64) -> f64 { + assert!( + s >= 0.0 && s <= 1.0, + "Can only compute square root of numbers between 0 and 1" + ); + let mut x = s; let mut y = 0.0_f64; let mut z; @@ -71,3 +77,22 @@ pub(crate) fn ecef2ned_matrix(llh: crate::coords::LLHRadians) -> nalgebra::Matri -sin_lat, ) } + +#[cfg(test)] +mod tests { + use super::*; + use float_eq::assert_float_eq; + use proptest::prelude::*; + + proptest! { + #![proptest_config(ProptestConfig::with_cases(1000))] + + /// Property: Converting LLH->ECEF->LLH should always result in the original value + #[test] + fn newton_sqrt(x in 0.0..=1.0) { + let newton_approx = compile_time_sqrt(x); + let sqrt = x.sqrt(); + assert_float_eq!(sqrt, newton_approx, ulps <= 1, "Newton approximation of square root doesn't match IEEE sqrt! (Newton: {}, IEEE: {})", newton_approx, sqrt); + } + } +} diff --git a/swiftnav/src/reference_frame/mod.rs b/swiftnav/src/reference_frame/mod.rs index fefad79..b78df34 100644 --- a/swiftnav/src/reference_frame/mod.rs +++ b/swiftnav/src/reference_frame/mod.rs @@ -75,6 +75,7 @@ //! use crate::coords::{Coordinate, ECEF}; +use nalgebra::{Matrix3, Vector3}; use std::{ collections::{HashMap, HashSet, VecDeque}, fmt, @@ -168,20 +169,12 @@ pub enum ReferenceFrame { /// formulation of the Helmert transformation. #[derive(Debug, PartialEq, PartialOrd, Clone, Copy)] pub struct TimeDependentHelmertParams { - tx: f64, - tx_dot: f64, - ty: f64, - ty_dot: f64, - tz: f64, - tz_dot: f64, + t: Vector3, + t_dot: Vector3, s: f64, s_dot: f64, - rx: f64, - rx_dot: f64, - ry: f64, - ry_dot: f64, - rz: f64, - rz_dot: f64, + r: Vector3, + r_dot: Vector3, epoch: f64, } @@ -192,57 +185,42 @@ impl TimeDependentHelmertParams { /// Reverses the transformation. Since this is a linear transformation we simply negate all terms pub fn invert(&mut self) { - self.tx *= -1.0; - self.tx_dot *= -1.0; - self.ty *= -1.0; - self.ty_dot *= -1.0; - self.tz *= -1.0; - self.tz_dot *= -1.0; + self.t *= -1.0; + self.t_dot *= -1.0; self.s *= -1.0; self.s_dot *= -1.0; - self.rx *= -1.0; - self.rx_dot *= -1.0; - self.ry *= -1.0; - self.ry_dot *= -1.0; - self.rz *= -1.0; - self.rz_dot *= -1.0; + self.r *= -1.0; + self.r_dot *= -1.0; } /// Apply the transformation on a position at a specific epoch #[must_use] 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; - let tz = (self.tz + self.tz_dot * dt) * Self::TRANSLATE_SCALE; + let t = (self.t + self.t_dot * dt) * Self::TRANSLATE_SCALE; let s = (self.s + self.s_dot * dt) * Self::SCALE_SCALE; - let rx = (self.rx + self.rx_dot * dt) * Self::ROTATE_SCALE; - let ry = (self.ry + self.ry_dot * dt) * Self::ROTATE_SCALE; - let rz = (self.rz + self.rz_dot * dt) * Self::ROTATE_SCALE; + let r = (self.r + self.r_dot * dt) * Self::ROTATE_SCALE; - let x = position.x() + tx + (s * position.x()) + (-rz * position.y()) + (ry * position.z()); - let y = position.y() + ty + (rz * position.x()) + (s * position.y()) + (-rx * position.z()); - let z = position.z() + tz + (-ry * position.x()) + (rx * position.y()) + (s * position.z()); + let m = Self::make_rotation_matrix(s, r); - ECEF::new(x, y, z) + (position.as_vector() + t + m * position.as_vector()).into() } /// Apply the transformation on a velocity at a specific position #[must_use] 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; + let t = self.t_dot * Self::TRANSLATE_SCALE; let s = self.s_dot * Self::SCALE_SCALE; - let rx = self.rx_dot * Self::ROTATE_SCALE; - let ry = self.ry_dot * Self::ROTATE_SCALE; - let rz = self.rz_dot * Self::ROTATE_SCALE; + let r = self.r_dot * Self::ROTATE_SCALE; - let x = velocity.x() + tx + (s * position.x()) + (-rz * position.y()) + (ry * position.z()); - let y = velocity.y() + ty + (rz * position.x()) + (s * position.y()) + (-rx * position.z()); - let z = velocity.z() + tz + (-ry * position.x()) + (rx * position.y()) + (s * position.z()); + let m = Self::make_rotation_matrix(s, r); - ECEF::new(x, y, z) + (velocity.as_vector() + t + m * position.as_vector()).into() + } + + #[must_use] + fn make_rotation_matrix(s: f64, r: Vector3) -> Matrix3 { + Matrix3::new(s, -r.z, r.y, r.z, s, -r.x, -r.y, r.x, s) } } @@ -564,20 +542,20 @@ mod tests { #[test] fn helmert_position_translations() { let params = TimeDependentHelmertParams { - tx: 1.0 / TimeDependentHelmertParams::TRANSLATE_SCALE, - tx_dot: 0.1 / TimeDependentHelmertParams::TRANSLATE_SCALE, - ty: 2.0 / TimeDependentHelmertParams::TRANSLATE_SCALE, - ty_dot: 0.2 / TimeDependentHelmertParams::TRANSLATE_SCALE, - tz: 3.0 / TimeDependentHelmertParams::TRANSLATE_SCALE, - tz_dot: 0.3 / TimeDependentHelmertParams::TRANSLATE_SCALE, + t: Vector3::new( + 1.0 / TimeDependentHelmertParams::TRANSLATE_SCALE, + 2.0 / TimeDependentHelmertParams::TRANSLATE_SCALE, + 3.0 / TimeDependentHelmertParams::TRANSLATE_SCALE, + ), + t_dot: Vector3::new( + 0.1 / TimeDependentHelmertParams::TRANSLATE_SCALE, + 0.2 / TimeDependentHelmertParams::TRANSLATE_SCALE, + 0.3 / TimeDependentHelmertParams::TRANSLATE_SCALE, + ), s: 0.0, 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, + r: Vector3::new(0.0, 0.0, 0.0), + r_dot: Vector3::new(0.0, 0.0, 0.0), epoch: 2010.0, }; let initial_position = ECEF::default(); @@ -596,20 +574,12 @@ mod tests { #[test] fn helmert_position_scaling() { let params = TimeDependentHelmertParams { - tx: 0.0, - tx_dot: 0.0, - ty: 0.0, - ty_dot: 0.0, - tz: 0.0, - tz_dot: 0.0, + t: Vector3::new(0.0, 0.0, 0.0), + t_dot: Vector3::new(0.0, 0.0, 0.0), s: 1.0 / TimeDependentHelmertParams::SCALE_SCALE, s_dot: 0.1 / TimeDependentHelmertParams::SCALE_SCALE, - rx: 90.0, - rx_dot: 0.0, - ry: 0.0, - ry_dot: 0.0, - rz: 0.0, - rz_dot: 0.0, + r: Vector3::new(90.0, 0.0, 0.0), + r_dot: Vector3::new(0.0, 0.0, 0.0), epoch: 2010.0, }; let initial_position = ECEF::new(1., 2., 3.); @@ -628,20 +598,20 @@ mod tests { #[test] fn helmert_position_rotations() { let params = TimeDependentHelmertParams { - tx: 0.0, - tx_dot: 0.0, - ty: 0.0, - ty_dot: 0.0, - tz: 0.0, - tz_dot: 0.0, + t: Vector3::new(0.0, 0.0, 0.0), + t_dot: Vector3::new(0.0, 0.0, 0.0), s: 0.0, s_dot: 0.0, - rx: 1.0 / TimeDependentHelmertParams::ROTATE_SCALE, - rx_dot: 0.1 / TimeDependentHelmertParams::ROTATE_SCALE, - ry: 2.0 / TimeDependentHelmertParams::ROTATE_SCALE, - ry_dot: 0.2 / TimeDependentHelmertParams::ROTATE_SCALE, - rz: 3.0 / TimeDependentHelmertParams::ROTATE_SCALE, - rz_dot: 0.3 / TimeDependentHelmertParams::ROTATE_SCALE, + r: Vector3::new( + 1.0 / TimeDependentHelmertParams::ROTATE_SCALE, + 2.0 / TimeDependentHelmertParams::ROTATE_SCALE, + 3.0 / TimeDependentHelmertParams::ROTATE_SCALE, + ), + r_dot: Vector3::new( + 0.1 / TimeDependentHelmertParams::ROTATE_SCALE, + 0.2 / TimeDependentHelmertParams::ROTATE_SCALE, + 0.3 / TimeDependentHelmertParams::ROTATE_SCALE, + ), epoch: 2010.0, }; let initial_position = ECEF::new(1.0, 1.0, 1.0); @@ -660,20 +630,20 @@ mod tests { #[test] fn helmert_velocity_translations() { let params = TimeDependentHelmertParams { - tx: 1.0 / TimeDependentHelmertParams::TRANSLATE_SCALE, - tx_dot: 0.1 / TimeDependentHelmertParams::TRANSLATE_SCALE, - ty: 2.0 / TimeDependentHelmertParams::TRANSLATE_SCALE, - ty_dot: 0.2 / TimeDependentHelmertParams::TRANSLATE_SCALE, - tz: 3.0 / TimeDependentHelmertParams::TRANSLATE_SCALE, - tz_dot: 0.3 / TimeDependentHelmertParams::TRANSLATE_SCALE, + t: Vector3::new( + 1.0 / TimeDependentHelmertParams::TRANSLATE_SCALE, + 2.0 / TimeDependentHelmertParams::TRANSLATE_SCALE, + 3.0 / TimeDependentHelmertParams::TRANSLATE_SCALE, + ), + t_dot: Vector3::new( + 0.1 / TimeDependentHelmertParams::TRANSLATE_SCALE, + 0.2 / TimeDependentHelmertParams::TRANSLATE_SCALE, + 0.3 / TimeDependentHelmertParams::TRANSLATE_SCALE, + ), s: 0.0, 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, + r: Vector3::new(0.0, 0.0, 0.0), + r_dot: Vector3::new(0.0, 0.0, 0.0), epoch: 2010.0, }; let initial_velocity = ECEF::default(); @@ -688,20 +658,12 @@ mod tests { #[test] fn helmert_velocity_scaling() { let params = TimeDependentHelmertParams { - tx: 0.0, - tx_dot: 0.0, - ty: 0.0, - ty_dot: 0.0, - tz: 0.0, - tz_dot: 0.0, + t: Vector3::new(0.0, 0.0, 0.0), + t_dot: Vector3::new(0.0, 0.0, 0.0), s: 1.0 / TimeDependentHelmertParams::SCALE_SCALE, s_dot: 0.1 / TimeDependentHelmertParams::SCALE_SCALE, - rx: 90.0, - rx_dot: 0.0, - ry: 0.0, - ry_dot: 0.0, - rz: 0.0, - rz_dot: 0.0, + r: Vector3::new(90.0, 0.0, 0.0), + r_dot: Vector3::new(0.0, 0.0, 0.0), epoch: 2010.0, }; let initial_velocity = ECEF::default(); @@ -716,20 +678,20 @@ mod tests { #[test] fn helmert_velocity_rotations() { let params = TimeDependentHelmertParams { - tx: 0.0, - tx_dot: 0.0, - ty: 0.0, - ty_dot: 0.0, - tz: 0.0, - tz_dot: 0.0, + t: Vector3::new(0.0, 0.0, 0.0), + t_dot: Vector3::new(0.0, 0.0, 0.0), s: 0.0, s_dot: 0.0, - rx: 1.0 / TimeDependentHelmertParams::ROTATE_SCALE, - rx_dot: 0.1 / TimeDependentHelmertParams::ROTATE_SCALE, - ry: 2.0 / TimeDependentHelmertParams::ROTATE_SCALE, - ry_dot: 0.2 / TimeDependentHelmertParams::ROTATE_SCALE, - rz: 3.0 / TimeDependentHelmertParams::ROTATE_SCALE, - rz_dot: 0.3 / TimeDependentHelmertParams::ROTATE_SCALE, + r: Vector3::new( + 1.0 / TimeDependentHelmertParams::ROTATE_SCALE, + 2.0 / TimeDependentHelmertParams::ROTATE_SCALE, + 3.0 / TimeDependentHelmertParams::ROTATE_SCALE, + ), + r_dot: Vector3::new( + 0.1 / TimeDependentHelmertParams::ROTATE_SCALE, + 0.2 / TimeDependentHelmertParams::ROTATE_SCALE, + 0.3 / TimeDependentHelmertParams::ROTATE_SCALE, + ), epoch: 2010.0, }; let initial_velocity = ECEF::default(); @@ -744,53 +706,45 @@ mod tests { #[test] fn helmert_invert() { let mut params = TimeDependentHelmertParams { - tx: 1.0, - tx_dot: 0.1, - ty: 2.0, - ty_dot: 0.2, - tz: 3.0, - tz_dot: 0.3, + t: Vector3::new(1.0, 2.0, 3.0), + t_dot: Vector3::new(0.1, 0.2, 0.3), s: 4.0, s_dot: 0.4, - rx: 5.0, - rx_dot: 0.5, - ry: 6.0, - ry_dot: 0.6, - rz: 7.0, - rz_dot: 0.7, + r: Vector3::new(5.0, 6.0, 7.0), + r_dot: Vector3::new(0.5, 0.6, 0.7), epoch: 2010.0, }; params.invert(); - assert_float_eq!(params.tx, -1.0, abs_all <= 1e-4); - assert_float_eq!(params.tx_dot, -0.1, abs_all <= 1e-4); - assert_float_eq!(params.ty, -2.0, abs_all <= 1e-4); - assert_float_eq!(params.ty_dot, -0.2, abs_all <= 1e-4); - assert_float_eq!(params.tz, -3.0, abs_all <= 1e-4); - assert_float_eq!(params.tz_dot, -0.3, abs_all <= 1e-4); + assert_float_eq!(params.t.x, -1.0, abs_all <= 1e-4); + assert_float_eq!(params.t_dot.x, -0.1, abs_all <= 1e-4); + assert_float_eq!(params.t.y, -2.0, abs_all <= 1e-4); + assert_float_eq!(params.t_dot.y, -0.2, abs_all <= 1e-4); + assert_float_eq!(params.t.z, -3.0, abs_all <= 1e-4); + assert_float_eq!(params.t_dot.z, -0.3, abs_all <= 1e-4); assert_float_eq!(params.s, -4.0, abs_all <= 1e-4); assert_float_eq!(params.s_dot, -0.4, abs_all <= 1e-4); - assert_float_eq!(params.rx, -5.0, abs_all <= 1e-4); - assert_float_eq!(params.rx_dot, -0.5, abs_all <= 1e-4); - assert_float_eq!(params.ry, -6.0, abs_all <= 1e-4); - assert_float_eq!(params.ry_dot, -0.6, abs_all <= 1e-4); - assert_float_eq!(params.rz, -7.0, abs_all <= 1e-4); - assert_float_eq!(params.rz_dot, -0.7, abs_all <= 1e-4); + assert_float_eq!(params.r.x, -5.0, abs_all <= 1e-4); + assert_float_eq!(params.r_dot.x, -0.5, abs_all <= 1e-4); + assert_float_eq!(params.r.y, -6.0, abs_all <= 1e-4); + assert_float_eq!(params.r_dot.y, -0.6, abs_all <= 1e-4); + assert_float_eq!(params.r.z, -7.0, abs_all <= 1e-4); + assert_float_eq!(params.r_dot.z, -0.7, abs_all <= 1e-4); assert_float_eq!(params.epoch, 2010.0, abs_all <= 1e-4); params.invert(); - assert_float_eq!(params.tx, 1.0, abs_all <= 1e-4); - assert_float_eq!(params.tx_dot, 0.1, abs_all <= 1e-4); - assert_float_eq!(params.ty, 2.0, abs_all <= 1e-4); - assert_float_eq!(params.ty_dot, 0.2, abs_all <= 1e-4); - assert_float_eq!(params.tz, 3.0, abs_all <= 1e-4); - assert_float_eq!(params.tz_dot, 0.3, abs_all <= 1e-4); + assert_float_eq!(params.t.x, 1.0, abs_all <= 1e-4); + assert_float_eq!(params.t_dot.x, 0.1, abs_all <= 1e-4); + assert_float_eq!(params.t.y, 2.0, abs_all <= 1e-4); + assert_float_eq!(params.t_dot.y, 0.2, abs_all <= 1e-4); + assert_float_eq!(params.t.z, 3.0, abs_all <= 1e-4); + assert_float_eq!(params.t_dot.z, 0.3, abs_all <= 1e-4); assert_float_eq!(params.s, 4.0, abs_all <= 1e-4); assert_float_eq!(params.s_dot, 0.4, abs_all <= 1e-4); - assert_float_eq!(params.rx, 5.0, abs_all <= 1e-4); - assert_float_eq!(params.rx_dot, 0.5, abs_all <= 1e-4); - assert_float_eq!(params.ry, 6.0, abs_all <= 1e-4); - assert_float_eq!(params.ry_dot, 0.6, abs_all <= 1e-4); - assert_float_eq!(params.rz, 7.0, abs_all <= 1e-4); - assert_float_eq!(params.rz_dot, 0.7, abs_all <= 1e-4); + assert_float_eq!(params.r.x, 5.0, abs_all <= 1e-4); + assert_float_eq!(params.r_dot.x, 0.5, abs_all <= 1e-4); + assert_float_eq!(params.r.y, 6.0, abs_all <= 1e-4); + assert_float_eq!(params.r_dot.y, 0.6, abs_all <= 1e-4); + assert_float_eq!(params.r.z, 7.0, abs_all <= 1e-4); + assert_float_eq!(params.r_dot.z, 0.7, abs_all <= 1e-4); assert_float_eq!(params.epoch, 2010.0, abs_all <= 1e-4); } diff --git a/swiftnav/src/reference_frame/params.rs b/swiftnav/src/reference_frame/params.rs index a993148..3649019 100644 --- a/swiftnav/src/reference_frame/params.rs +++ b/swiftnav/src/reference_frame/params.rs @@ -1,3 +1,5 @@ +use nalgebra::Vector3; + use super::{ReferenceFrame, TimeDependentHelmertParams, Transformation}; pub const TRANSFORMATIONS: [Transformation; 34] = [ @@ -5,20 +7,12 @@ pub const TRANSFORMATIONS: [Transformation; 34] = [ 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, + t: Vector3::new(-1.4, -0.9, 1.4), + t_dot: Vector3::new(0.0, -0.1, 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, + r: Vector3::new(0.0, 0.0, 0.0), + r_dot: Vector3::new(0.0, 0.0, 0.0), epoch: 2015.0, }, }, @@ -26,20 +20,12 @@ pub const TRANSFORMATIONS: [Transformation; 34] = [ 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, + t: Vector3::new(0.2, 1.0, 3.3), + t_dot: Vector3::new(0.0, -0.1, 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, + r: Vector3::new(0.0, 0.0, 0.0), + r_dot: Vector3::new(0.0, 0.0, 0.0), epoch: 2015.0, }, }, @@ -47,20 +33,12 @@ pub const TRANSFORMATIONS: [Transformation; 34] = [ 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, + t: Vector3::new(2.7, 0.1, -1.4), + t_dot: Vector3::new(0.3, -0.1, 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, + r: Vector3::new(0.0, 0.0, 0.0), + r_dot: Vector3::new(0.0, 0.0, 0.0), epoch: 2015.0, }, }, @@ -68,20 +46,12 @@ pub const TRANSFORMATIONS: [Transformation; 34] = [ 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, + t: Vector3::new(-0.2, 0.8, -34.2), + t_dot: Vector3::new(0.1, 0.0, -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, + r: Vector3::new(0.0, 0.0, 0.0), + r_dot: Vector3::new(0.0, 0.0, 0.0), epoch: 2015.0, }, }, @@ -89,20 +59,12 @@ pub const TRANSFORMATIONS: [Transformation; 34] = [ 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, + t: Vector3::new(6.5, -3.9, -77.9), + t_dot: Vector3::new(0.1, -0.6, -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, + r: Vector3::new(0.0, 0.0, 0.36), + r_dot: Vector3::new(0.0, 0.0, 0.02), epoch: 2015.0, }, }, @@ -110,20 +72,12 @@ pub const TRANSFORMATIONS: [Transformation; 34] = [ 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, + t: Vector3::new(6.5, -3.9, -77.9), + t_dot: Vector3::new(0.1, -0.6, -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, + r: Vector3::new(0.0, 0.0, 0.36), + r_dot: Vector3::new(0.0, 0.0, 0.02), epoch: 2015.0, }, }, @@ -131,20 +85,12 @@ pub const TRANSFORMATIONS: [Transformation; 34] = [ 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, + t: Vector3::new(6.5, -3.9, -77.9), + t_dot: Vector3::new(0.1, -0.6, -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, + r: Vector3::new(0.0, 0.0, 0.36), + r_dot: Vector3::new(0.0, 0.0, 0.02), epoch: 2015.0, }, }, @@ -152,20 +98,12 @@ pub const TRANSFORMATIONS: [Transformation; 34] = [ 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, + t: Vector3::new(-65.8, 1.9, -71.3), + t_dot: Vector3::new(-2.8, -0.2, -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, + r: Vector3::new(-3.36, -4.33, 0.75), + r_dot: Vector3::new(-0.11, -0.19, 0.07), epoch: 2015.0, }, }, @@ -173,20 +111,12 @@ pub const TRANSFORMATIONS: [Transformation; 34] = [ 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, + t: Vector3::new(14.5, -1.9, -85.9), + t_dot: Vector3::new(0.1, -0.6, -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, + r: Vector3::new(0.00, 0.00, 0.36), + r_dot: Vector3::new(0.00, 0.00, 0.02), epoch: 2015.0, }, }, @@ -194,20 +124,12 @@ pub const TRANSFORMATIONS: [Transformation; 34] = [ 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, + t: Vector3::new(26.5, 12.1, -91.9), + t_dot: Vector3::new(0.1, -0.6, -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, + r: Vector3::new(0.00, 0.00, 0.36), + r_dot: Vector3::new(0.00, 0.00, 0.02), epoch: 2015.0, }, }, @@ -215,20 +137,12 @@ pub const TRANSFORMATIONS: [Transformation; 34] = [ 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, + t: Vector3::new(24.5, 8.1, -107.9), + t_dot: Vector3::new(0.1, -0.6, -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, + r: Vector3::new(0.00, 0.00, 0.36), + r_dot: Vector3::new(0.00, 0.00, 0.02), epoch: 2015.0, }, }, @@ -236,20 +150,12 @@ pub const TRANSFORMATIONS: [Transformation; 34] = [ 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, + t: Vector3::new(29.5, 32.1, -145.9), + t_dot: Vector3::new(0.1, -0.6, -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, + r: Vector3::new(0.00, 0.00, 0.36), + r_dot: Vector3::new(0.00, 0.00, 0.02), epoch: 2015.0, }, }, @@ -257,20 +163,12 @@ pub const TRANSFORMATIONS: [Transformation; 34] = [ 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, + t: Vector3::new(24.5, -3.9, -169.9), + t_dot: Vector3::new(0.1, -0.6, -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, + r: Vector3::new(0.10, 0.00, 0.36), + r_dot: Vector3::new(0.00, 0.00, 0.02), epoch: 2015.0, }, }, @@ -278,20 +176,12 @@ pub const TRANSFORMATIONS: [Transformation; 34] = [ 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, + t: Vector3::new(0.0, 0.0, 0.0), + t_dot: Vector3::new(0.0, 0.0, 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, + r: Vector3::new(0.0, 0.0, 0.0), + r_dot: Vector3::new(0.086, 0.519, -0.753), epoch: 1989.0, }, }, @@ -299,20 +189,12 @@ pub const TRANSFORMATIONS: [Transformation; 34] = [ 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, + t: Vector3::new(0.0, 0.0, 0.0), + t_dot: Vector3::new(0.0, 0.0, 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, + r: Vector3::new(0.0, 0.0, 0.0), + r_dot: Vector3::new(0.085, 0.531, -0.770), epoch: 1989.0, }, }, @@ -320,20 +202,12 @@ pub const TRANSFORMATIONS: [Transformation; 34] = [ 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, + t: Vector3::new(56.0, 48.0, -37.0), + t_dot: Vector3::new(0.0, 0.0, 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, + r: Vector3::new(0.0, 0.0, 0.0), + r_dot: Vector3::new(0.054, 0.518, -0.781), epoch: 1989.0, }, }, @@ -341,20 +215,12 @@ pub const TRANSFORMATIONS: [Transformation; 34] = [ 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, + t: Vector3::new(54.0, 51.0, -48.0), + t_dot: Vector3::new(0.0, 0.0, 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, + r: Vector3::new(0.0, 0.0, 0.0), + r_dot: Vector3::new(0.081, 0.490, -0.792), epoch: 1989.0, }, }, @@ -362,20 +228,12 @@ pub const TRANSFORMATIONS: [Transformation; 34] = [ 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, + t: Vector3::new(41.0, 41.0, -49.0), + t_dot: Vector3::new(0.0, 0.0, 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, + r: Vector3::new(0.0, 0.0, 0.0), + r_dot: Vector3::new(0.200, 0.500, -0.650), epoch: 1989.0, }, }, @@ -383,20 +241,12 @@ pub const TRANSFORMATIONS: [Transformation; 34] = [ 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, + t: Vector3::new(41.0, 41.0, -49.0), + t_dot: Vector3::new(0.0, 0.0, 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, + r: Vector3::new(0.0, 0.0, 0.0), + r_dot: Vector3::new(0.200, 0.500, -0.650), epoch: 1989.0, }, }, @@ -404,20 +254,12 @@ pub const TRANSFORMATIONS: [Transformation; 34] = [ 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, + t: Vector3::new(41.0, 41.0, -49.0), + t_dot: Vector3::new(0.0, 0.0, 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, + r: Vector3::new(0.0, 0.0, 0.0), + r_dot: Vector3::new(0.200, 0.500, -0.650), epoch: 1989.0, }, }, @@ -425,20 +267,12 @@ pub const TRANSFORMATIONS: [Transformation; 34] = [ 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, + t: Vector3::new(19.0, 53.0, -21.0), + t_dot: Vector3::new(0.0, 0.0, 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, + r: Vector3::new(0.0, 0.0, 0.0), + r_dot: Vector3::new(0.320, 0.780, -0.670), epoch: 1989.0, }, }, @@ -446,20 +280,12 @@ pub const TRANSFORMATIONS: [Transformation; 34] = [ 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, + t: Vector3::new(38.0, 40.0, -37.0), + t_dot: Vector3::new(0.0, 0.0, 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, + r: Vector3::new(0.0, 0.0, 0.0), + r_dot: Vector3::new(0.210, 0.520, -0.680), epoch: 1989.0, }, }, @@ -467,20 +293,12 @@ pub const TRANSFORMATIONS: [Transformation; 34] = [ 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, + t: Vector3::new(21.0, 25.0, -37.0), + t_dot: Vector3::new(0.0, 0.0, 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, + r: Vector3::new(0.0, 0.0, 0.0), + r_dot: Vector3::new(0.210, 0.520, -0.680), epoch: 1989.0, }, }, @@ -488,20 +306,12 @@ pub const TRANSFORMATIONS: [Transformation; 34] = [ 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, + t: Vector3::new(19.0, 28.0, -23.0), + t_dot: Vector3::new(0.0, 0.0, 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, + r: Vector3::new(0.0, 0.0, 0.0), + r_dot: Vector3::new(0.110, 0.570, -0.710), epoch: 1989.0, }, }, @@ -509,20 +319,12 @@ pub const TRANSFORMATIONS: [Transformation; 34] = [ 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, + t: Vector3::new(0.0, 0.0, 0.0), + t_dot: Vector3::new(0.0, 0.0, 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, + r: Vector3::new(0.0, 0.0, 0.0), + r_dot: Vector3::new(0.110, 0.570, -0.710), epoch: 1989.0, }, }, @@ -530,20 +332,12 @@ pub const TRANSFORMATIONS: [Transformation; 34] = [ 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, + t: Vector3::new(1005.30, -1909.21, -541.57), + t_dot: Vector3::new(0.79, -0.60, -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, + r: Vector3::new(-26.78138, 0.42027, -10.93206), + r_dot: Vector3::new(-0.06667, 0.75744, 0.05133), epoch: 2010.0, }, }, @@ -551,20 +345,12 @@ pub const TRANSFORMATIONS: [Transformation; 34] = [ 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, + t: Vector3::new(0.0, 0.0, 0.0), + t_dot: Vector3::new(0.0, 0.0, 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, + r: Vector3::new(0.0, 0.0, 0.0), + r_dot: Vector3::new(0.085, 0.531, -0.770), epoch: 1989.0, }, }, @@ -572,20 +358,12 @@ pub const TRANSFORMATIONS: [Transformation; 34] = [ 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, + t: Vector3::new(1003.70, -1911.11, -543.97), + t_dot: Vector3::new(0.79, -0.60, -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, + r: Vector3::new(-26.78138, 0.42027, -10.93206), + r_dot: Vector3::new(-0.06667, 0.75744, 0.05133), epoch: 2010.0, }, }, @@ -593,20 +371,12 @@ pub const TRANSFORMATIONS: [Transformation; 34] = [ 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, + t: Vector3::new(1005.30, -1909.21, -541.57), + t_dot: Vector3::new(0.79, -0.60, -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, + r: Vector3::new(-26.78138, 0.42027, -10.93206), + r_dot: Vector3::new(-0.06667, 0.75744, 0.05133), epoch: 2010.0, }, }, @@ -614,20 +384,12 @@ pub const TRANSFORMATIONS: [Transformation; 34] = [ 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, + t: Vector3::new(1003.90, -1909.61, -541.17), + t_dot: Vector3::new(0.79, -0.70, -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, + r: Vector3::new(-26.78138, 0.42027, -10.93206), + r_dot: Vector3::new(-0.06667, 0.75744, 0.05133), epoch: 2010.0, }, }, @@ -635,20 +397,12 @@ pub const TRANSFORMATIONS: [Transformation; 34] = [ 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, + t: Vector3::new(-3.0821, 95.0769, -73.5435), + t_dot: Vector3::new(-20.3181, -20.3593, 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, + r: Vector3::new(2.5445, 17.6078, -27.6123), + r_dot: Vector3::new(-0.5966, 1.4967, -0.5284), epoch: 2021.0, }, }, @@ -657,20 +411,12 @@ pub const TRANSFORMATIONS: [Transformation; 34] = [ from: ReferenceFrame::ITRF2020, to: ReferenceFrame::WGS84_G2296, params: TimeDependentHelmertParams { - tx: 0.0, - tx_dot: 0.0, - ty: 0.0, - ty_dot: 0.0, - tz: 0.0, - tz_dot: 0.0, + t: Vector3::new(0.0, 0.0, 0.0), + t_dot: Vector3::new(0.0, 0.0, 0.0), s: 0.0, 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, + r: Vector3::new(0.0, 0.0, 0.0), + r_dot: Vector3::new(0.0, 0.0, 0.0), epoch: 2024.0, }, }, @@ -679,20 +425,12 @@ pub const TRANSFORMATIONS: [Transformation; 34] = [ from: ReferenceFrame::ITRF2014, to: ReferenceFrame::WGS84_G2139, params: TimeDependentHelmertParams { - tx: 0.0, - tx_dot: 0.0, - ty: 0.0, - ty_dot: 0.0, - tz: 0.0, - tz_dot: 0.0, + t: Vector3::new(0.0, 0.0, 0.0), + t_dot: Vector3::new(0.0, 0.0, 0.0), s: 0.0, 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, + r: Vector3::new(0.0, 0.0, 0.0), + r_dot: Vector3::new(0.0, 0.0, 0.0), epoch: 2016.0, }, }, @@ -701,20 +439,12 @@ pub const TRANSFORMATIONS: [Transformation; 34] = [ from: ReferenceFrame::ITRF2008, to: ReferenceFrame::WGS84_G1762, params: TimeDependentHelmertParams { - tx: 0.0, - tx_dot: 0.0, - ty: 0.0, - ty_dot: 0.0, - tz: 0.0, - tz_dot: 0.0, + t: Vector3::new(0.0, 0.0, 0.0), + t_dot: Vector3::new(0.0, 0.0, 0.0), s: 0.0, 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, + r: Vector3::new(0.0, 0.0, 0.0), + r_dot: Vector3::new(0.0, 0.0, 0.0), epoch: 2005.0, }, },