1use crate::{BoundingBox, Object, PrimitiveParameters, RealField};
2use num_traits::Float;
3
4#[derive(Clone, Debug)]
5pub struct AffineTransformer<S: RealField> {
9 object: Box<dyn Object<S>>,
10 transform: na::Matrix4<S>,
11 transposed3x3: na::Matrix3<S>,
12 scale_min: S,
13 bbox: BoundingBox<S>,
14}
15
16impl<S: RealField + Float + From<f32>> Object<S> for AffineTransformer<S> {
17 fn approx_value(&self, p: &na::Point3<S>, slack: S) -> S {
18 let approx = self.bbox.distance(p);
19 if approx <= slack {
20 self.object
21 .approx_value(&self.transform.transform_point(&p), slack / self.scale_min)
22 * self.scale_min
23 } else {
24 approx
25 }
26 }
27 fn bbox(&self) -> &BoundingBox<S> {
28 &self.bbox
29 }
30 fn set_parameters(&mut self, p: &PrimitiveParameters<S>) {
31 self.object.set_parameters(p);
32 }
33 fn normal(&self, p: &na::Point3<S>) -> na::Vector3<S> {
34 let normal_at_p = self.object.normal(&self.transform.transform_point(&p));
35 let transformed_normal = self.transposed3x3 * normal_at_p;
36 transformed_normal.normalize()
37 }
38 fn translate(&self, v: &na::Vector3<S>) -> Box<dyn Object<S>> {
39 let new_trans = self.transform.prepend_translation(&-v);
40 Box::new(AffineTransformer::new_with_scaler(
41 self.object.clone(),
42 new_trans,
43 self.scale_min,
44 ))
45 }
46 fn rotate(&self, r: &na::Vector3<S>) -> Box<dyn Object<S>> {
47 let euler = ::na::Rotation::from_euler_angles(r.x, r.y, r.z).to_homogeneous();
48 let new_trans = self.transform * euler;
49 Box::new(AffineTransformer::new_with_scaler(
50 self.object.clone(),
51 new_trans,
52 self.scale_min,
53 ))
54 }
55 fn scale(&self, s: &na::Vector3<S>) -> Box<dyn Object<S>> {
56 let one: S = From::from(1f32);
57 let new_trans = self.transform.prepend_nonuniform_scaling(&na::Vector3::new(
58 one / s.x,
59 one / s.y,
60 one / s.z,
61 ));
62 Box::new(AffineTransformer::new_with_scaler(
63 self.object.clone(),
64 new_trans,
65 self.scale_min * Float::min(s.x, Float::min(s.y, s.z)),
66 ))
67 }
68}
69
70impl<S: RealField + Float + From<f32>> AffineTransformer<S> {
71 fn identity(o: Box<dyn Object<S>>) -> Self {
72 AffineTransformer::new(o, na::Matrix4::identity())
73 }
74 fn new(o: Box<dyn Object<S>>, t: na::Matrix4<S>) -> Self {
75 let one: S = From::from(1f32);
76 AffineTransformer::new_with_scaler(o, t, one)
77 }
78 fn new_with_scaler(o: Box<dyn Object<S>>, t: na::Matrix4<S>, scale_min: S) -> Self {
79 match t.try_inverse() {
85 None => panic!("Failed to invert {:?}", t),
86 Some(ref t_inv) => {
87 let bbox = o.bbox().transform(t_inv);
88 let transposed3x3 = t
89 .fixed_slice::<::na::core::dimension::U3, ::na::core::dimension::U3>(0, 0)
90 .transpose();
91 AffineTransformer {
92 object: o,
93 transform: t,
94 transposed3x3,
95 scale_min,
96 bbox,
97 }
98 }
99 }
100 }
101 pub fn new_translate(o: Box<dyn Object<S>>, v: &na::Vector3<S>) -> Box<dyn Object<S>> {
103 AffineTransformer::identity(o).translate(v)
104 }
105 pub fn new_rotate(o: Box<dyn Object<S>>, r: &na::Vector3<S>) -> Box<dyn Object<S>> {
107 AffineTransformer::identity(o).rotate(r)
108 }
109 pub fn new_scale(o: Box<dyn Object<S>>, s: &na::Vector3<S>) -> Box<dyn Object<S>> {
111 AffineTransformer::identity(o).scale(s)
112 }
113}
114
115#[cfg(test)]
116mod test {
117 use crate::test::MockObject;
118 use crate::Object;
119
120 #[test]
121 fn translate() {
122 let normal = na::Vector3::new(1.0, 0.0, 0.0);
123 let mut mock_object = MockObject::new(1.0, normal);
124 let receiver = mock_object.add_normal_call_recorder(1);
125 let translation = na::Vector3::new(0.0001, 0.0, 0.0);
126 let translated = mock_object.translate(&translation);
127 let p = na::Point3::new(1.0, 0.0, 0.0);
128 assert_eq!(translated.normal(&p), normal);
129 assert_eq!(receiver.recv().unwrap(), p - translation);
130 }
131
132 #[test]
133 fn scale() {
134 let normal = na::Vector3::new(1.0, 0.0, 0.0);
135 let mut mock_object = MockObject::new(1.0, normal);
136 let receiver = mock_object.add_normal_call_recorder(1);
137 let scale = na::Vector3::new(0.1, 0.1, 0.1);
138 let scaled = mock_object.scale(&scale);
139 let p = na::Point3::new(1.0, 0.0, 0.0);
140 assert_eq!(scaled.normal(&p), normal);
141 assert_eq!(receiver.recv().unwrap(), p / 0.1);
142 }
143
144 #[test]
145 fn rotate() {
146 let normal = na::Vector3::new(1.0, 0.0, 0.0);
147 let mut mock_object = MockObject::new(1.0, normal);
148 let receiver = mock_object.add_normal_call_recorder(1);
149 let rotation = na::Vector3::new(0.0, 0.0, ::std::f64::consts::PI / 6.0);
150 let rotated = mock_object.rotate(&rotation);
151 let p = na::Point3::new(1.0, 0.0, 0.0);
152
153 assert_relative_eq!(
154 rotated.normal(&p),
155 na::Vector3::new(num_traits::Float::sqrt(3.0) / 2.0, -0.5, 0.0)
156 );
157 assert_relative_eq!(
158 receiver.try_recv().unwrap(),
159 na::Point3::new(num_traits::Float::sqrt(3.0) / 2.0, 0.5, 0.0)
160 );
161 }
162
163 #[test]
164 fn scale_and_translate() {
165 let normal = na::Vector3::new(1.0, 0.0, 0.0);
166 let mut mock_object = MockObject::new(1.0, normal);
167 let receiver = mock_object.add_normal_call_recorder(1);
168 let scale = na::Vector3::new(0.1, 0.1, 0.1);
169 let scaled = mock_object.scale(&scale);
170 let translation = na::Vector3::new(5.0, 0.0, 0.0);
171 let translated = scaled.translate(&translation);
172 let p = na::Point3::new(1.0, 0.0, 0.0);
173 assert_eq!(translated.normal(&p), normal);
174 assert_eq!(receiver.recv().unwrap(), (p - translation) / 0.1);
175 }
176
177 #[test]
178 fn translate_and_scale() {
179 let normal = na::Vector3::new(1.0, 0.0, 0.0);
180 let mut mock_object = MockObject::new(1.0, normal);
181 let receiver = mock_object.add_normal_call_recorder(1);
182 let translation = na::Vector3::new(5.0, 0.0, 0.0);
183 let translated = mock_object.translate(&translation);
184 let scale = na::Vector3::new(0.1, 0.1, 0.1);
185 let scaled = translated.scale(&scale);
186 let p = na::Point3::new(1.0, 0.0, 0.0);
187 assert_eq!(scaled.normal(&p), normal);
188 assert_eq!(receiver.recv().unwrap(), p / 0.1 - translation);
189 }
190
191 #[test]
192 fn rotate_and_translate() {
193 let normal = na::Vector3::new(1.0, 0.0, 0.0);
194 let mut mock_object = MockObject::new(1.0, normal);
195 let receiver = mock_object.add_normal_call_recorder(1);
196 let rotation = na::Vector3::new(0.0, 0.0, ::std::f64::consts::PI / 2.0);
197 let rotated = mock_object.rotate(&rotation);
198 let translation = na::Vector3::new(5.0, 0.0, 0.0);
199 let translated = rotated.translate(&translation);
200 let p = na::Point3::new(1.0, 0.0, 0.0);
201 translated.normal(&p);
202 assert_relative_eq!(
203 receiver.recv().unwrap(),
204 na::Point3::new(
205 p.y - translation.y,
206 p.x - translation.x,
207 p.z - translation.z
208 ),
209 epsilon = 10e-10
210 );
211 }
212
213 #[test]
214 fn translate_and_rotate() {
215 let normal = na::Vector3::new(1.0, 0.0, 0.0);
216 let mut mock_object = MockObject::new(1.0, normal);
217 let receiver = mock_object.add_normal_call_recorder(1);
218 let translation = na::Vector3::new(5.0, 0.0, 0.0);
219 let translated = mock_object.translate(&translation);
220 let rotation = na::Vector3::new(0.0, 0.0, ::std::f64::consts::PI / 2.0);
221 let rotated = translated.rotate(&rotation);
222 let p = na::Point3::new(1.0, 0.0, 0.0);
223 rotated.normal(&p);
224 assert_relative_eq!(
225 receiver.recv().unwrap(),
226 na::Point3::new(p.y, p.x, p.z) - translation,
227 epsilon = 10e-10
228 );
229 }
230}