noise/noise_fns/transformers/
rotate_point.rs

1use crate::noise_fns::NoiseFn;
2
3/// Noise function that rotates the input value around the origin before
4/// returning the output value from the source function.
5///
6/// The get() method rotates the coordinates of the input value around the
7/// origin before returning the output value from the source function.
8///
9/// The coordinate system of the input value is assumed to be "right-handed"
10/// (_x_ increases to the right, _y_ increases upward, and _z_ increases inward).
11#[derive(Clone)]
12pub struct RotatePoint<Source> {
13    /// Source function that outputs a value
14    pub source: Source,
15
16    /// _x_ rotation angle applied to the input value, in degrees. The
17    /// default angle is set to 0.0 degrees.
18    pub x_angle: f64,
19
20    /// _y_ rotation angle applied to the input value, in degrees. The
21    /// default angle is set to 0.0 degrees.
22    pub y_angle: f64,
23
24    /// _z_ rotation angle applied to the input value, in degrees. The
25    /// default angle is set to 0.0 degrees.
26    pub z_angle: f64,
27
28    /// _u_ rotation angle applied to the input value, in degrees. The
29    /// default angle is set to 0.0 degrees.
30    pub u_angle: f64,
31}
32
33impl<Source> RotatePoint<Source> {
34    pub fn new(source: Source) -> Self {
35        Self {
36            source,
37            x_angle: 0.0,
38            y_angle: 0.0,
39            z_angle: 0.0,
40            u_angle: 0.0,
41        }
42    }
43
44    /// Sets the rotation angle around the _x_ axis to apply to the input
45    /// value.
46    pub fn set_x_angle(self, x_angle: f64) -> Self {
47        Self { x_angle, ..self }
48    }
49
50    /// Sets the rotation angle around the _y_ axis to apply to the input
51    /// value.
52    pub fn set_y_angle(self, y_angle: f64) -> Self {
53        Self { y_angle, ..self }
54    }
55
56    /// Sets the rotation angle around the _z_ axis to apply to the input
57    /// value.
58    pub fn set_z_angle(self, z_angle: f64) -> Self {
59        Self { z_angle, ..self }
60    }
61
62    /// Sets the rotation angle around the _u_ axis to apply to the input
63    /// value.
64    pub fn set_u_angle(self, u_angle: f64) -> Self {
65        Self { u_angle, ..self }
66    }
67
68    /// Sets the rotation angles around all of the axes to apply to the input
69    /// value.
70    pub fn set_angles(self, x_angle: f64, y_angle: f64, z_angle: f64, u_angle: f64) -> Self {
71        Self {
72            x_angle,
73            y_angle,
74            z_angle,
75            u_angle,
76            ..self
77        }
78    }
79}
80
81impl<Source> NoiseFn<f64, 2> for RotatePoint<Source>
82where
83    Source: NoiseFn<f64, 2>,
84{
85    fn get(&self, point: [f64; 2]) -> f64 {
86        // In two dimensions, the plane is _xy_, and we rotate around the
87        // z-axis.
88        let x = point[0];
89        let y = point[1];
90        let theta = self.z_angle.to_radians();
91
92        let x2 = x * theta.cos() - y * theta.sin();
93        let y2 = x * theta.sin() + y * theta.cos();
94
95        // get the output value using the offset input value instead of the
96        // original input value.
97        self.source.get([x2, y2])
98    }
99}
100
101impl<Source> NoiseFn<f64, 3> for RotatePoint<Source>
102where
103    Source: NoiseFn<f64, 3>,
104{
105    fn get(&self, point: [f64; 3]) -> f64 {
106        // In three dimensions, we could rotate around any of the x, y, or z
107        // axes. Need a more complicated function to handle this case.
108        let x_cos = self.x_angle.to_radians().cos();
109        let y_cos = self.y_angle.to_radians().cos();
110        let z_cos = self.z_angle.to_radians().cos();
111        let x_sin = self.x_angle.to_radians().sin();
112        let y_sin = self.y_angle.to_radians().sin();
113        let z_sin = self.z_angle.to_radians().sin();
114
115        let x1 = x_sin * y_sin * z_sin + y_cos * z_cos;
116        let y1 = x_cos * z_sin;
117        let z1 = y_sin * z_cos - y_cos * x_sin * z_sin;
118        let x2 = y_sin * x_sin * z_cos - y_cos * z_sin;
119        let y2 = x_cos * z_cos;
120        let z2 = -y_cos * x_sin * z_cos - y_sin * z_sin;
121        let x3 = -y_sin * x_cos;
122        let y3 = x_sin;
123        let z3 = y_cos * x_cos;
124
125        let x = (x1 * point[0]) + (y1 * point[1]) + (z1 * point[2]);
126        let y = (x2 * point[0]) + (y2 * point[1]) + (z2 * point[2]);
127        let z = (x3 * point[0]) + (y3 * point[1]) + (z3 * point[2]);
128
129        // get the output value using the offset input value instead of the
130        // original input value.
131        self.source.get([x, y, z])
132    }
133}
134
135impl<Source> NoiseFn<f64, 4> for RotatePoint<Source>
136where
137    Source: NoiseFn<f64, 4>,
138{
139    fn get(&self, _point: [f64; 4]) -> f64 {
140        // 4d rotations are hard.
141        unimplemented!();
142    }
143}