Orientation

Struct Orientation 

Source
pub struct Orientation<In> { /* private fields */ }
Expand description

Defines the orientation of an object in CoordinateSystem In.

This includes yaw, pitch, and roll, so not just facing direction (which would miss roll).

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.

Implementations§

Source§

impl<In> Orientation<In>

Source

pub 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 an orientation from (intrinsic) yaw, pitch, and roll Tait-Bryan angles.

The meanings of yaw, pitch, and roll tend to align with common use in aerospace applications (eg, FrdLike or NedLike), but are more formally defined as described below.

Yaw is rotation about the Z axis of In, with an object oriented at 0° yaw facing along the positive X axis. Bearing::azimuth tends to have the same semantics as yaw (but not always; eg, this is not the case for ENU).

Since we are using intrinsic rotations (by convention), we now consider further rotations (ie, pitch and roll) to be with respect to the axes after applying the yaw. So, as an example, with a yaw of 90° in NED (ie, facing East), a pitch of 45° will tilt the nose of the plane up by 45° while still pointing the plane East.

Pitch is rotation about the Y axis, with an object at 0° pitch facing along the positive X axis (again, this is the X axis with yaw applied). Bearing::elevation tends to have the same semantics as pitch (though again, watch out for ENU!).

Roll is rotation about the X axis, with an object with 0° roll having its positive body Z axis pointing along positive Z. For instance, in NED, after applying a yaw of 90° and a pitch of 45° (so the plane points directly East with its nose pitched up by 45°), applying a roll of 20° would result in the plane’s nose still pointing in the same direction, but rotated clockwise about its own axis by 20°. There is no equivalent to roll in Bearing.

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. Note that a counterclockwise rotation about a Z if positive Z is down is a clockwise rotation when viewed from negative Z (ie, “up”); this matches the common use of yaw in FrdLike where a positive yaw means “to the right”, or in NedLike where a positive yaw means “eastward”.

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).

Source

pub fn aligned() -> Self

Constructs an orientation that is aligned with the axes of the CoordinateSystem In.

That is equivalent to calling Orientation::from_tait_bryan_angles with all zero values.

Source

pub fn tait_bryan_builder() -> TaitBryanBuilder<NeedsYaw, Orientation<In>>

Provides a type-safe builder for constructing an orientation 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, engineering::Orientation};
use uom::si::{f64::Angle, angle::degree};

system!(struct PlaneNed using NED);

let orientation = Orientation::<PlaneNed>::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 roll before pitch - roll() method doesn't exist on NeedsPitch state
let orientation = Orientation::<PlaneNed>::tait_bryan_builder()
    .yaw(Angle::new::<degree>(90.0))
    .roll(Angle::new::<degree>(5.0))
    .pitch(Angle::new::<degree>(45.0))
    .build();
// Cannot skip yaw and start with pitch - pitch() method doesn't exist on NeedsYaw state
let orientation = Orientation::<PlaneNed>::tait_bryan_builder()
    .pitch(Angle::new::<degree>(45.0))
    .yaw(Angle::new::<degree>(90.0))
    .roll(Angle::new::<degree>(5.0))
    .build();
Source§

impl<In> Orientation<In>

Source

pub unsafe fn map_as_zero_in<To>(self) -> Rotation<In, To>

Constructs a rotation into CoordinateSystem To such that self has an orientation of zero in To (ie, Orientation::aligned).

Less informally, if this rotation is applied to this Orientation<In>, it will yield Orientation::aligned as Orientation<To>.

Conversely, if the inverse of this rotation is applied to Orientation::aligned for Orientation<To>, it will yield this Orientation<In>.

Or, alternatively phrased, this yields a transformation that

  1. takes a coordinate, vector, or orientation observed by the object with this orientation in the coordinate system In; and
  2. returns that coordinate or vector as if it were observed in a coordinate system (To) where this Orientation<In> is Orientation::aligned.

Or, if you prefer a more mathematical description: this defines the pose of the whole coordinate system To in In.

§Safety

This method allows you to end up with erroneous transforms if you’re not careful. See Pose::map_as_zero_in for more details.

Specifically in the case of Orientation, you are also asserting that only rotation (ie, no translation) is needed to convert from In to To.

§Examples
use approx::assert_relative_eq;
use sguaba::{system, Bearing, Coordinate, engineering::Orientation};
use uom::si::f64::{Angle, Length};
use uom::si::{angle::degree, length::meter};

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

// plane orientation in NED is yaw 90° (east), pitch 45° (climbing), roll 5° (tilted right)
let orientation = Orientation::<PlaneNed>::from_tait_bryan_angles(
    Angle::new::<degree>(90.),
    Angle::new::<degree>(45.),
    Angle::new::<degree>(5.),
);

// plane observes something below it to its right (45° azimuth, -20° elevation),
// at a range of 100m.
let observation = Coordinate::<PlaneFrd>::from_bearing(
    Bearing::builder()
      .azimuth(Angle::new::<degree>(45.))
      .elevation(Angle::new::<degree>(-20.)).expect("elevation is in-range")
      .build(),
    Length::new::<meter>(100.)
);

// to get the absolute bearing of the observation (ie, with respect to North and horizon),
// we can use map_as_zero_in to obtain a transformation from PlaneNed to PlaneFrd, and
// then invert it to go from PlaneFrd to PlaneNed:
let plane_frd_to_ned = unsafe { orientation.map_as_zero_in::<PlaneFrd>() }.inverse();

// applying that transform gives us the translated coordinate
let observation_in_ned = plane_frd_to_ned.transform(observation);
Source

pub fn cast<NewIn>(self) -> Orientation<NewIn>
where In: EquivalentTo<NewIn>,

Casts the coordinate system type parameter of the orientation to the equivalent coordinate system NewIn.

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

Note that this performs no transform on the orientation’s components, as that should be unnecessary when EquivalentTo is implemented.

use sguaba::{system, systems::EquivalentTo, Bearing, engineering::Orientation};
use uom::si::{f64::Angle, angle::degree};

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

// SAFETY: these are truly the same thing just defined in different places
unsafe impl EquivalentTo<PlaneNedFromCrate1> for PlaneNedFromCrate2 {}
unsafe impl EquivalentTo<PlaneNedFromCrate2> for PlaneNedFromCrate1 {}

let orientation_in_1 = Orientation::<PlaneNedFromCrate1>::from_tait_bryan_angles(
    Angle::new::<degree>(90.),
    Angle::new::<degree>(45.),
    Angle::new::<degree>(5.),
);

assert_eq!(
    Orientation::<PlaneNedFromCrate2>::from_tait_bryan_angles(
        Angle::new::<degree>(90.),
        Angle::new::<degree>(45.),
        Angle::new::<degree>(5.),
    ),
    orientation_in_1.cast::<PlaneNedFromCrate2>()
);
Source

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

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

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

Source

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

Linearly interpolate between this orientation 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.

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

Trait Implementations§

Source§

impl<In> Clone for Orientation<In>

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<In: Debug> Debug for Orientation<In>

Source§

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

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

impl<In> Default for Orientation<In>

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl<'de, In> Deserialize<'de> for Orientation<In>

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> Mul<Orientation<To>> for RigidBodyTransform<From, To>

Source§

type Output = Pose<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<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<RigidBodyTransform<From, To>> for Orientation<From>

Source§

type Output = Pose<To>

The resulting type after applying the * operator.
Source§

fn mul(self, rhs: RigidBodyTransform<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<In> PartialEq for Orientation<In>

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<In> Serialize for Orientation<In>

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<In> Copy for Orientation<In>

Auto Trait Implementations§

§

impl<In> Freeze for Orientation<In>

§

impl<In> RefUnwindSafe for Orientation<In>
where In: RefUnwindSafe,

§

impl<In> Send for Orientation<In>
where In: Send,

§

impl<In> Sync for Orientation<In>
where In: Sync,

§

impl<In> Unpin for Orientation<In>
where In: Unpin,

§

impl<In> UnwindSafe for Orientation<In>
where In: 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, 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> 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,