Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [unreleased]

## [0.7.1 - 2026-05-14]

### Added
- New frame-tagged 3×3 matrix primitives in `affn::matrix3`: `FrameMatrix3<F, T>` for general matrices and `SymmetricFrameMatrix3<F, T>` for symmetry-preserving covariance-style blocks.
- Rotation similarity helpers on the new matrix types: `rotated_by::<G>(&Rotation3)` for frame-changing `R · M · Rᵀ` transforms, with numerical re-symmetrization for `SymmetricFrameMatrix3`.
- `Rotation3::apply_vec<F1, F2, U>` for rotating typed `Vector`/`Displacement` values while preserving units and retagging the output frame.
- New frame-tagged 6×6 matrix primitives in `affn::matrix6`: `FrameMatrix6<F>` for general 6×6 matrices and `BlockDiagRotation6<F>` for block-diagonal `blockdiag(R, R)` frame-change transforms on `[position; velocity]` state vectors. Uses the instantaneous-rotation convention (time-derivative `Ṙ` ignored), which is correct for covariance transport and fixed-epoch STM frame changes.
- Additional helpers on `FrameMatrix3<F>`: `from_diagonal`, matrix–matrix product `mat_mul`, transpose `transpose`, and frame-retag `retag`.
- `Acceleration<F, U>` semantic type alias for `Vector<F, U>` where `U` is an acceleration unit, representing the second time-derivative of position. Available from `affn::cartesian`, the crate root, and `affn::prelude`.
- `Force<F, U>` semantic type alias for `Vector<F, U>` where `U` is a force unit (e.g. `Newton`, `Kilonewton`), representing the physical cause of acceleration via Newton's second law. Available from `affn::cartesian`, the crate root, and `affn::prelude`.

### Changed
- `Position<C, F, U>` now implements `PartialEq`, comparing both Cartesian coordinates and `center_params` so affine points only compare equal when they represent the same location relative to the same parameterized center state.
Expand Down
16 changes: 8 additions & 8 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[package]
name = "affn"
version = "0.7.0"
version = "0.7.1"
edition = "2021"
authors = ["VPRamon <vallespuigramon@gmail.com>"]
description = "Affine geometry primitives: strongly-typed coordinate systems, reference frames, and centers for scientific computing."
Expand All @@ -21,8 +21,8 @@ serde = ["dep:serde", "qtty/serde"]
astro = ["qtty/astro"]

[dependencies]
affn-derive = { version = "0.7.0", path = "affn-derive" }
qtty = "0.7.1"
affn-derive = { version = "0.7.1", path = "affn-derive" }
qtty = "0.8"
serde = { version = "1.0", default-features = false, features = ["derive"], optional = true }

[dev-dependencies]
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ Add the dependency:

```toml
[dependencies]
affn = "0.7.0"
qtty = "0.7.1"
affn = "0.7.1"
qtty = "0.8.1"
```

Define a center + frame and do basic affine algebra:
Expand Down
2 changes: 1 addition & 1 deletion affn-derive/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "affn-derive"
version = "0.7.0"
version = "0.7.1"
edition = "2021"
authors = ["VPRamon <vallespuigramon@gmail.com>"]
description = "Derive macros for affn: ReferenceFrame and ReferenceCenter"
Expand Down
79 changes: 50 additions & 29 deletions affn-derive/src/center.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,40 +69,61 @@ pub(crate) fn parse_center_attributes(input: &DeriveInput) -> syn::Result<Center
)?;

for meta in nested {
if let Meta::NameValue(nv) = meta {
if nv.path.is_ident("name") {
if let Expr::Lit(expr_lit) = &nv.value {
if let Lit::Str(lit_str) = &expr_lit.lit {
attrs.name = Some(lit_str.value());
continue;
match &meta {
Meta::NameValue(nv) => {
if nv.path.is_ident("name") {
if let Expr::Lit(expr_lit) = &nv.value {
if let Lit::Str(lit_str) = &expr_lit.lit {
attrs.name = Some(lit_str.value());
continue;
}
}
}
return Err(syn::Error::new_spanned(
&nv.value,
"expected string literal for `name`",
));
} else if nv.path.is_ident("params") {
if let Expr::Path(expr_path) = &nv.value {
attrs.params = Some(Type::Path(syn::TypePath {
qself: None,
path: expr_path.path.clone(),
}));
continue;
}
return Err(syn::Error::new_spanned(
&nv.value,
"expected type for `params`",
));
} else if nv.path.is_ident("affine") {
if let Expr::Lit(expr_lit) = &nv.value {
if let Lit::Bool(lit_bool) = &expr_lit.lit {
attrs.affine = lit_bool.value();
return Err(syn::Error::new_spanned(
&nv.value,
"expected string literal for `name`",
));
} else if nv.path.is_ident("params") {
if let Expr::Path(expr_path) = &nv.value {
attrs.params = Some(Type::Path(syn::TypePath {
qself: None,
path: expr_path.path.clone(),
}));
continue;
}
return Err(syn::Error::new_spanned(
&nv.value,
"expected type for `params`",
));
} else if nv.path.is_ident("affine") {
if let Expr::Lit(expr_lit) = &nv.value {
if let Lit::Bool(lit_bool) = &expr_lit.lit {
attrs.affine = lit_bool.value();
continue;
}
}
return Err(syn::Error::new_spanned(
&nv.value,
"expected boolean for `affine`",
));
} else {
return Err(syn::Error::new_spanned(
&nv.path,
format!(
"unknown `center` attribute `{}`; \
known attributes are: name, params, affine",
nv.path
.get_ident()
.map(|id| id.to_string())
.unwrap_or_else(|| "<unknown>".into())
),
));
}
}
_ => {
return Err(syn::Error::new_spanned(
&nv.value,
"expected boolean for `affine`",
&meta,
"unknown `center` attribute; expected a name=value attribute \
such as `name = \"...\"`, `params = MyType`, or `affine = true`",
));
}
}
Expand Down
23 changes: 22 additions & 1 deletion affn-derive/src/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,9 +284,30 @@ pub(crate) fn parse_frame_attributes(input: &DeriveInput) -> syn::Result<FrameAt
} else if nv.path.is_ident("ellipsoid") {
attrs.ellipsoid =
Some(syn::Ident::new(&value_str, proc_macro2::Span::call_site()));
} else {
return Err(syn::Error::new_spanned(
&nv.path,
format!(
"unknown `frame` attribute `{}`; \
known attributes are: name, polar, azimuth, \
distance, ellipsoid, inherent",
nv.path
.get_ident()
.map(|id| id.to_string())
.unwrap_or_else(|| "<unknown>".into())
),
));
}
}
_ => {}
_ => {
return Err(syn::Error::new_spanned(
&meta,
"unknown `frame` attribute; expected a name=value attribute \
such as `name = \"...\"`, `polar = \"...\"`, \
`azimuth = \"...\"`, `distance = \"...\"`, \
`ellipsoid = \"...\"`, or the bare flag `inherent`",
));
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/cartesian/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,6 @@ pub use xyz::XYZ;

pub use direction::Direction;
pub use position::{CenterParamsMismatchError, Position};
pub use vector::{Displacement, Vector, Velocity};
pub use vector::{Acceleration, Displacement, Force, Vector, Velocity};

pub use line_of_sight::{line_of_sight, line_of_sight_with_distance, try_line_of_sight};
14 changes: 14 additions & 0 deletions src/cartesian/vector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,20 @@ pub type Displacement<F, U> = Vector<F, U>;
/// Velocities represent rates of change of position.
pub type Velocity<F, U> = Vector<F, U>;

/// An acceleration vector (free vector with acceleration unit).
///
/// This is a semantic alias for [`Vector<F, U>`] where `U` is an acceleration
/// unit (e.g. `Per<Per<Kilometer, Second>, Second>`).
/// Accelerations represent the second time-derivative of position.
pub type Acceleration<F, U> = Vector<F, U>;

/// A force vector (free vector with force unit).
///
/// This is a semantic alias for [`Vector<F, U>`] where `U` is a force unit
/// (e.g. `Newton`, `Kilonewton`).
/// Forces represent the physical cause of acceleration via Newton's second law.
pub type Force<F, U> = Vector<F, U>;

// =============================================================================
// Tests
// =============================================================================
Expand Down
Loading
Loading