diff --git a/src/structure/records/mod.rs b/src/structure/records/mod.rs deleted file mode 100644 index 732d96b3..00000000 --- a/src/structure/records/mod.rs +++ /dev/null @@ -1,19 +0,0 @@ -/* - * ANISE Toolkit - * Copyright (C) 2021-2023 Christopher Rabotin et al. (cf. AUTHORS.md) - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * Documentation: https://nyxspace.com/ - */ -use der::{Decode, Encode}; - -use crate::prelude::AniseError; - -pub trait Record<'a>: Encode + Decode<'a> { - /// Returns whether or not the integrity of the data is correct. - fn check_integrity(&self) -> Result<(), AniseError> { - Ok(()) - } -} diff --git a/src/structure/save.rs b/src/structure/save.rs deleted file mode 100644 index 03f190f2..00000000 --- a/src/structure/save.rs +++ /dev/null @@ -1,72 +0,0 @@ -/* - * ANISE Toolkit - * Copyright (C) 2021-2023 Christopher Rabotin et al. (cf. AUTHORS.md) - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * Documentation: https://nyxspace.com/ - */ - -use crate::errors::{AniseError, InternalErrorKind}; -use der::{Decode, Encode}; -use log::warn; -use std::fs::File; -use std::io::Write; -use std::path::Path; - -/// A trait to encode / decode ANISE specific data. -pub trait Asn1Serde<'a>: Encode + Decode<'a> { - /// Saves this context in the providef filename. - /// If overwrite is set to false, and the filename already exists, this function will return an error. - fn save_as(&self, filename: &'a str, overwrite: bool) -> Result<(), AniseError> { - match self.encoded_len() { - Err(e) => Err(AniseError::InternalError(e.into())), - Ok(length) => { - let len: u32 = length.into(); - // Fill the vector with zeros - let mut buf = vec![0x0; len as usize]; - self.save_as_via_buffer(filename, overwrite, &mut buf) - } - } - } - - /// Saves this context in the providef filename. - /// If overwrite is set to false, and the filename already exists, this function will return an error. - fn save_as_via_buffer( - &self, - filename: &'a str, - overwrite: bool, - buf: &mut [u8], - ) -> Result<(), AniseError> { - if Path::new(filename).exists() { - if !overwrite { - return Err(AniseError::FileExists); - } else { - warn!("[save_as] overwriting {filename}"); - } - } - - match File::create(filename) { - Ok(mut file) => { - if let Err(e) = self.encode_to_slice(buf) { - return Err(InternalErrorKind::Asn1Error(e).into()); - } - if let Err(e) = file.write_all(buf) { - Err(e.kind().into()) - } else { - Ok(()) - } - } - Err(e) => Err(e.kind().into()), - } - } - - /// Attempts to load this data from its bytes - fn try_from_bytes(bytes: &'a [u8]) -> Result { - match Self::from_der(bytes) { - Ok(yay) => Ok(yay), - Err(e) => Err(AniseError::DecodingError(e)), - } - } -} diff --git a/src/structure/spline/covkind.rs b/src/structure/spline/covkind.rs deleted file mode 100644 index 8c05e422..00000000 --- a/src/structure/spline/covkind.rs +++ /dev/null @@ -1,188 +0,0 @@ -/* - * ANISE Toolkit - * Copyright (C) 2021-2023 Christopher Rabotin et al. (cf. AUTHORS.md) - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * Documentation: https://nyxspace.com/ - */ -use der::{Decode, Encode, Reader, Writer}; - -use crate::DBL_SIZE; - -use super::statekind::StateKind; - -/// Covariance Kind defines what kind of covariance is stored in the spline, if at all. -/// Under the hood, this works exactly like [StateKind] since the CovKind structure has a single field `data` which is a StateKind. -/// -/// # Storage requirements and field ordering -/// Covariance information requires more data than just a state since it includes both the covariance and the variance between different elements. -/// In ANISE, this is stored as an upper triangular matrix. -/// -/// ## Position variance storage -/// -/// The order of the data is as follows: -/// 1. cov_x_x -/// 2. cov_y_x -/// 3. cov_y_y -/// 4. cov_z_x -/// 5. cov_z_y -/// 6. cov_z_z -/// -/// Hence, if the covariance is interpolated with a degree 6, then the position covariance of a single spline is stored as a contiguous octet array of 288 octets: -/// -/// | field | length | start octet | end octet -/// | -- | -- | -- | -- | -/// | cov_x_x | 6*8 = 48 | 0 | 47 -/// | cov_y_x | 6*8 = 48 | 48 | 95 -/// | cov_y_y | 48 | 96 | 143 -/// | cov_z_x | 48 | 144 | 191 -/// | cov_z_y | 48 | 192 | 239 -/// | cov_z_z | 48 | 240 | 287 -/// -/// ### Example -/// Storing the position and velocity covariance, interpolated as a 6 degree polynomial will require **6** fields of **6 * 8 = 48* octets each, leading to **288 octets per spline**. -/// -/// ## Position and velocity variance storage -/// -/// It is not possible to store the velocity variance without also storing the position variance. If we've missed a use case where this is relevant, please open an issue. -/// -/// Additional fields for the velocity variance. -/// -/// + cov_vx_x -/// + cov_vx_y -/// + cov_vx_z -/// + cov_vx_vx -/// -/// + cov_vy_x -/// + cov_vy_y -/// + cov_vy_z -/// + cov_vy_vx -/// + cov_vy_vy -/// -/// + cov_vz_x -/// + cov_vz_y -/// + cov_vz_z -/// + cov_vz_vx -/// + cov_vz_vy -/// + cov_vz_vz -/// -/// ### Example -/// Storing the position and velocity covariance, interpolated as a 6 degree polynomial will require **6 + 15 = 21** fields of **6 * 8 = 48* octets each, leading to **1008 octets per spline**. -/// -/// ## Position, velocity, and acceleration variance storage -/// -/// We also don't know of a use case where one would need to store the variance of the acceleration, but it's supported because the support is relatively easy. -/// **Warning:** this will add 7+8+9 = 24 fields, each storing one 64-bit floating point number _per interpolation degree_. -/// -/// + cov_ax_x -/// + cov_ax_y -/// + cov_ax_z -/// + cov_ax_vx -/// + cov_ax_vy -/// + cov_ax_vz -/// + cov_ax_ax -/// -/// + cov_ay_x -/// + cov_ay_y -/// + cov_ay_z -/// + cov_ay_vx -/// + cov_ay_vy -/// + cov_ay_vz -/// + cov_ay_ax -/// + cov_ay_ay -/// -/// + cov_az_x -/// + cov_az_y -/// + cov_az_z -/// + cov_az_vx -/// + cov_az_vy -/// + cov_az_vz -/// + cov_az_ax -/// + cov_az_ay -/// + cov_az_az -/// -/// ### Example -/// Storing the full covariance of position, velocity, and acceleration, interpolated as a 6 degree polynomial will require **6 + 15 + 24 = 45** fields of **6 * 8 = 48* octets each, leading to **2160 octets per spline**. - -#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord)] -pub struct CovKind { - pub(crate) data: StateKind, -} - -impl CovKind { - pub const fn is_empty(&self) -> bool { - self.len() == 0 - } - - /// Returns the length in octets required to store this covariance information - pub const fn len(&self) -> usize { - let num_items = match self.data { - StateKind::None => 0, - StateKind::Position { degree } => degree * 6, - StateKind::PositionVelocity { degree } => degree * (6 + 15), - StateKind::PositionVelocityAcceleration { degree } => degree * (6 + 15 + 21), - }; - DBL_SIZE * (num_items as usize) - } - - /// Returns the interpolation degree - pub const fn degree(&self) -> u8 { - match &self.data { - StateKind::None => 0, - StateKind::Position { degree } => *degree, - StateKind::PositionVelocity { degree } => *degree, - StateKind::PositionVelocityAcceleration { degree } => *degree, - } - } -} - -impl Default for CovKind { - fn default() -> Self { - Self { - data: StateKind::None, - } - } -} - -/// Allows conversion of the CovKind into a u8 with the following mapping. -impl From for u16 { - fn from(kind: CovKind) -> Self { - u16::from(kind.data) - } -} - -impl From<&CovKind> for u16 { - fn from(kind: &CovKind) -> Self { - u16::from(*kind) - } -} - -/// Allows conversion of a u8 into a CovKind. -impl From for CovKind { - fn from(val: u16) -> Self { - Self { - data: StateKind::from(val), - } - } -} - -impl Encode for CovKind { - fn encoded_len(&self) -> der::Result { - let converted: u16 = self.into(); - converted.encoded_len() - } - - fn encode(&self, encoder: &mut impl Writer) -> der::Result<()> { - let converted: u16 = self.into(); - converted.encode(encoder) - } -} - -impl<'a> Decode<'a> for CovKind { - fn decode>(decoder: &mut R) -> der::Result { - let converted: u16 = decoder.decode()?; - Ok(Self::from(converted)) - } -} diff --git a/src/structure/spline/evenness.rs b/src/structure/spline/evenness.rs deleted file mode 100644 index 13f25294..00000000 --- a/src/structure/spline/evenness.rs +++ /dev/null @@ -1,96 +0,0 @@ -/* - * ANISE Toolkit - * Copyright (C) 2021-2023 Christopher Rabotin et al. (cf. AUTHORS.md) - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * Documentation: https://nyxspace.com/ - */ -use der::{Decode, Encode, Reader, Tag, Writer}; - -use crate::DBL_SIZE; - -/// Splice Space defines whether this is an equal-time step interpolation spline (called `Even` splines in ANISE) or an unequal-time step spline (called `Uneven`). -/// -/// # Even splines -/// -/// These store data like what would typically be stored in the NAIF SPK Types 2, 3, 8, and 12. The interpolation of the trajectory is done over a fixed time window, e.g. 16 days. -/// In ANISE, a single interpolation spline must be less than 4000 years because the window duration is stored in nanoseconds on an unsigned integer. -/// -/// ## Querying -/// To query the set of coefficients needed for a given interpolation, the following algorithm applies given the desired epoch `epoch` as an input parameter. -/// 1. Compute `delta_ns`: the difference in nanoseconds between `epoch` and the ephemeris start epoch (making sure that both are in the same time system). -/// 2. Compute the spline index `spl_idx` by performing the integer division between `delta_ns` and the spline duration `duration_ns` (defined in the meta data of the splines). -/// 3. Seek through the byte string of the spline data by chunks of the spline length, which depends on the kind of data stored (Position, etc.) and the existence of not of covariance information. -/// -/// Defines the two kinds of spacing splines supports: equal time steps (fixed sized interpolation) or unequal time steps (also called sliding window) -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum Evenness { - Even { - duration_ns: u64, - }, - Uneven { - /// Unevenly spaced window ephemerides may only span five centuries to constraint stack size - indexes: [i16; 5], // TODO: Consider 10? Or just enough for DE in full. - }, -} - -impl Evenness { - pub const fn is_empty(&self) -> bool { - self.len() == 0 - } - - /// Returns the length in octets that precedes the spline coefficient data. - /// - /// For example, if this is set to 16, it means that the spline coefficient data starts at an offset of 16 compared to the start of the spline itself. - pub const fn len(&self) -> usize { - DBL_SIZE - * match self { - Self::Even { duration_ns: _ } => 1, - Self::Uneven { indexes: _ } => 2, - } - } -} - -impl Default for Evenness { - fn default() -> Self { - Self::Even { duration_ns: 0 } - } -} - -impl Encode for Evenness { - fn encoded_len(&self) -> der::Result { - match self { - Self::Even { duration_ns } => (*duration_ns).encoded_len(), - Self::Uneven { indexes: _indexes } => { - todo!() - } - } - } - - fn encode(&self, encoder: &mut impl Writer) -> der::Result<()> { - match self { - Self::Even { duration_ns } => (*duration_ns).encode(encoder), - Self::Uneven { indexes: _indexes } => { - todo!() - } - } - } -} - -impl<'a> Decode<'a> for Evenness { - fn decode>(decoder: &mut R) -> der::Result { - // Check the header tag to decode this CHOICE - if decoder.peek_tag()? == Tag::Integer { - Ok(Self::Even { - duration_ns: decoder.decode()?, - }) - } else { - decoder.sequence(|sdecoder| { - let indexes = sdecoder.decode()?; - Ok(Self::Uneven { indexes }) - }) - } - } -} diff --git a/src/structure/spline/field.rs b/src/structure/spline/field.rs deleted file mode 100644 index af94fbfb..00000000 --- a/src/structure/spline/field.rs +++ /dev/null @@ -1,135 +0,0 @@ -/* - * ANISE Toolkit - * Copyright (C) 2021-2023 Christopher Rabotin et al. (cf. AUTHORS.md) - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * Documentation: https://nyxspace.com/ - */ - -/// The fields that can be queried for spline data. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum Field { - MidPoint, - Duration, - X, - Y, - Z, - Vx, - Vy, - Vz, - Ax, - Ay, - Az, - CovXX, - CovYZ, - CovYY, - CovZX, - CovZY, - CovZZ, - CovVxX, - CovVxY, - CovVxZ, - CovVxVx, - CovVyX, - CovVyY, - CovVyZ, - CovVyVx, - CovVyVy, - CovVzX, - CovVzY, - CovVzZ, - CovVzVx, - CovVzVy, - CovVzVz, - CovAxX, - CovAxY, - CovAxZ, - CovAxVx, - CovAxVy, - CovAxVz, - CovAxAx, - CovAyX, - CovAyY, - CovAyZ, - CovAyVx, - CovAyVy, - CovAyVz, - CovAyAx, - CovAyAy, - CovAzX, - CovAzY, - CovAzZ, - CovAzVx, - CovAzVy, - CovAzVz, - CovAzAx, - CovAzAy, - CovAzAz, -} - -impl Field { - pub const fn is_position(&self) -> bool { - matches!(self, Self::X | Self::Y | Self::Z) - } - - pub const fn is_velocity(&self) -> bool { - matches!(self, Self::Vx | Self::Vy | Self::Vz) - } - - pub const fn is_acceleration(&self) -> bool { - matches!(self, Self::Ax | Self::Ay | Self::Az) - } - - pub const fn is_covariance(&self) -> bool { - matches!( - self, - Self::CovXX - | Self::CovYZ - | Self::CovYY - | Self::CovZX - | Self::CovZY - | Self::CovZZ - | Self::CovVxX - | Self::CovVxY - | Self::CovVxZ - | Self::CovVxVx - | Self::CovVyX - | Self::CovVyY - | Self::CovVyZ - | Self::CovVyVx - | Self::CovVyVy - | Self::CovVzX - | Self::CovVzY - | Self::CovVzZ - | Self::CovVzVx - | Self::CovVzVy - | Self::CovVzVz - | Self::CovAxX - | Self::CovAxY - | Self::CovAxZ - | Self::CovAxVx - | Self::CovAxVy - | Self::CovAxVz - | Self::CovAxAx - | Self::CovAyX - | Self::CovAyY - | Self::CovAyZ - | Self::CovAyVx - | Self::CovAyVy - | Self::CovAyVz - | Self::CovAyAx - | Self::CovAyAy - | Self::CovAzX - | Self::CovAzY - | Self::CovAzZ - | Self::CovAzVx - | Self::CovAzVy - | Self::CovAzVz - | Self::CovAzAx - | Self::CovAzAy - | Self::CovAzAz - ) - } -} diff --git a/src/structure/spline/meta.rs b/src/structure/spline/meta.rs deleted file mode 100644 index f5de130c..00000000 --- a/src/structure/spline/meta.rs +++ /dev/null @@ -1,115 +0,0 @@ -/* - * ANISE Toolkit - * Copyright (C) 2021-2023 Christopher Rabotin et al. (cf. AUTHORS.md) - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * Documentation: https://nyxspace.com/ - */ -use der::{Decode, Encode, Reader, Writer}; - -use crate::{prelude::AniseError, DBL_SIZE}; - -use super::{covkind::CovKind, evenness::Evenness, statekind::StateKind, Field}; - -#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)] - -pub struct SplineMeta { - /// Defines whether this is an evenly or unevenly timed spline - pub evenness: Evenness, - /// Defines what kind of state data is stored in this spline - pub state_kind: StateKind, - /// Defines what kind of covariance data is stored in this spline - pub cov_kind: CovKind, -} - -impl SplineMeta { - /// Returns the offset (in bytes) in the octet string - pub fn spline_offset(&self, idx: usize) -> usize { - idx * self.len() - } - - /// Returns the offset of this field in the spline given how this spline is set up. - /// This may return an error when requesting a field that is not available. - pub fn field_offset(&self, field: Field, coeff_idx: usize) -> Result { - // Make the field is valid in this spline. - if (self.cov_kind.is_empty() && field.is_covariance()) - || (!field.is_covariance() && self.state_kind.is_empty()) - { - Err(AniseError::ParameterNotSpecified) - } else { - // TODO Make sure the position data is also there. - // Padding from header (e.g. one double for even splines, two for uneven splines). - let header_padding = self.evenness.len(); - // Offset from the requested field (e.g. coefficients for X are stored before those for Y components). - let field_offset = match field { - Field::MidPoint => { - // Special case: the midpoint is always at the start of each spline. - return Ok(0); - } - Field::Duration => { - if header_padding == 2 { - // Special case: the duration of the spline is always the second item of each spline, if this spline type supports it - return Ok(DBL_SIZE); - } else { - return Err(AniseError::ParameterNotSpecified); - } - } - Field::X => 0, - Field::Y => 1, - Field::Z => 2, - Field::Vx => 3, - Field::Vy => 4, - Field::Vz => 5, - Field::Ax => 6, - Field::Ay => 7, - Field::Az => 8, - _ => unreachable!(), - }; - - // Offset to reach the correct coefficient given the index, e.g. to get the 3rd Y component, - // the total offset in the spline should be header_padding + 1 * num of coeffs + coefficient index. - Ok(header_padding - + field_offset * (self.state_kind.degree() as usize) * DBL_SIZE - + coeff_idx * DBL_SIZE) - } - } - - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - - /// Returns the length of a spline in bytes - pub fn len(&self) -> usize { - self.evenness.len() + self.state_kind.len() + self.cov_kind.len() - } -} - -impl Encode for SplineMeta { - fn encoded_len(&self) -> der::Result { - self.evenness.encoded_len()? - + self.state_kind.encoded_len()? - + self.cov_kind.encoded_len()? - } - - fn encode(&self, encoder: &mut impl Writer) -> der::Result<()> { - self.evenness.encode(encoder)?; - self.state_kind.encode(encoder)?; - self.cov_kind.encode(encoder) - } -} - -impl<'a> Decode<'a> for SplineMeta { - fn decode>(decoder: &mut R) -> der::Result { - let spacing = decoder.decode()?; - let state_kind = decoder.decode()?; - let cov_kind = decoder.decode()?; - - Ok(Self { - evenness: spacing, - state_kind, - cov_kind, - }) - } -} diff --git a/src/structure/spline/mod.rs b/src/structure/spline/mod.rs deleted file mode 100644 index 7eb542c3..00000000 --- a/src/structure/spline/mod.rs +++ /dev/null @@ -1,22 +0,0 @@ -/* - * ANISE Toolkit - * Copyright (C) 2021-2023 Christopher Rabotin et al. (cf. AUTHORS.md) - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * Documentation: https://nyxspace.com/ - */ - -mod covkind; -pub use covkind::*; -mod evenness; -pub use evenness::*; -mod meta; -pub use meta::*; -mod splines; -pub use splines::*; -mod statekind; -pub use statekind::*; -mod field; -pub use field::*; diff --git a/src/structure/spline/splines.rs b/src/structure/spline/splines.rs deleted file mode 100644 index c6cf133b..00000000 --- a/src/structure/spline/splines.rs +++ /dev/null @@ -1,62 +0,0 @@ -/* - * ANISE Toolkit - * Copyright (C) 2021-2023 Christopher Rabotin et al. (cf. AUTHORS.md) - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * Documentation: https://nyxspace.com/ - */ -use der::{asn1::OctetStringRef, Decode, Encode, Length, Reader, Writer}; - -use super::meta::SplineMeta; - -// #[derive(Enumerated)] -// #[repr(u8)] -// pub enum TruncationStrategy { -// None = 0, -// TruncateLow = 1, -// TruncateHigh = 2, -// } - -// WARNING: How do I specify the start and end epochs for variable sized windows where the duration in the window is needed to rebuild the state? -// Is that some kind of header? If so, what's its size? If it's a high precision epoch, it would be 80 bits, but more likely people will provide 64 bit floats. -// Also, I can't use an offset from the index because the splines are built separately from the index via multithreading, so that would be difficult to build (would need to mutate the spline prior to encoding) - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct Splines<'a> { - /// Metadata of the spline - pub metadata: SplineMeta, - // use AsBytes / FromBytes from "zerocopy" crate to load the data ? - /// Stores the CRC32 checksum of the data octet string. - pub data_checksum: u32, // TODO: move the checksum into a CRC32DataArray to check integrity on load - /// The data as a packed struct of octets - pub data: &'a [u8], -} - -impl<'a> Encode for Splines<'a> { - fn encoded_len(&self) -> der::Result { - self.metadata.encoded_len()? - + self.data_checksum.encoded_len()? - + OctetStringRef::new(self.data).unwrap().encoded_len()? - } - - fn encode(&self, encoder: &mut impl Writer) -> der::Result<()> { - self.metadata.encode(encoder)?; - self.data_checksum.encode(encoder)?; - OctetStringRef::new(self.data).unwrap().encode(encoder) - } -} - -impl<'a> Decode<'a> for Splines<'a> { - fn decode>(decoder: &mut R) -> der::Result { - let metadata = decoder.decode()?; - let data_checksum = decoder.decode()?; - let data_bytes: OctetStringRef = decoder.decode()?; - Ok(Self { - metadata, - data_checksum, - data: data_bytes.as_bytes(), - }) - } -} diff --git a/src/structure/spline/statekind.rs b/src/structure/spline/statekind.rs deleted file mode 100644 index 8124c96d..00000000 --- a/src/structure/spline/statekind.rs +++ /dev/null @@ -1,173 +0,0 @@ -/* - * ANISE Toolkit - * Copyright (C) 2021-2023 Christopher Rabotin et al. (cf. AUTHORS.md) - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * Documentation: https://nyxspace.com/ - */ -use der::{Decode, Encode, Reader, Writer}; - -use crate::DBL_SIZE; - -/// State Kind defines what kind of state is stored in the spline. -/// -/// # Limitations -/// 1. The interpolation degree of all items in the state must be identical. -/// 2. A constant position must be encoded as degree 1 whose sole coefficient is the constant value. -/// -/// ## Example -/// If the position is interpolated with an 11 degree polynomial, and the velocity must also be interpolated with an 11 degree polynomial. -/// -/// # Encoding / decoding -/// The state kind is encoded along with its degree as a single field in the ASN1 encoding scheme. -/// The interpolation degrees are expressed on an 8-bit unsigned integer whose maximum value is 255 (2^8 - 1). -/// Hence, to encode both the state kind and the interpolation degree, a spacing of 255 is used between each state kind. -/// -/// ASN1 encodes the tag and length as one octet each. Hence, position state metadata will always fit in exactly three octets: tag (1), length (1), degree (1). -/// Position and velocity data will fit in four octets: tag (1), length (1), data (2). And so on for each state kind. -/// Had the degree and state kind been stored as separate fields, we would be constantly using exactly six octets. -/// -/// The other advantage is that a single ASN1 tag decoding will yield both the state kind and the degree: this allows the code to store both the state kind and the degree in the same enumerate structure. -/// -/// ## Example -/// -/// | Encoded value | State Kind | Degree | -/// | -- | -- | -- | -/// | 1 | Position only | 1 -/// | 28 | Position only | 28 -/// | 266 | Position and Velocity | 266-255 = 11 -/// | 0 | None | _not applicable_ -/// -/// # Storage -/// -/// Position data will always require three fields (x, y, z). Velocity adds another three (vx, vy, vz), and so does acceleration (ax, ay, az). -/// -/// ## Example -/// Storing the position and velocity with an 11 degree polynomial will require 11*6 = 66 coefficient. Each coefficient is stored as packed structure of 8 octets floating point values in IEEE754 format. -/// Hence, this would require 66*8 = 528 octets per spline. -/// -#[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord)] -pub enum StateKind { - /// No state data at all, i.e. this spline only has covariance information - None, - Position { - degree: u8, - }, - PositionVelocity { - degree: u8, - }, - PositionVelocityAcceleration { - degree: u8, - }, -} - -impl StateKind { - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - - /// Returns the length in octets required to store this covariance information - pub fn len(&self) -> usize { - let num_items = match self { - StateKind::None => 0, - StateKind::Position { degree } => degree * 3, - StateKind::PositionVelocity { degree } => degree * 6, - StateKind::PositionVelocityAcceleration { degree } => degree * 9, - }; - DBL_SIZE * (num_items as usize) - } - - /// Returns the interpolation degree - pub const fn degree(&self) -> u8 { - match self { - StateKind::None => 0, - StateKind::Position { degree } => *degree, - StateKind::PositionVelocity { degree } => *degree, - StateKind::PositionVelocityAcceleration { degree } => *degree, - } - } - - /// Returns whether this state kind includes the position interpolation coefficients - pub const fn includes_position(&self) -> bool { - !matches!(self, Self::None) - } - - /// Returns whether this state kind includes velocity interpolation coefficients - pub const fn includes_velocity(&self) -> bool { - matches!( - self, - Self::PositionVelocity { degree: _ } | Self::PositionVelocityAcceleration { degree: _ } - ) - } - - /// Returns whether this state kind includes acceleration interpolation coefficients. - pub const fn includes_acceleration(&self) -> bool { - matches!(self, Self::PositionVelocityAcceleration { degree: _ }) - } -} - -impl Default for StateKind { - fn default() -> Self { - Self::None - } -} - -/// Allows conversion of the StateKind into a u8 with the following mapping. -impl From for u16 { - fn from(kind: StateKind) -> Self { - match kind { - StateKind::None => 0, - StateKind::Position { degree } => degree.into(), - StateKind::PositionVelocity { degree } => (u8::MAX + degree).into(), - StateKind::PositionVelocityAcceleration { degree } => { - 2_u16 * (u8::MAX as u16) + (degree as u16) - } - } - } -} - -impl From<&StateKind> for u16 { - fn from(kind: &StateKind) -> Self { - u16::from(*kind) - } -} - -/// Allows conversion of a u8 into a StateKind. -impl From for StateKind { - fn from(val: u16) -> Self { - if val == 0 { - Self::None - } else { - // Prevents an overflow and coerces the degree to be within the bounds of a u8, as per the specs. - let degree = (val % (u8::MAX as u16)) as u8; - if val < u8::MAX.into() { - Self::Position { degree } - } else if val < 2 * (u8::MAX as u16) { - Self::PositionVelocity { degree } - } else { - Self::PositionVelocityAcceleration { degree } - } - } - } -} - -impl Encode for StateKind { - fn encoded_len(&self) -> der::Result { - let converted: u16 = self.into(); - converted.encoded_len() - } - - fn encode(&self, encoder: &mut impl Writer) -> der::Result<()> { - let converted: u16 = self.into(); - converted.encode(encoder) - } -} - -impl<'a> Decode<'a> for StateKind { - fn decode>(decoder: &mut R) -> der::Result { - let converted: u16 = decoder.decode()?; - Ok(Self::from(converted)) - } -}