Skip to content

Commit

Permalink
WIP: Complete initial implementation of attitude representations and …
Browse files Browse the repository at this point in the history
…covnersions
  • Loading branch information
duncaneddy committed Feb 8, 2024
1 parent 57c3c7d commit 19e3508
Show file tree
Hide file tree
Showing 6 changed files with 1,199 additions and 252 deletions.
7 changes: 4 additions & 3 deletions src/attitude/attitude_representation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
* Attitude representation trait defines the interface for converting between different attitude representations.
*/

use crate::attitude::attitude_types::{EulerAngle, EulerAxis, Quaternion, RotationMatrix, EulerAngleOrder};
use crate::attitude::attitude_types::{
EulerAngle, EulerAngleOrder, EulerAxis, Quaternion, RotationMatrix,
};

/// `ToAttitude` trait defines the interface for converting to different attitude representations. Any struct that
/// implements `ToAttitude` can convert its attitude representation into the main attitude representation methods of
Expand All @@ -13,7 +15,6 @@ use crate::attitude::attitude_types::{EulerAngle, EulerAxis, Quaternion, Rotatio
/// See [_Representing Attitude: Euler Angles, Unit Quaternions, and Rotation Vectors_ by James Diebel](https://www.astro.rug.nl/software/kapteyn-beta/_downloads/attitude.pdf) for more information
/// on the different attitude representations and their conversions.
pub trait ToAttitude {

fn to_quaternion(&self) -> Quaternion;
fn to_euler_axis(&self) -> EulerAxis;
fn to_euler_angle(&self, order: EulerAngleOrder) -> EulerAngle;
Expand All @@ -35,4 +36,4 @@ pub trait FromAttitude {
fn from_euler_axis(e: EulerAxis) -> Self;
fn from_euler_angle(e: EulerAngle) -> Self;
fn from_rotation_matrix(r: RotationMatrix) -> Self;
}
}
5 changes: 4 additions & 1 deletion src/attitude/attitude_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
* Defines the attitude types used in Brahe
*/

use std::fmt;
use nalgebra::{Matrix3, Vector3, Vector4};
use std::fmt;

/// The `Quaternion` struct represents a quaternion in the form of one scalar and three vector components.
/// The scalar component is the real part of the quaternion, and the vector components are the imaginary
Expand Down Expand Up @@ -114,6 +114,9 @@ impl fmt::Debug for EulerAngleOrder {
/// different attitude representation and angle order must be supplied. Since this information is not part of the
/// `FromAttitude` trait method signatures, `EulerAngle` implements its own initialization function for initialization
/// from `Quaternion`, `EulerAxis`, and `RotationMatrix`.
///
/// The internal representation of the Euler angles is in radians. When creating a new `EulerAngle` struct, the angles
/// can be specified in either radians or degrees.
#[derive(Clone, Copy)]
pub struct EulerAngle {
pub order: EulerAngleOrder,
Expand Down
255 changes: 231 additions & 24 deletions src/attitude/euler_angle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@
`euler_angle` module provides the implementation of the EulerAngle struct, which represents an attitude transformation in the form of three successive rotations about the x, y, or z axes.
*/

use std::{fmt, ops};
use nalgebra::Vector3;
use std::fmt;

use crate::constants::{DEG2RAD, RAD2DEG};
use crate::attitude::ToAttitude;
use crate::{EulerAngle, EulerAngleOrder, Quaternion, RotationMatrix, EulerAxis};
use crate::attitude::{FromAttitude, ToAttitude};
use crate::constants::DEG2RAD;
use crate::{EulerAngle, EulerAngleOrder, EulerAxis, Quaternion, RotationMatrix};

impl EulerAngle {

/// Create a new `EulerAngle`, which represents an attitude transformation in the form of three successive rotations
/// about the x-, y-, or z-axes.
///
Expand All @@ -20,6 +19,7 @@ impl EulerAngle {
/// - `phi` - The angle of the first rotation, in radians.
/// - `theta` - The angle of the second rotation, in radians.
/// - `psi` - The angle of the third rotation, in radians.
/// - `as_degrees` - A boolean indicating if the input angles are in degrees. If true, the angles are converted to radians.
///
/// # Returns
///
Expand All @@ -33,7 +33,16 @@ impl EulerAngle {
/// let e = EulerAngle::new(EulerAngleOrder::XYZ, 30.0, 45.0, 60.0, true);
/// ```
pub fn new(order: EulerAngleOrder, phi: f64, theta: f64, psi: f64, as_degrees: bool) -> Self {
Self { order, phi, theta, psi }
let phi = if as_degrees { phi * DEG2RAD } else { phi };
let theta = if as_degrees { theta * DEG2RAD } else { theta };
let psi = if as_degrees { psi * DEG2RAD } else { psi };

Self {
order,
phi,
theta,
psi,
}
}

/// Create a new `EulerAngle` from a `Vector3<f64>`, which represents an attitude transformation in the form of three
Expand Down Expand Up @@ -64,77 +73,275 @@ impl EulerAngle {
Self::new(order, vector.x, vector.y, vector.z, as_degrees)
}

/// Convert a `Quaternion` to an `EulerAngle`.
/// Create a new `EulerAngle` from a `Quaternion`.
///
/// # Arguments
///
/// - `q` - A `Quaternion` struct.
/// - `order` - The order of the rotations. This is a value from the `EulerAngleOrder` enum.
///
/// # Returns
///
/// - A new `EulerAngle` struct.
///
/// # Example
///
fn from_quaternion(q: Quaternion, order: EulerAngleOrder) -> Self {
/// ```
/// use brahe::attitude::attitude_types::{EulerAngle, EulerAngleOrder, Quaternion};
///
/// let q = Quaternion::new(0.7071, 0.0, 0.0, 0.7071);
/// let e = EulerAngle::from_quaternion(q, EulerAngleOrder::XYZ);
/// ```
pub fn from_quaternion(q: Quaternion, order: EulerAngleOrder) -> Self {
q.to_euler_angle(order)
}

fn from_euler_axis(e: EulerAxis, order: EulerAngleOrder) -> Self {
todo!()
/// Create a new `EulerAngle` from an `EulerAxis`.
///
/// # Arguments
///
/// - `e` - An `EulerAxis` struct.
/// - `order` - The order of the rotations. This is a value from the `EulerAngleOrder` enum.
///
/// # Returns
///
/// - A new `EulerAngle` struct.
///
/// # Example
///
/// ```
/// use brahe::attitude::attitude_types::{EulerAngle, EulerAxis, EulerAngleOrder};
///
/// let e = EulerAxis::new(Vector3::new(1.0, 0.0, 0.0), 45.0, true);
/// let e = EulerAngle::from_euler_axis(e, EulerAngleOrder::XYZ);
/// ```
pub fn from_euler_axis(e: EulerAxis, order: EulerAngleOrder) -> Self {
// Convert to Quaternion and then to EulerAngle
Quaternion::from_euler_axis(e).to_euler_angle(order)
}

fn from_euler_angle(e: EulerAngle, order: EulerAngleOrder) -> Self {
todo!()
/// Create a new `EulerAngle` from another `EulerAngle`. This can be used to convert between different angle order
/// representations.
///
/// # Arguments
///
/// - `e` - An `EulerAngle` struct.
/// - `order` - The order of the rotations for the output `EulerAngle`. This is a value from the `EulerAngleOrder` enum.
///
/// # Returns
///
/// - A new `EulerAngle` struct.
///
/// # Example
///
/// ```
/// use brahe::attitude::attitude_types::{EulerAngle, EulerAngleOrder};
///
/// let e = EulerAngle::new(EulerAngleOrder::XYZ, 30.0, 45.0, 60.0, true);
/// let e = EulerAngle::from_euler_angle(e, EulerAngleOrder::ZYX);
/// ```
pub fn from_euler_angle(e: EulerAngle, order: EulerAngleOrder) -> Self {
// Convert to Quaternion and back to change angle representation
e.to_quaternion().to_euler_angle(order)
}

fn from_rotation_matrix(r: RotationMatrix, order: EulerAngleOrder) -> Self {
todo!()
/// Create a new `EulerAngle` from a `RotationMatrix`.
///
/// # Arguments
///
/// - `r` - A `RotationMatrix` struct.
/// - `order` - The order of the rotations. This is a value from the `EulerAngleOrder` enum.
///
/// # Returns
///
/// - A new `EulerAngle` struct.
///
/// # Example
///
/// ```
/// use brahe::attitude::attitude_types::{EulerAngle, EulerAngleOrder, RotationMatrix};
///
/// let r = RotationMatrix::new(
/// 1.0, 0.0, 0.0,
/// 0.0, 0.866, -0.5,
/// 0.0, 0.5, 0.866
/// );
/// let e = EulerAngle::from_rotation_matrix(r, EulerAngleOrder::XYZ);
/// ```
pub fn from_rotation_matrix(r: RotationMatrix, order: EulerAngleOrder) -> Self {
r.to_euler_angle(order)
}
}

impl fmt::Display for EulerAngle {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// TODO: Accept formatting options per https://doc.rust-lang.org/std/fmt/struct.Formatter.html
write!(f, "EulerAngle: [phi: {}, theta: {}, psi: {}, order: {}]", self.phi, self.theta, self.psi, self.order)
write!(
f,
"EulerAngle: [phi: {}, theta: {}, psi: {}, order: {}]",
self.phi, self.theta, self.psi, self.order
)
}
}

impl PartialEq for EulerAngle {
fn eq(&self, other: &Self) -> bool {
self.phi == other.phi && self.theta == other.theta && self.psi == other.psi && self.order == other.order
self.phi == other.phi
&& self.theta == other.theta
&& self.psi == other.psi
&& self.order == other.order
}

fn ne(&self, other: &Self) -> bool {
self.phi != other.phi || self.theta != other.theta || self.psi != other.psi || self.order != other.order
self.phi != other.phi
|| self.theta != other.theta
|| self.psi != other.psi
|| self.order != other.order
}
}

impl fmt::Debug for EulerAngle {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "EulerAngle<{},{},{},{:?}>", self.phi, self.theta, self.psi, self.order)
write!(
f,
"EulerAngle<{},{},{},{:?}>",
self.phi, self.theta, self.psi, self.order
)
}
}

impl ToAttitude for EulerAngle {
/// Convert the `EulerAngle` to a `Quaternion`.
///
/// # Returns
///
/// - A new `Quaternion` struct.
///
/// # Example
///
/// ```
/// use brahe::attitude::attitude_types::{EulerAngle, EulerAngleOrder};
///
/// let e = EulerAngle::new(EulerAngleOrder::XYZ, 30.0, 45.0, 60.0, true);
/// let q = e.to_quaternion();
/// ```
fn to_quaternion(&self) -> Quaternion {
todo!()
Quaternion::from_euler_angle(*self)
}

/// Convert the `EulerAngle` to an `EulerAxis`.
///
/// # Returns
///
/// - A new `EulerAxis` struct.
///
/// # Example
///
/// ```
/// use brahe::attitude::attitude_types::{EulerAngle, EulerAngleOrder};
///
/// let e = EulerAngle::new(EulerAngleOrder::XYZ, 30.0, 45.0, 60.0, true);
/// let e = e.to_euler_axis();
/// ```
fn to_euler_axis(&self) -> EulerAxis {
todo!()
EulerAxis::from_euler_angle(*self)
}

/// Convert the `EulerAngle` to another `EulerAngle` with a different order.
///
/// # Arguments
///
/// - `order` - The order of the rotations for the output `EulerAngle`. This is a value from the `EulerAngleOrder` enum.
///
/// # Returns
///
/// - A new `EulerAngle` struct.
///
/// # Example
///
/// ```
/// use brahe::attitude::attitude_types::{EulerAngle, EulerAngleOrder};
///
/// let e = EulerAngle::new(EulerAngleOrder::XYZ, 30.0, 45.0, 60.0, true);
/// let e = e.to_euler_angle(EulerAngleOrder::ZYX);
/// ```
fn to_euler_angle(&self, order: EulerAngleOrder) -> EulerAngle {
todo!()
self.to_quaternion().to_euler_angle(order)
}

/// Convert the `EulerAngle` to a `RotationMatrix`.
///
/// # Returns
///
/// - A new `RotationMatrix` struct.
///
/// # Example
///
/// ```
/// use brahe::attitude::attitude_types::{EulerAngle, EulerAngleOrder};
///
/// let e = EulerAngle::new(EulerAngleOrder::XYZ, 30.0, 45.0, 60.0, true);
/// let r = e.to_rotation_matrix();
/// ```
fn to_rotation_matrix(&self) -> RotationMatrix {
todo!()
RotationMatrix::from_euler_angle(*self)
}
}

// Note that From is not implemented as the conversion is ambiguous
// without having the order of the EulerAngle specified.

#[cfg(test)]
mod tests{
mod tests {
use super::*;
}

#[test]
fn test_euler_angle_new() {
todo!()
}

#[test]
fn test_euler_angle_from_vector() {
todo!()
}

#[test]
fn test_euler_angle_from_quaternion() {
todo!()
}

#[test]
fn test_euler_angle_from_euler_axis() {
todo!()
}

#[test]
fn test_euler_angle_from_euler_angle() {
todo!()
}

#[test]
fn test_euler_angle_from_rotation_matrix() {
todo!()
}

#[test]
fn test_euler_angle_to_quaternion() {
todo!()
}

#[test]
fn test_euler_angle_to_euler_axis() {
todo!()
}

#[test]
fn test_euler_angle_to_euler_angle() {
todo!()
}

#[test]
fn test_euler_angle_to_rotation_matrix() {
todo!()
}
}

0 comments on commit 19e3508

Please sign in to comment.