ranim_core/traits/transform/
scale.rs1use std::cmp::Ordering;
2
3use glam::{DVec3, dvec3};
4use itertools::Itertools;
5
6use crate::{anchor::Aabb, traits::StrokeWidth};
7
8#[derive(Debug, Clone, Copy)]
10pub enum ScaleHint {
11 X(f64),
13 Y(f64),
15 Z(f64),
17 PorportionalX(f64),
19 PorportionalY(f64),
21 PorportionalZ(f64),
23}
24
25pub trait ScaleTransform {
29 fn scale(&mut self, scale: DVec3) -> &mut Self;
31}
32
33impl ScaleTransform for DVec3 {
34 fn scale(&mut self, scale: DVec3) -> &mut Self {
35 *self *= scale;
36 self
37 }
38}
39
40impl<T: ScaleTransform> ScaleTransform for [T] {
41 fn scale(&mut self, scale: DVec3) -> &mut Self {
42 self.iter_mut().for_each(|x| {
43 x.scale(scale);
44 });
45 self
46 }
47}
48
49impl<T: ScaleTransform> ScaleTransform for Vec<T> {
50 fn scale(&mut self, scale: DVec3) -> &mut Self {
51 self.as_mut_slice().scale(scale);
52 self
53 }
54}
55
56pub trait ScaleTransformExt: ScaleTransform {
60 fn calc_scale_ratio(&self, hint: ScaleHint) -> DVec3
64 where
65 Self: Aabb,
66 {
67 let aabb_size = self.aabb_size();
68 match hint {
69 ScaleHint::X(v) => dvec3(v / (aabb_size.x), 1.0, 1.0),
70 ScaleHint::Y(v) => dvec3(1.0, v / (aabb_size.y), 1.0),
71 ScaleHint::Z(v) => dvec3(1.0, 1.0, v / aabb_size.z),
72 ScaleHint::PorportionalX(v) => DVec3::splat(v / aabb_size.x),
73 ScaleHint::PorportionalY(v) => DVec3::splat(v / aabb_size.y),
74 ScaleHint::PorportionalZ(v) => DVec3::splat(v / aabb_size.z),
75 }
76 }
77 fn scale_to(&mut self, hint: ScaleHint) -> &mut Self
81 where
82 Self: Aabb,
83 {
84 self.scale(self.calc_scale_ratio(hint));
85 self
86 }
87 fn scale_to_min(&mut self, hints: &[ScaleHint]) -> &mut Self
91 where
92 Self: Aabb,
93 {
94 let scale = hints
95 .iter()
96 .map(|hint| self.calc_scale_ratio(*hint))
97 .reduce(|a, b| a.min(b))
98 .unwrap_or(DVec3::ONE);
99 self.scale(scale);
100 self
101 }
102 fn scale_to_max(&mut self, hints: &[ScaleHint]) -> &mut Self
106 where
107 Self: Aabb,
108 {
109 let scale = hints
110 .iter()
111 .map(|hint| self.calc_scale_ratio(*hint))
112 .reduce(|a, b| a.max(b))
113 .unwrap_or(DVec3::ONE);
114 self.scale(scale);
115 self
116 }
117}
118
119impl<T: ScaleTransform + ?Sized> ScaleTransformExt for T {}
120
121pub trait ScaleTransformStrokeExt: ScaleTransform + StrokeWidth {
123 fn scale_with_stroke(&mut self, scale: DVec3) -> &mut Self {
125 self.scale(scale);
126
127 let scales = [scale.x, scale.y, scale.z];
128 let idx = scales
129 .iter()
130 .map(|x: &f64| if *x > 1.0 { *x } else { 1.0 / *x })
131 .position_max_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Equal))
132 .unwrap_or(0);
133 let scale = scales[idx];
134 self.apply_stroke_func(|widths| widths.iter_mut().for_each(|w| w.0 *= scale as f32));
135 self
136 }
137 fn scale_to_with_stroke(&mut self, hint: ScaleHint) -> &mut Self
141 where
142 Self: Aabb,
143 {
144 let scale = self.calc_scale_ratio(hint);
145 self.scale_with_stroke(scale)
146 }
147}
148
149impl<T: ScaleTransform + StrokeWidth + ?Sized> ScaleTransformStrokeExt for T {}