ranim_core/traits/transform/
scale.rs1use std::cmp::Ordering;
2
3use glam::{DVec3, dvec3};
4use itertools::Itertools;
5
6use crate::{
7 anchor::Aabb,
8 traits::{StrokeWidth, transform::group::Similarity},
9};
10
11use super::ApplyTransform;
12
13#[derive(Debug, Clone, Copy)]
15pub enum ScaleHint {
16 X(f64),
18 Y(f64),
20 Z(f64),
22 PorportionalX(f64),
24 PorportionalY(f64),
26 PorportionalZ(f64),
28}
29
30pub trait ScaleTransform {
36 fn scale(&mut self, scale: DVec3) -> &mut Self;
38}
39
40pub trait ScaleTransformExt: ScaleTransform {
44 fn calc_scale_ratio(&self, hint: ScaleHint) -> DVec3
48 where
49 Self: Aabb,
50 {
51 let aabb_size = self.aabb_size();
52 match hint {
53 ScaleHint::X(v) => dvec3(v / (aabb_size.x), 1.0, 1.0),
54 ScaleHint::Y(v) => dvec3(1.0, v / (aabb_size.y), 1.0),
55 ScaleHint::Z(v) => dvec3(1.0, 1.0, v / aabb_size.z),
56 ScaleHint::PorportionalX(v) => DVec3::splat(v / aabb_size.x),
57 ScaleHint::PorportionalY(v) => DVec3::splat(v / aabb_size.y),
58 ScaleHint::PorportionalZ(v) => DVec3::splat(v / aabb_size.z),
59 }
60 }
61 fn scale_to(&mut self, hint: ScaleHint) -> &mut Self
65 where
66 Self: Aabb,
67 {
68 self.scale(self.calc_scale_ratio(hint));
69 self
70 }
71 fn scale_to_min(&mut self, hints: &[ScaleHint]) -> &mut Self
75 where
76 Self: Aabb,
77 {
78 let scale = hints
79 .iter()
80 .map(|hint| self.calc_scale_ratio(*hint))
81 .reduce(|a, b| a.min(b))
82 .unwrap_or(DVec3::ONE);
83 self.scale(scale);
84 self
85 }
86 fn scale_to_max(&mut self, hints: &[ScaleHint]) -> &mut Self
90 where
91 Self: Aabb,
92 {
93 let scale = hints
94 .iter()
95 .map(|hint| self.calc_scale_ratio(*hint))
96 .reduce(|a, b| a.max(b))
97 .unwrap_or(DVec3::ONE);
98 self.scale(scale);
99 self
100 }
101}
102
103impl<T: ScaleTransform + ?Sized> ScaleTransformExt for T {}
104
105pub trait ScaleTransformStrokeExt: ScaleTransform + StrokeWidth {
107 fn scale_with_stroke(&mut self, scale: DVec3) -> &mut Self {
109 self.scale(scale);
110
111 let scales = [scale.x, scale.y, scale.z];
112 let idx = scales
113 .iter()
114 .map(|x: &f64| if *x > 1.0 { *x } else { 1.0 / *x })
115 .position_max_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Equal))
116 .unwrap_or(0);
117 let scale = scales[idx];
118 self.apply_stroke_func(|widths| widths.iter_mut().for_each(|w| w.0 *= scale as f32));
119 self
120 }
121 fn scale_to_with_stroke(&mut self, hint: ScaleHint) -> &mut Self
125 where
126 Self: Aabb,
127 {
128 let scale = self.calc_scale_ratio(hint);
129 self.scale_with_stroke(scale)
130 }
131}
132
133impl<T: ScaleTransform + StrokeWidth + ?Sized> ScaleTransformStrokeExt for T {}
134
135pub trait UniformScaleTransform {
137 fn scale_uniform(&mut self, s: f64) -> &mut Self;
139}
140
141impl<T: ApplyTransform<Similarity> + ?Sized> UniformScaleTransform for T {
142 fn scale_uniform(&mut self, s: f64) -> &mut Self {
143 self.apply(Similarity::from_scale(s))
144 }
145}