pub enum RelativeTranslation<Reference: Vehicle> {
BodyFrame {
position: Position<BodyFrame<Reference>>,
velocity: Velocity<BodyFrame<Reference>>,
},
Inertial {
position: Position<RootInertial>,
velocity: Velocity<RootInertial>,
},
}Expand description
Frame-tagged translational state inside a RelativeState.
The compute_relative_state producer chooses the variant based on
the runtime presence of the reference’s rotational state — JEOD’s
decr_left convention rotates into the reference body frame iff a
rotational state is available, and otherwise leaves the difference
in the inertial frame. Encoding the choice as a sum-typed variant
lets each variant carry a distinct phantom-tagged
Position/Velocity pair, so a consumer that mixes a
body-frame value with a root-inertial value is a compile error.
§Vehicle phantom
RelativeTranslation carries a single <Reference: Vehicle>
parameter naming the reference vehicle in whose body frame the
BodyFrame variant’s values are expressed. The Inertial variant
is in the root inertial frame and does not depend on a vehicle
identity, but the parameter is still threaded through the type so
the two variants share a consistent compile-time pair shape with
RelativeState’s <Subject, Reference>. Mission code that pins
the reference at compile time gets a cross-pair guard:
RelativeTranslation<Iss> and RelativeTranslation<Soyuz> are
distinct types. The Bevy adapter and standalone runner instantiate
<Reference = SelfRef>.
Pattern-match to read:
match rel.trans {
RelativeTranslation::BodyFrame { position, velocity } => { /* typed body-frame */ }
RelativeTranslation::Inertial { position, velocity } => { /* typed root-inertial */ }
}For consumers that just want the raw DVec3 (e.g. CSV-reference
distance metrics in Tier 3 tests where both branches are valid
inputs to the same scalar length()), Self::position_raw and
Self::velocity_raw return the underlying SI vector without
committing to a phantom — they’re the deliberate escape hatch for
branch-agnostic numerical consumers.
§Compile-time frame guard
The body-frame variant carries a Position<BodyFrame<Reference>>
while the inertial variant carries a Position<RootInertial>.
Adding (or otherwise mixing without a deliberate FrameTransform)
the two phantoms is a compile error. The doctest below documents
the guard and is consumed by cargo test --doc as a compile_fail
rustdoc test; if the body-frame and inertial-frame Position
types ever became compatible, this test would start passing and
fail the doctest.
use astrodyn_quantities::ext::Vec3Ext;
use astrodyn_quantities::frame::{BodyFrame, RootInertial, SelfRef};
use glam::DVec3;
let body_frame_pos = DVec3::ZERO.m_at::<BodyFrame<SelfRef>>();
let inertial_pos = DVec3::ZERO.m_at::<RootInertial>();
// The two phantoms are kind-distinct — addition requires either
// matching frames or an explicit `FrameTransform`. The compiler
// refuses this expression at the type level:
let _ = body_frame_pos + inertial_pos;§Compile-time cross-pair guard
The reference-vehicle phantom makes a BodyFrame<Iss> value
kind-distinct from a BodyFrame<Soyuz> value. The doctest below
shows that a consumer holding a Position<BodyFrame<Iss>> cannot
accidentally bind it from a RelativeTranslation<Soyuz>’s
body-frame variant — the destructure refuses to typecheck.
use astrodyn_quantities::aliases::Position;
use astrodyn_quantities::define_vehicle;
use astrodyn_quantities::frame::BodyFrame;
use astrodyn::RelativeTranslation;
define_vehicle!(Iss);
define_vehicle!(Soyuz);
fn binder(t: RelativeTranslation<Soyuz>) {
// Would silently accept Soyuz-frame data into the Iss slot if
// the phantom didn't propagate through the variant — the
// compiler refuses this binding:
let RelativeTranslation::BodyFrame { position, .. } = t else { return; };
let _bound: Position<BodyFrame<Iss>> = position;
}Variants§
BodyFrame
Reference rotational state was present: position/velocity are
rotated into the reference body frame (JEOD S_{ref:subj}).
The BodyFrame<Reference> phantom names the reference
vehicle’s body frame at the type level — distinct from the
subject’s body frame on RelativeState::ang_vel.
Fields
Inertial
Reference rotational state was absent: position/velocity are
the raw inertial-frame difference. The RootInertial phantom
is the simulation’s root inertial frame — for body-state
inputs read from an integration-frame storage slot the
convention rests on the call site (the producer cannot know
statically that the inputs are root-inertial vs. some
PlanetInertial<P> integration frame). Mission code that
holds typed inputs should use the typed sibling API path
rather than feeding raw DVec3 here.
Fields
position: Position<RootInertial>Position of subject relative to reference, in the inertial frame.
velocity: Velocity<RootInertial>Velocity of subject relative to reference, in the inertial frame.
Implementations§
Source§impl<Reference: Vehicle> RelativeTranslation<Reference>
impl<Reference: Vehicle> RelativeTranslation<Reference>
Sourcepub fn position_raw(&self) -> DVec3
pub fn position_raw(&self) -> DVec3
Raw position vector in whichever frame the variant carries.
Provided for branch-agnostic numerical consumers (e.g. scalar
distance metrics). Frame-aware consumers should pattern-match
on the variant to obtain the typed Position<F> and route
it through the typed boundary.
Sourcepub fn velocity_raw(&self) -> DVec3
pub fn velocity_raw(&self) -> DVec3
Raw velocity vector in whichever frame the variant carries.
Companion to Self::position_raw.
Sourcepub fn assert_reference<R: Vehicle>(self) -> Selfwhere
(): CompatibleVehicles<Reference, R>,
pub fn assert_reference<R: Vehicle>(self) -> Selfwhere
(): CompatibleVehicles<Reference, R>,
Type-level witness that this translation carries the caller’s
expected reference-vehicle phantom R. Compiles only when
Reference == R; on mismatch the
astrodyn_quantities::diagnostics::CompatibleVehicles bound fails
and surfaces a physics-language diagnostic naming the expected
and found vehicles instead of a PhantomData<…> wall.
The method is a no-op (returns self) and has zero runtime
cost; it exists so a consumer holding a
RelativeTranslation<Iss> can refuse — at compile time, with a
physics-language message — a value built for a different
reference vehicle.
§Compile-time mismatch
use glam::DVec3;
use astrodyn_quantities::define_vehicle;
use astrodyn::{compute_relative_state, RelativeTranslation, TranslationalState};
define_vehicle!(Iss);
define_vehicle!(Soyuz);
let trans = TranslationalState { position: DVec3::ZERO, velocity: DVec3::ZERO };
let rel = compute_relative_state::<Iss, Iss>(&trans, None, &trans, None);
// Asserting the wrong reference fires the `CompatibleVehicles`
// diagnostic naming `Iss` (found) and `Soyuz` (expected).
let _ = rel.trans.assert_reference::<Soyuz>();Trait Implementations§
Auto Trait Implementations§
impl<Reference> Freeze for RelativeTranslation<Reference>
impl<Reference> RefUnwindSafe for RelativeTranslation<Reference>where
Reference: RefUnwindSafe,
impl<Reference> Send for RelativeTranslation<Reference>
impl<Reference> Sync for RelativeTranslation<Reference>
impl<Reference> Unpin for RelativeTranslation<Reference>where
Reference: Unpin,
impl<Reference> UnsafeUnpin for RelativeTranslation<Reference>
impl<Reference> UnwindSafe for RelativeTranslation<Reference>where
Reference: UnwindSafe,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> Pointable for T
impl<T> Pointable for T
Source§impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
Source§fn to_subset(&self) -> Option<SS>
fn to_subset(&self) -> Option<SS>
self from the equivalent element of its
superset. Read moreSource§fn is_in_subset(&self) -> bool
fn is_in_subset(&self) -> bool
self is actually part of its subset T (and can be converted to it).Source§fn to_subset_unchecked(&self) -> SS
fn to_subset_unchecked(&self) -> SS
self.to_subset but without any property checks. Always succeeds.Source§fn from_subset(element: &SS) -> SP
fn from_subset(element: &SS) -> SP
self to the equivalent element of its superset.