meshx/ops/
transform.rs

1//!
2//! This module defines a number of transformations that can be applied to geometrical objects like
3//! meshes or point clouds.
4//!
5
6use crate::ops::Skew;
7use math::{Matrix3, RealField, Vector3};
8use num_traits::Zero;
9
10pub trait Scale<T: Clone> {
11    /// Scale the given object in 3D by a given vector of scale factors.
12    /// `s = [1.0; 3]` corresponds to a noop.
13    fn scale(&mut self, s: [T; 3]);
14    /// Uniformly scale the given object by the given factor in all dimensions.
15    fn uniform_scale(&mut self, s: T) {
16        self.scale([s.clone(), s.clone(), s]);
17    }
18}
19
20/// Rotate a given object by a certain amount. All functions rotate the object using the
21/// right-hand-rule.
22pub trait Rotate<T: RealField> {
23    /// Rotate the object using the given column-major rotation matrix.
24    fn rotate_by_matrix(&mut self, mtx: [[T; 3]; 3]);
25
26    /// Rotate the object around the given unit vector `u` by the given angle `theta` (in radians).
27    ///
28    /// Note that it is assumed that `u` is indeed a unit vector, no further normalization should
29    /// be performed.
30    fn rotate(&mut self, axis: [T; 3], theta: T) {
31        let u = Vector3::from(axis.clone());
32        let [x, y, z] = axis;
33        let id = Matrix3::identity();
34        let u_skew = u.skew();
35        let cos_theta = theta.clone().cos();
36
37        // Compute rotation matrix
38        // R = cos(theta) * I + sin(theta)*[u]_X + (1 - cos(theta))(uu^T)
39        // Compute outer product
40        let u_v_t = {
41            let [a, b, c]: [T; 3] = (u * (T::one() - cos_theta.clone())).into();
42            Matrix3::from([
43                [x.clone() * a.clone(), x.clone() * b.clone(), x * c.clone()],
44                [y.clone() * a.clone(), y.clone() * b.clone(), y * c.clone()],
45                [z.clone() * a, z.clone() * b, z * c],
46            ])
47        };
48        let mtx = id * cos_theta + u_skew * theta.sin() + u_v_t;
49        self.rotate_by_matrix(mtx.into());
50    }
51
52    /// Rotate the object using the given Euler vector (or rotation vector) `e`. The direction of
53    /// `e` specifies the axis of rotation and its magnitude is the angle in radians.
54    fn rotate_by_vector(&mut self, e: [T; 3])
55    where
56        T: Zero,
57    {
58        let e = Vector3::from(e);
59        let theta = e.norm();
60        if theta == T::zero() {
61            return;
62        }
63
64        let u = e / theta.clone();
65        self.rotate(u.into(), theta);
66    }
67}
68
69pub trait Translate<T> {
70    /// Translate the object by the given translation vector (displacement) `t`.
71    fn translate(&mut self, t: [T; 3]);
72}
73
74/*
75 * Functional variants of the above traits and their blanket implementations.
76 */
77
78pub trait Scaled<T>
79where
80    Self: Sized,
81{
82    /// Return a scaled version of `self`.
83    fn scaled(self, s: [T; 3]) -> Self;
84    /// Return a uniformly scaled version of `self`.
85    fn uniformly_scaled(self, s: T) -> Self;
86}
87
88pub trait Rotated<T>
89where
90    Self: Sized,
91{
92    /// Return a version of `self` rotated about the unit vector `u` by the given angle `theta` (in
93    /// radians).
94    ///
95    /// Note that it is assumed that `u` is indeed a unit vector, no further normalization should
96    /// be performed.
97    fn rotated(self, u: [T; 3], theta: T) -> Self;
98    /// Return a version of `self` rotated using the given column-major rotation matrix
99    fn rotated_by_matrix(self, mtx: [[T; 3]; 3]) -> Self;
100    /// Return a version of `self` rotated about the Euler vector `e`.
101    fn rotated_by_vector(self, e: [T; 3]) -> Self;
102}
103
104pub trait Translated<T>
105where
106    Self: Sized,
107{
108    /// Return a version of `self` translated by the given translation vector `t`.
109    fn translated(self, t: [T; 3]) -> Self;
110}
111
112impl<S, T: Copy> Scaled<T> for S
113where
114    S: Scale<T> + Sized,
115{
116    fn scaled(mut self, s: [T; 3]) -> Self {
117        self.scale(s);
118        self
119    }
120    fn uniformly_scaled(mut self, s: T) -> Self {
121        self.uniform_scale(s);
122        self
123    }
124}
125
126impl<S, T: RealField> Rotated<T> for S
127where
128    S: Rotate<T> + Sized,
129{
130    fn rotated(mut self, u: [T; 3], theta: T) -> Self {
131        self.rotate(u, theta);
132        self
133    }
134    fn rotated_by_matrix(mut self, mtx: [[T; 3]; 3]) -> Self {
135        self.rotate_by_matrix(mtx);
136        self
137    }
138    fn rotated_by_vector(mut self, e: [T; 3]) -> Self {
139        self.rotate_by_vector(e);
140        self
141    }
142}
143
144impl<S, T> Translated<T> for S
145where
146    S: Translate<T> + Sized,
147{
148    fn translated(mut self, t: [T; 3]) -> Self {
149        self.translate(t);
150        self
151    }
152}