Rotation

Struct Rotation 

Source
pub struct Rotation<From, To> { /* private fields */ }
Expand description

Defines a rotation transform between two CoordinateSystems.

There are generally two ways to construct a rotation:

  1. by using engineering::Orientation::map_as_zero_in when you already have an engineering::Orientation;
  2. by using Tait-Bryan angles to construct arbitrary rotations.

Mathematically speaking, this is a type-safe wrapper around a unit quaternion.

Note that this type implements Deserialize despite having unsafe constructors – this is because doing otherwise would be extremely unergonomic. However, when deserializing, the coordinate system of the deserialized value is not checked, so this is a foot-gun to be mindful of.

Rotations can be chained with other transformations using * (ie, the Mul trait). However, note that the order of the operands to * matter, and do not match the mathematical convention. Specifically, matrix multiply for transforms (like rotations) traditionally have the transform on the left and the vector to transform on the right. However, doing so here would lead to a type signature of

let _: Coordinate<To> = Rotation<From, To> * Coordinate<From>;

Which violates the expectation that a matrix multiply eliminates the “middle” component (ie, (m × n)(n × p) = (m × p)). So, we require that the rotation is on the right to go from From into To, and that the rotation is on the left to go from To into From (ie, for the inverse transform).

Implementations§

Source§

impl<From, To> Rotation<From, To>
where To: CoordinateSystem<Convention = EnuLike>,

Source

pub unsafe fn into_ned_equivalent<NedTo>(self) -> Rotation<From, NedTo>
where NedTo: CoordinateSystem<Convention = NedLike>,

Converts a rotation from an EnuLike coordinate system into the equivalent rotation in the NedLike coordinate system that shares the same origin.

§Safety

This function only provides a valid rotation if the EnuLike and NedLike coordinate systems share the same origin. If this is not the case, the resulting rotation will lead to incorrect transformations.

Source§

impl<From, To> Rotation<From, To>
where To: CoordinateSystem<Convention = NedLike>,

Source

pub unsafe fn into_enu_equivalent<EnuTo>(self) -> Rotation<From, EnuTo>
where EnuTo: CoordinateSystem<Convention = EnuLike>,

Converts a rotation from a NedLike coordinate system into the equivalent rotation in the EnuLike coordinate system that shares the same origin.

§Safety

This function only provides a valid rotation if the NedLike and EnuLike coordinate systems share the same origin. If this is not the case, the resulting rotation will lead to incorrect transformations.

Source§

impl<From, To> Rotation<From, To>

Source

pub unsafe fn from_tait_bryan_angles( yaw: impl Into<Angle>, pitch: impl Into<Angle>, roll: impl Into<Angle>, ) -> Self

👎Deprecated: Prefer tait_bryan_builder to avoid argument-order confusion

Constructs a rotation between two CoordinateSystems using (intrinsic) yaw, pitch, and roll Tait-Bryan angles.

Perhaps counter-intuitively, this is the rotation of From in To. That is, it is the rotation that must be applied to points in To to place them in From.

If your brain is more engineering-oriented, prefer the alternatives listed in the type docs.

Perhaps counter-intuitively, the angles provided here should represent the rotation that must be applied to an object with zero Bearing in To to arrivate at a Bearing with the given angles in From. This is because we take the inverse of this rotation to go from From into To, which in turn stems from mathematical norms.

The three rotations are defined as follows:

  • yaw is rotation about the Z axis of In;
  • pitch is rotation about the Y axis; and
  • roll is rotation about the X axis.

Since we are using intrinsic rotations (by convention given the naming of the arguments), pitch is with respect to the Y axis after applying the yaw, and roll is with respect to X after applying both yaw and pitch.

To determine the direction of rotation (ie, in which direction a positive angle goes), you can use the right-hand rule for rotations: curl your fingers and stick your thumb out in the positive direction of the axis you want to check rotation around (eg, positive Z for yaw). The direction your fingers curl is the direction of (positive) rotation.

Be aware that rotational angles have high ambiguities in literature and are easy to use wrong, especially because different fields tend to use the same term with different meanings (eg, “Euler angles” mean something else in aerospace than in mathematics).

See also engineering::Orientation::from_tait_bryan_angles.

§Safety

Calling this method asserts that the provided rotational angles represent a correct way to transform any input from From to To (and crucially, that no translation is needed). If this is not the correct transform, then this allows moving values between different coordinate system types without adjusting the values correctly, leading to a defeat of their type safety.

Source

pub unsafe fn identity() -> Self

Asserts that the rotational transform from From to To is one that returns the original point or vector when applied.

§Safety

Like RigidBodyTransform::identity, this allows you to claim that the “correct” rotational transform between the coordinate systems From and To is the identity function (and that no translation is needed). If this is not the correct transform, then this allows moving values between different coordinate system types without adjusting the values correctly, leading to a defeat of their type safety.

Source

pub unsafe fn is_also_into<NewTo>(self) -> Rotation<From, NewTo>

Changes the target coordinate system of the rotation to <NewTo> with no changes to the rotational angles.

This is useful when you have two coordinate systems that you know have exactly equivalent axes, and you need the types to “work out”. This can be the case, for instance, when two crates have both separately declared a NED-like coordinate system centered on the same object, and you have a rotation from some coordinate system into one of them, but you want the end type to be in the other.

This is not how you generally want to convert between coordinate systems. For that, you’ll want to use RigidBodyTransform.

This is exactly equivalent to re-constructing the rotation with the same rotational angles using <NewTo> instead of <To>, just more concise and legible. That is, it is exactly equal to:

use sguaba::{system, math::Rotation};
use uom::si::f64::Angle;
use uom::si::angle::degree;
use approx::assert_relative_eq;

system!(struct PlaneFrd using NED);
system!(struct PlaneNedFromCrate1 using NED);
system!(struct PlaneNedFromCrate2 using NED);

// SAFETY
// we're claiming, without any factual basis for doing so,
// that this _is_ the plane's orientation.
let rotation_into_1 = unsafe {
    Rotation::<PlaneFrd, PlaneNedFromCrate1>::from_tait_bryan_angles(
      Angle::new::<degree>(30.),
      Angle::new::<degree>(45.),
      Angle::new::<degree>(90.),
    )
};

let (yaw, pitch, roll) = rotation_into_1.to_tait_bryan_angles();
assert_relative_eq!(
    unsafe { Rotation::<PlaneFrd, PlaneNedFromCrate2>::from_tait_bryan_angles(yaw, pitch, roll) },
    unsafe { rotation_into_1.is_also_into::<PlaneNedFromCrate2>() }
);
§Safety

This asserts that the transform From to To is the same as the transform from From to NewTo. However, if that is not the case, the resulting transform would allow violating type safety by moving, say, a coordinate into NewTo without correctly adjusting its values.

Source

pub unsafe fn is_also_from<NewFrom>(self) -> Rotation<NewFrom, To>

Changes the origin coordinate system of the rotation to <NewFrom> with no changes to the rotational angles.

This is useful when you have two coordinate systems that you know have exactly equivalent axes, and you need the types to “work out”. This can be the case, for instance, when two crates have both separately declared a NED-like coordinate system centered on the same object, and you have a rotation into some coordinate system from one of them, but need to transform from something typed to be in the other.

This is not how you generally want to convert between coordinate systems. For that, you’ll want to use RigidBodyTransform.

This is exactly equivalent to re-constructing the rotation with the same rotational angles using <NewFrom> instead of <From>, just more concise and legible. That is, it is exactly equal to:

use sguaba::{system, math::Rotation};
use uom::si::f64::Angle;
use uom::si::angle::degree;
use approx::assert_relative_eq;

system!(struct PlaneFrd using NED);
system!(struct PlaneNedFromCrate1 using NED);
system!(struct PlaneNedFromCrate2 using NED);

// SAFETY
// we're claiming, without any factual basis for doing so,
// that this _is_ the plane's orientation.
let rotation_into_1 = unsafe {
    Rotation::<PlaneNedFromCrate1, PlaneFrd>::from_tait_bryan_angles(
      Angle::new::<degree>(30.),
      Angle::new::<degree>(45.),
      Angle::new::<degree>(90.),
    )
};

let (yaw, pitch, roll) = rotation_into_1.to_tait_bryan_angles();
assert_relative_eq!(
    unsafe { Rotation::<PlaneNedFromCrate2, PlaneFrd>::from_tait_bryan_angles(yaw, pitch, roll) },
    unsafe { rotation_into_1.is_also_from::<PlaneNedFromCrate2>() }
);
§Safety

This asserts that the transform From to To is the same as the transform from NewFrom to To. However, if that is not the case, the resulting transform would allow violating type safety by moving, say, a coordinate from NewFrom without correctly adjusting its values.

Source

pub fn cast_type_of_from<AlsoFrom>(self) -> Rotation<AlsoFrom, To>
where From: EquivalentTo<AlsoFrom>,

Casts the coordinate system type parameter From of the rotation to the equivalent coordinate system AlsoFrom.

See EquivalentTo for details on when this is useful (and safe).

Note that this performs no modifications to the transform itself, as that should be unnecessary when EquivalentTo is implemented.

Source

pub fn cast_type_of_to<AlsoTo>(self) -> Rotation<From, AlsoTo>
where To: EquivalentTo<AlsoTo>,

Casts the coordinate system type parameter To of the rotation to the equivalent coordinate system AlsoTo.

See EquivalentTo for details on when this is useful (and safe).

Note that this performs no modifications to the rotation itself, as that should be unnecessary when EquivalentTo is implemented.

Source

pub fn inverse(&self) -> Rotation<To, From>

Returns the equal-but-opposite transform to this one.

That is, a rotation from the CoordinateSystem To into the coordinate system From.

Source

pub fn nlerp(&self, rhs: &Self, t: f64) -> Self

Linearly interpolate between this rotation and another one.

Conceptually returns self * (1.0 - t) + rhs * t, i.e., the linear blend of the two rotations using the scalar value t.

Note that this function inherently normalizes the underlying rotation such that it remains a unit quaternion.

The value for t is not restricted to the range [0, 1].

Source

pub fn to_tait_bryan_angles(&self) -> (Angle, Angle, Angle)

Returns the yaw-pitch-roll Tait-Bryan angles that describe this rotation.

See Rotation::from_tait_bryan_angles for documentation about the exact meaning of yaw, pitch, and roll here.

The angles returned are, perhaps counter-intuitively but also in alignment with Rotation::from_tait_bryan_angles, the rotations that must be performed to go from To into From.

Source

pub fn euler_angles(&self) -> (Angle, Angle, Angle)

Returns the Euler angles describing this rotation.

The use of this method is discouraged as Eulers angles are both hard to work with and do not have a single, canonical definition across domains (eg, in aerospace).

The angles returned are, perhaps counter-intuitively but in alignment with Rotation::from_tait_bryan_angles, the rotations that must be performed to go from To into From.

Source

pub fn tait_bryan_builder() -> TaitBryanBuilder<NeedsYaw, Rotation<From, To>>

Provides a type-safe builder for constructing a rotation from Tait-Bryan angles.

This builder enforces the correct intrinsic order (yaw → pitch → roll) at compile time and provides named parameters to prevent argument order confusion.

§Examples
use sguaba::{system, math::Rotation};
use uom::si::{f64::Angle, angle::degree};

system!(struct PlaneNed using NED);
system!(struct PlaneFrd using FRD);

let rotation = unsafe {
    Rotation::<PlaneNed, PlaneFrd>::tait_bryan_builder()
        .yaw(Angle::new::<degree>(90.0))
        .pitch(Angle::new::<degree>(45.0))
        .roll(Angle::new::<degree>(5.0))
        .build()
};

The following examples should fail to compile because the angles are not provided in the correct order:

// Cannot call pitch before yaw - pitch() method doesn't exist on NeedsYaw state
let rotation = unsafe {
    Rotation::<PlaneNed, PlaneFrd>::tait_bryan_builder()
        .pitch(Angle::new::<degree>(45.0))
        .yaw(Angle::new::<degree>(90.0))
        .roll(Angle::new::<degree>(5.0))
        .build()
};
// Cannot call build before setting all angles - build() method doesn't exist on NeedsPitch state
let rotation = unsafe {
    Rotation::<PlaneNed, PlaneFrd>::tait_bryan_builder()
        .yaw(Angle::new::<degree>(90.0))
        .build()
};
// Cannot call roll before pitch - roll() method doesn't exist on NeedsPitch state
let rotation = unsafe {
    Rotation::<PlaneNed, PlaneFrd>::tait_bryan_builder()
        .yaw(Angle::new::<degree>(90.0))
        .roll(Angle::new::<degree>(5.0))
        .pitch(Angle::new::<degree>(45.0))
        .build()
};
§Safety

The builder’s build() method is unsafe for the same reasons as from_tait_bryan_angles: you are asserting a relationship between coordinate systems From and To.

Source§

impl<From, To> Rotation<From, To>

Source

pub fn transform<T>(&self, in_from: T) -> <T as Mul<Self>>::Output
where T: Mul<Self>,

Transforms an element in CoordinateSystem From into To.

Source

pub fn inverse_transform<T>(&self, in_to: T) -> <Self as Mul<T>>::Output
where Self: Mul<T>,

Transforms an element in CoordinateSystem To into From.

This is equivalent to (but more efficient than) first inverting the transform with RigidBodyTransform::inverse and then calling RigidBodyTransform::transform.

Trait Implementations§

Source§

impl<From, To> AbsDiffEq for Rotation<From, To>

Source§

type Epsilon = <f64 as AbsDiffEq>::Epsilon

Used for specifying relative comparisons.
Source§

fn default_epsilon() -> Self::Epsilon

The default tolerance to use when testing values that are close together. Read more
Source§

fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool

A test for equality that uses the absolute difference to compute the approximate equality of two numbers.
Source§

fn abs_diff_ne(&self, other: &Rhs, epsilon: Self::Epsilon) -> bool

The inverse of AbsDiffEq::abs_diff_eq.
Source§

impl<From, To> Clone for Rotation<From, To>

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<From: Debug, To: Debug> Debug for Rotation<From, To>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'de, From, To> Deserialize<'de> for Rotation<From, To>

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl<From, To> Display for Rotation<From, To>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<From, To> Mul<Bearing<To>> for Rotation<From, To>
where From: BearingDefined, To: BearingDefined,

Source§

type Output = Bearing<From>

The resulting type after applying the * operator.
Source§

fn mul(self, rhs: Bearing<To>) -> Self::Output

Performs the * operation. Read more
Source§

impl<From, To> Mul<Coordinate<To>> for Rotation<From, To>

Source§

type Output = Coordinate<From>

The resulting type after applying the * operator.
Source§

fn mul(self, rhs: Coordinate<To>) -> Self::Output

Performs the * operation. Read more
Source§

impl<From, To> Mul<Orientation<To>> for Rotation<From, To>

Source§

type Output = Orientation<From>

The resulting type after applying the * operator.
Source§

fn mul(self, rhs: Orientation<To>) -> Self::Output

Performs the * operation. Read more
Source§

impl<From, To> Mul<Rotation<From, To>> for Bearing<From>
where From: BearingDefined, To: BearingDefined,

Source§

type Output = Bearing<To>

The resulting type after applying the * operator.
Source§

fn mul(self, rhs: Rotation<From, To>) -> Self::Output

Performs the * operation. Read more
Source§

impl<From, To> Mul<Rotation<From, To>> for Coordinate<From>

Source§

type Output = Coordinate<To>

The resulting type after applying the * operator.
Source§

fn mul(self, rhs: Rotation<From, To>) -> Self::Output

Performs the * operation. Read more
Source§

impl<From, To> Mul<Rotation<From, To>> for Orientation<From>

Source§

type Output = Orientation<To>

The resulting type after applying the * operator.
Source§

fn mul(self, rhs: Rotation<From, To>) -> Self::Output

Performs the * operation. Read more
Source§

impl<From, To> Mul<Rotation<From, To>> for Vector<From>

Source§

type Output = Vector<To>

The resulting type after applying the * operator.
Source§

fn mul(self, rhs: Rotation<From, To>) -> Self::Output

Performs the * operation. Read more
Source§

impl<From, Over, To> Mul<Rotation<Over, To>> for RigidBodyTransform<From, Over>

Source§

type Output = RigidBodyTransform<From, To>

The resulting type after applying the * operator.
Source§

fn mul(self, rhs: Rotation<Over, To>) -> Self::Output

Performs the * operation. Read more
Source§

impl<From, Over, To> Mul<Rotation<Over, To>> for Rotation<From, Over>

Source§

type Output = Rotation<From, To>

The resulting type after applying the * operator.
Source§

fn mul(self, rhs: Rotation<Over, To>) -> Self::Output

Performs the * operation. Read more
Source§

impl<From, To> Mul<Vector<To>> for Rotation<From, To>

Source§

type Output = Vector<From>

The resulting type after applying the * operator.
Source§

fn mul(self, rhs: Vector<To>) -> Self::Output

Performs the * operation. Read more
Source§

impl<From, To> Neg for Rotation<From, To>

Source§

type Output = Rotation<To, From>

The resulting type after applying the - operator.
Source§

fn neg(self) -> Self::Output

Performs the unary - operation. Read more
Source§

impl<From, To> PartialEq for Rotation<From, To>

Source§

fn eq(&self, other: &Self) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl<From, To> RelativeEq for Rotation<From, To>

Source§

fn default_max_relative() -> Self::Epsilon

The default relative tolerance for testing values that are far-apart. Read more
Source§

fn relative_eq( &self, other: &Self, epsilon: Self::Epsilon, max_relative: Self::Epsilon, ) -> bool

A test for equality that uses a relative comparison if the values are far apart.
Source§

fn relative_ne( &self, other: &Rhs, epsilon: Self::Epsilon, max_relative: Self::Epsilon, ) -> bool

The inverse of RelativeEq::relative_eq.
Source§

impl<From, To> Serialize for Rotation<From, To>

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl<From, To> Copy for Rotation<From, To>

Auto Trait Implementations§

§

impl<From, To> Freeze for Rotation<From, To>

§

impl<From, To> RefUnwindSafe for Rotation<From, To>
where From: RefUnwindSafe, To: RefUnwindSafe,

§

impl<From, To> Send for Rotation<From, To>
where From: Send, To: Send,

§

impl<From, To> Sync for Rotation<From, To>
where From: Sync, To: Sync,

§

impl<From, To> Unpin for Rotation<From, To>
where From: Unpin, To: Unpin,

§

impl<From, To> UnwindSafe for Rotation<From, To>
where From: UnwindSafe, To: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<SS, SP> SupersetOf<SS> for SP
where SS: SubsetOf<SP>,

Source§

fn to_subset(&self) -> Option<SS>

The inverse inclusion map: attempts to construct self from the equivalent element of its superset. Read more
Source§

fn is_in_subset(&self) -> bool

Checks if self is actually part of its subset T (and can be converted to it).
Source§

fn to_subset_unchecked(&self) -> SS

Use with care! Same as self.to_subset but without any property checks. Always succeeds.
Source§

fn from_subset(element: &SS) -> SP

The inclusion map: converts self to the equivalent element of its superset.
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> ClosedNeg for T
where T: Neg<Output = T>,

Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<System> EquivalentTo<System> for System

Source§

impl<T> Scalar for T
where T: 'static + Clone + PartialEq + Debug,