Skip to main content

ranim_core/traits/transform/
mod.rs

1/// Types of transforms based on group theory.
2pub mod group;
3mod rotate;
4mod scale;
5mod shift;
6
7pub use group::{Diag, NotSimilarity, Rigid, Similarity, TransformGroup, Translation};
8pub use rotate::RotateTransform;
9pub use scale::{
10    ScaleHint, ScaleTransform, ScaleTransformExt, ScaleTransformStrokeExt, UniformScaleTransform,
11};
12pub use shift::{ShiftTransform, ShiftTransformExt};
13
14use glam::{DAffine3, DVec3};
15
16// MARK: ApplyTransform
17/// A group action of `G` on `Self`: baking a transform into the item's data.
18///
19/// This is the single primitive trait of the transform system. A type
20/// declares its *closure group* by the bound it implements this trait for:
21///
22/// - `impl<G: Into<DAffine3>> ApplyTransform<G> for T` — **affine closure**
23///   (point-data types: `VItem`, polygons, meshes, ...),
24/// - `impl<G: Into<Similarity>> ApplyTransform<G> for T` — **similarity
25///   closure** (circles, spheres, squares, circular arcs, ...).
26///
27/// The operation traits ([`ShiftTransform`], [`RotateTransform`],
28/// [`ScaleTransform`], [`UniformScaleTransform`]) are blanket-derived from
29/// this trait, so implementing `ApplyTransform<G>` provides them
30/// automatically — and opts out of implementing them manually (the
31/// coherence conflict is intentional: it keeps one method name meaning one
32/// group action across all types).
33pub trait ApplyTransform<G> {
34    /// Bake `transform` (expressed in world coordinates) into the item's
35    /// data, in place.
36    fn apply(&mut self, transform: G) -> &mut Self;
37}
38
39impl<G: Into<DAffine3>> ApplyTransform<G> for DVec3 {
40    fn apply(&mut self, transform: G) -> &mut Self {
41        *self = transform.into().transform_point3(*self);
42        self
43    }
44}
45
46impl<G: Copy + Into<DAffine3>, T: ApplyTransform<G>> ApplyTransform<G> for [T] {
47    fn apply(&mut self, transform: G) -> &mut Self {
48        self.iter_mut().for_each(|x| {
49            x.apply(transform);
50        });
51        self
52    }
53}
54
55impl<G: Copy + Into<DAffine3>, T: ApplyTransform<G>> ApplyTransform<G> for Vec<T> {
56    fn apply(&mut self, transform: G) -> &mut Self {
57        self.as_mut_slice().apply(transform);
58        self
59    }
60}
61
62// MARK: Blanket derivations
63// One method name, one group action. The bounds name the required group
64// precisely: shifting needs T(3), rotating needs SE(3), (axis-aligned)
65// scaling needs Diag, uniform scaling needs Sim(3).
66
67impl<T: ApplyTransform<Translation> + ?Sized> ShiftTransform for T {
68    fn shift(&mut self, offset: DVec3) -> &mut Self {
69        self.apply(Translation(offset))
70    }
71}
72
73impl<T: ApplyTransform<Rigid> + ?Sized> RotateTransform for T {
74    fn rotate_on_axis(&mut self, axis: DVec3, angle: f64) -> &mut Self {
75        self.apply(Rigid::from_axis_angle(axis, angle))
76    }
77}
78
79impl<T: ApplyTransform<Diag> + ?Sized> ScaleTransform for T {
80    fn scale(&mut self, scale: DVec3) -> &mut Self {
81        self.apply(Diag(scale))
82    }
83}