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-vectorsQty3<D, F>with aliasesPosition<F>,Velocity<F>,Acceleration<F>,Force<F>,Torque<F>, …- Quaternion convention tags (
ScalarFirst/ScalarLast,LeftTransform/RightTransform) plus aNormalizedQuatconstructor-gated witness - Typed
FrameTransform<From, To>composing only when inner frames match - The
F64Extfacade (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 + Massis rejected becauseQty3’sAddimpl requires identical dimensionD. -
Frame mismatch on
+/-/+=/-=—Position<Ecef> + Position<RootInertial>fails with a tailored#[diagnostic::on_unimplemented]message pointing atFrameTransform. Wired via thediagnostics::CompatibleFrames<Fl, Fr>bound inops. -
Time-scale separation —
SecondsSince<S>has noAdd/Subimpl across distinct scales, so direct arithmetic between (e.g.)SecondsSince<TAI>andSecondsSince<TT>is rejected. The intended way to combine scales is viaTimeConverter::apply. The rawSecondsSince::from_seconds/as_secondsboundaries can still relabel anf64across scales without applying the offset — see “Where the guards stop” below. -
Quaternion convention separation — layout (
ScalarFirstvsScalarLast), transform convention (LeftTransformvsRightTransform), and normalization status are distinct phantom tags.NormalizedQuat<L, T>is a separate type fromQuat<L, T>, so a rawQuatcannot 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 forFrom = To. -
Cross-dimension multiply / divide on
Qty3usestypenumexponent arithmetic, soVelocity × Time → PositionandAcceleration × Time → Velocityare 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>, andIntegrationFrameare kind-distinct phantoms. Body integration-frame state cannot silently flow into root-inertial-only consumers (gravity, SRP, relativistic); the only safe transition is viaIntegOrigin. -
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 thediagnostics::CompatibleVehicles/diagnostics::CompatibleVehiclePairmarkers. Each type exposes a zero-costassert_*witness method whosewherebound resolves only when the vehicle phantoms agree; on mismatch the diagnostic names the expected and found vehicles in physics language instead of aPhantomData<…>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 rawglam::DVec3(frame tag and dimension are erased onraw_si, reattached without check onfrom_raw_si).SecondsSince::from_seconds/as_seconds— into and out of rawf64seconds (time-scale tag is erased onas_seconds, reattached without check onfrom_seconds, which is how aTAIreading can be relabeled asTTwithout applying the 32.184 s offset).JeodQuat::from_array— accepts a raw[f64; 4]without normalization or convention checks. UseNormalizedQuat::new(q)?to recover the unit-norm witness.FrameTransform::from_matrix— accepts a rawDMat3without checking orthogonality. The validating sibling isFrameTransform::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
F64Extfacade and its vector/array companions. - frame
- Reference-frame phantom markers.
- frame_
transform - Typed frame transforms:
FrameTransform<From, To>rotates vectors from frameFromto frameTo. - harmonic
HarmonicDegree— semantic newtype overusizefor 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 withoutPhantomDataoruom::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
Planetmarker type. - define_
vehicle - Define a new compile-time
Vehiclemarker type.