Skip to main content

Crate astrodyn_quantities

Crate astrodyn_quantities 

Source
Expand description

§astrodyn_quantities

Dimensional-analysis and phantom-tag foundation for astrodyn_bevy.

This crate sits at the bottom of the workspace dependency graph. Every other astrodyn_* crate, plus astrodyn, astrodyn_runner, and the astrodyn_bevy Bevy glue all depend on it for typed quantities and phantom frame / time-scale tags.

§Three-layer facade

┌──────────────────────────────────────────────────────────┐
│ Facade  (astrodyn_bevy::prelude, astrodyn::recipes)          │
│   F64Ext: 400.0.km(), 51.6.deg(), 420_000.0.kg()         │
│   Concrete Component wrappers (no visible generics)      │
│   Custom #[diagnostic::on_unimplemented] messages        │
├──────────────────────────────────────────────────────────┤
│ Typed astrodyn_* siblings                                     │
│   Position<F: Frame>, SecondsSince<S: TimeScale>,        │
│   Quat<L, T>, NormalizedQuat, FrameTransform<From, To>   │
├──────────────────────────────────────────────────────────┤
│ astrodyn_quantities  (you are here)                          │
│   uom re-exports, Qty3<D, F>, phantom frames/scales,     │
│   F64Ext / Vec3Ext / Array3Ext                           │
└──────────────────────────────────────────────────────────┘

Mission-crate code consumes the facade layer and never sees PhantomData or uom::si::* paths. Internal physics kernels drop down to raw glam::DVec3/f64 for arithmetic density via .raw_si() and re-wrap on exit. See the Type-System and Strategy wiki pages (https://github.com/simnaut/astrodyn/wiki) for architecture.

§What this crate provides

  • Reference-frame and time-scale phantom markers (RootInertial, Ecef, PlanetFixed<P>, BodyFrame<V>, Lvlh<Chief>, TAI, TT, …)
  • uom-backed componentwise 3-vectors Qty3<D, F> with aliases Position<F>, Velocity<F>, Acceleration<F>, Force<F>, Torque<F>, …
  • Quaternion convention tags (ScalarFirst/ScalarLast, LeftTransform/RightTransform) plus a NormalizedQuat constructor-gated witness
  • Typed FrameTransform<From, To> composing only when inner frames match
  • The F64Ext facade (400.0.km(), 51.6.deg(), 420_000.0.kg())
  • Compiler error messages in physics language via #[diagnostic::on_unimplemented]

§Compile-time guards

Beyond uom’s built-in dimensional analysis, this crate adds layered type-system guards specific to orbital-mechanics conventions. The actively-wired set:

  • Dimensional mismatch (uom-native): Position + Mass is rejected because Qty3’s Add impl requires identical dimension D.

  • Frame mismatch on +/-/+=/-=Position<Ecef> + Position<RootInertial> fails with a tailored #[diagnostic::on_unimplemented] message pointing at FrameTransform. Wired via the diagnostics::CompatibleFrames<Fl, Fr> bound in ops.

  • Time-scale separationSecondsSince<S> has no Add/Sub impl across distinct scales, so direct arithmetic between (e.g.) SecondsSince<TAI> and SecondsSince<TT> is rejected. The intended way to combine scales is via TimeConverter::apply. The raw SecondsSince::from_seconds / as_seconds boundaries can still relabel an f64 across scales without applying the offset — see “Where the guards stop” below.

  • Quaternion convention separation — layout (ScalarFirst vs ScalarLast), transform convention (LeftTransform vs RightTransform), and normalization status are distinct phantom tags. NormalizedQuat<L, T> is a separate type from Quat<L, T>, so a raw Quat cannot stand in where a unit quaternion is required.

  • FrameTransform<From, To> composition only typechecks when the two inner frames align (A→B ∘ B→C); the identity is only defined for From = To.

  • Cross-dimension multiply / divide on Qty3 uses typenum exponent arithmetic, so Velocity × Time → Position and Acceleration × Time → Velocity are type-safe by construction; a bad combination produces a dimension that won’t unify with the target type.

  • Inertial-flavor distinctions (issue #255 / RF.10): RootInertial, PlanetInertial<P>, and IntegrationFrame are kind-distinct phantoms. Body integration-frame state cannot silently flow into root-inertial-only consumers (gravity, SRP, relativistic); the only safe transition is via IntegOrigin.

  • Vehicle-phantom mismatch on the Act-5 phantom-wrapped types (FlatPlate<V>, AttachEvent<VParent, VChild>, RelativeState<Subject, Reference>, RelativeTranslation<Reference>, LvlhRelativeState<Chief>) is surfaced via the diagnostics::CompatibleVehicles / diagnostics::CompatibleVehiclePair markers. Each type exposes a zero-cost assert_* witness method whose where bound resolves only when the vehicle phantoms agree; on mismatch the diagnostic names the expected and found vehicles in physics language instead of a PhantomData<…> wall. Mission code reaches for the witness at the boundary that hands the value to a slot of a specific identity (e.g. plate.assert_vehicle::<Iss>()).

§Scaffolded but not currently wired

diagnostics::IntoLength, diagnostics::IntoAngle, diagnostics::IntoGravParam, diagnostics::CompatibleGravParam, diagnostics::CompatibleTimeScales, diagnostics::CompatibleQuatLayouts, diagnostics::CompatibleQuatTransforms, diagnostics::RequiresNormalizedQuat, diagnostics::InertialOnly, and diagnostics::NoVectorVectorMul carry tailored diagnostic messages but are not currently used as where bounds by any impl in the workspace. Today, for example, passing 400_000.0 where a Length is expected produces uom’s stock “mismatched types” error rather than the IntoLength hint, and Qty3 * Qty3 produces a default “no Mul impl” rather than the NoVectorVectorMul hint. F64Ext discoverability today comes from the prelude and worked examples. These scaffolds let a future contributor flip on an active guard without touching call sites — the diagnostic message is already in place.

§Where the guards stop

The crate has several public raw-value boundaries where the type-system guards end and the caller takes responsibility for correctness:

  • Qty3::raw_si / Qty3::from_raw_si — into and out of raw glam::DVec3 (frame tag and dimension are erased on raw_si, reattached without check on from_raw_si).
  • SecondsSince::from_seconds / as_seconds — into and out of raw f64 seconds (time-scale tag is erased on as_seconds, reattached without check on from_seconds, which is how a TAI reading can be relabeled as TT without applying the 32.184 s offset).
  • JeodQuat::from_array — accepts a raw [f64; 4] without normalization or convention checks. Use NormalizedQuat::new(q)? to recover the unit-norm witness.
  • FrameTransform::from_matrix — accepts a raw DMat3 without checking orthogonality. The validating sibling is FrameTransform::from_matrix_validated.

These boundaries are deliberate: inside the _inner / _impl kernels of astrodyn_* crates the math runs on f64 / DVec3 / DMat3 for arithmetic density. Unit, frame, time-scale, and quaternion-convention slips inside a kernel are caught only at the F64Ext and typed-API ingestion boundary — once you’ve crossed into a raw representation the caller is responsible.

See the Type-System wiki page for the contributor primer (phantom-tag pattern, adding a new frame/scale/quantity, reading compiler errors, escape hatches) and examples/typed_mission.rs for the canonical worked example.

§Quick start

use astrodyn_quantities::prelude::*;

let altitude = 400.0.km();
let inclination = 51.6.deg();
let mass = 420_000.0.kg();

Re-exports§

pub use body_attitude::BodyAttitude;
pub use integ_origin::IntegOrigin;
pub use aliases::*;
pub use dims::*;
pub use frame::*;
pub use frame_transform::*;
pub use qty3::*;
pub use quat::*;
pub use time_scale::*;

Modules§

aliases
Convenience aliases for common physical 3-vectors.
body_attitude
BodyAttitude<V> — a vehicle-tagged inertial-to-body attitude that owns its mutation API.
body_constants
Canonical body constants (gravitational parameter, equatorial radius, polar radius, flattening coefficient) for the bodies that astrodyn supports out of the box.
diagnostics
Custom compiler diagnostics via #[diagnostic::on_unimplemented].
dims
Custom quantity dimensions not already present in uom::si.
ext
The F64Ext facade and its vector/array companions.
frame
Reference-frame phantom markers.
frame_transform
Typed frame transforms: FrameTransform<From, To> rotates vectors from frame From to frame To.
harmonic
HarmonicDegree — semantic newtype over usize for spherical-harmonic degree / order indices.
inertia
InertiaTensor<F> — a frame-tagged 3×3 inertia tensor.
integ_origin
Integration-frame origin and the typed shift to root-inertial.
ops
Arithmetic operators on Qty3.
prelude
Prelude: use astrodyn_quantities::prelude::*; brings in everything mission crates typically need without PhantomData or uom::si::* noise.
qty3
Qty3<D, F> — a frame-tagged, dimension-typed 3-vector.
quat
Quaternion convention tags and a normalization witness.
time_scale
Time-scale phantom markers + typed seconds.

Macros§

define_planet
Define a new compile-time Planet marker type.
define_vehicle
Define a new compile-time Vehicle marker type.