affn
Affine geometry primitives for strongly-typed coordinate systems.
affn is a small, domain-agnostic geometry kernel for scientific and engineering software. It provides:
- Reference centers (
C): the origin of a coordinate system (optionally parameterized viaC::Params) - Reference frames (
F): the orientation of axes - Typed coordinates: Cartesian, spherical, and ellipsoidal positions plus directions/vectors
- Affine operators:
Rotation3,Translation3, andIsometry3 - Units: distances/lengths are carried via
qttyunits at the type level
The goal is to make invalid operations (like adding two positions) fail at compile time.
Quick Start
Add the dependency:
[]
= "0.4"
= "0.4"
Define a center + frame and do basic affine algebra:
use ;
use ReferenceCenter;
use ReferenceFrame;
use *;
;
;
let a = new;
let b = new;
// Position - Position -> Displacement
let d: = b - a;
assert!;
// Position + Displacement -> Position
let c = a + d;
assert!;
Core Concepts
Position<C, F, U>: an affine point (depends on both center and frame)Direction<F>: a unit vector (frame-only, translation-invariant)Vector<F, U>/Displacement<F, U>/Velocity<F, U>: free vectors (frame-only)EllipsoidalPosition<C, F, U>: geodetic longitude/latitude/height on an ellipsoid-aware frame
The type system enforces the usual affine rules:
- ✅
Position - Position -> Displacement - ✅
Position + Displacement -> Position - ❌
Position + Position(does not compile)
Affine Operators
affn includes typed affine operators for pure geometric transforms:
Rotation3Translation3Isometry3
These operators preserve the existing frame tag. When you intentionally rotate from one frame into another, retag the result explicitly with reinterpret_frame:
use Position;
use Rotation3;
use *;
use *;
;
;
;
let pos_a = new;
let rot = rz;
let pos_b = .;
assert!;
Defining Custom Systems (Derive Macros)
For zero-sized marker types, use the derive macros re-exported by the crate:
use *;
;
;
Some centers need runtime parameters (e.g. “topocentric” depends on an observer):
use *;
;
Spherical ↔ Cartesian
Cartesian and spherical positions can be converted losslessly (up to floating point error):
use Position as CPos;
use Position as SPos;
use ReferenceCenter;
use ReferenceFrame;
use *;
;
;
let cart = new;
let sph: = cart.to_spherical;
let back: = from_spherical;
assert!;
Ellipsoidal Coordinates
affn::ellipsoidal::Position<C, F, U> models geodetic longitude, latitude, and height above an ellipsoid. Conversions to and from Cartesian coordinates are available when the frame implements HasEllipsoid.
Built-in terrestrial frames under the astro feature already carry ellipsoids:
ECEFusesWgs84ITRFusesGrs80
Example:
use ReferenceCenter;
use Position;
use *;
;
#
#
Built-In Astro Frames (optional)
Enable the astro feature to use the built-in astronomy and geodesy marker frames:
[]
= { = "0.4", = ["astro"] }
= "0.4"
Available built-ins include:
- Equatorial:
ICRS,ICRF,EquatorialMeanJ2000,EME2000,EquatorialMeanOfDate,EquatorialTrueOfDate,GCRS,CIRS,TIRS,FK4B1950,TEME - Ecliptic and galactic:
EclipticMeanJ2000,EclipticOfDate,EclipticTrueOfDate,Galactic - Terrestrial and horizontal:
Horizontal,ECEF,ITRF - Planetary body-fixed:
MercuryFixed,VenusFixed,MarsFixed,MoonPrincipalAxes,JupiterSystemIII,SaturnFixed,UranusFixed,NeptuneFixed,PlutoFixed
Examples
Run the included examples:
cargo run --example basic_cartesiancargo run --example parameterized_centercargo run --example spherical_roundtripcargo run --example serde_roundtrip --features serde
Serde (optional)
affn supports serde serialization for its core coordinate types behind an opt-in feature flag.
Enable it in your Cargo.toml:
[]
= { = "0.4", = ["serde"] }
= "0.4"
This feature also forwards serialization support to dependencies where needed (e.g. qtty/serde, and nalgebra's serde-serialize).
To run the serde example:
cargo run --example serde_roundtrip --features serde
Or to run tests including serde round-trips:
cargo test --features serde
License
Licensed under AGPL-3.0-only. See LICENSE.