cherry_rs/core/math/
vec3.rs1use serde::{Deserialize, Serialize};
3
4use crate::core::{Float, EPSILON, PI};
5
6const TOL: Float = (1 as Float) * EPSILON;
7
8#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
9#[serde(into = "[Float; 3]")]
10pub struct Vec3 {
11 e: [Float; 3],
12}
13
14impl From<Vec3> for [Float; 3] {
16 fn from(val: Vec3) -> Self {
17 val.e
18 }
19}
20
21impl Vec3 {
22 pub fn new(e0: Float, e1: Float, e2: Float) -> Self {
23 Self { e: [e0, e1, e2] }
24 }
25
26 pub fn x(&self) -> Float {
27 self.e[0]
28 }
29
30 pub fn y(&self) -> Float {
31 self.e[1]
32 }
33
34 pub fn z(&self) -> Float {
35 self.e[2]
36 }
37
38 pub fn set_x(&mut self, x: Float) {
39 self.e[0] = x;
40 }
41
42 pub fn set_y(&mut self, y: Float) {
43 self.e[1] = y;
44 }
45
46 pub fn set_z(&mut self, z: Float) {
47 self.e[2] = z;
48 }
49
50 pub fn k(&self) -> Float {
51 self.e[0]
52 }
53
54 pub fn l(&self) -> Float {
55 self.e[1]
56 }
57
58 pub fn m(&self) -> Float {
59 self.e[2]
60 }
61
62 pub fn length(&self) -> Float {
63 self.length_squared().sqrt()
64 }
65
66 pub fn length_squared(&self) -> Float {
67 self.e.iter().map(|e| e * e).sum()
68 }
69
70 pub fn normalize(&self) -> Self {
71 let length = self.length();
72 Self::new(self.e[0] / length, self.e[1] / length, self.e[2] / length)
73 }
74
75 pub fn is_unit(&self) -> bool {
76 (self.length_squared() - 1.0).abs() / Float::max(1.0, self.length_squared()) < TOL
77 }
78
79 pub fn dot(&self, rhs: Self) -> Float {
80 self.e[0] * rhs.e[0] + self.e[1] * rhs.e[1] + self.e[2] * rhs.e[2]
81 }
82
83 pub fn sq_grid_in_circ(
97 radius: Float,
98 spacing: Float,
99 z: Float,
100 radial_offset_x: Float,
101 radial_offset_y: Float,
102 ) -> Vec<Self> {
103 let r_over_s = radius / spacing;
105 let num_samples = (PI * r_over_s * r_over_s + 9 as Float * r_over_s).ceil() as usize;
106
107 let mut samples = Vec::with_capacity(num_samples);
109 let mut x = -radius;
110 while x <= radius {
111 let mut y = -radius;
112 while y <= radius {
113 if x * x + y * y <= radius * radius {
114 samples.push(Self::new(x + radial_offset_x, y + radial_offset_y, z));
115 }
116 y += spacing;
117 }
118 x += spacing;
119 }
120
121 samples
122 }
123
124 pub fn fan(
141 n: usize,
142 r: Float,
143 theta: Float,
144 z: Float,
145 radial_offset_x: Float,
146 radial_offset_y: Float,
147 ) -> Vec<Self> {
148 let mut vecs = Vec::with_capacity(n);
149 let step = 2.0 * r / (n - 1) as Float;
150 for i in 0..n {
151 let x = (-r + i as Float * step) * theta.cos() + radial_offset_x;
152 let y = (-r + i as Float * step) * theta.sin() + radial_offset_y;
153 vecs.push(Vec3::new(x, y, z));
154 }
155 vecs
156 }
157}
158
159impl PartialEq for Vec3 {
160 fn eq(&self, rhs: &Self) -> bool {
161 (self.e[0] - rhs.e[0]) * (self.e[0] - rhs.e[0])
162 + (self.e[1] - rhs.e[1]) * (self.e[1] - rhs.e[1])
163 + (self.e[2] - rhs.e[2]) * (self.e[2] - rhs.e[2])
164 < TOL * TOL
165 }
166}
167
168impl std::ops::Add<Vec3> for Vec3 {
169 type Output = Self;
170
171 fn add(self, rhs: Self) -> Self {
172 Self::new(
173 self.e[0] + rhs.e[0],
174 self.e[1] + rhs.e[1],
175 self.e[2] + rhs.e[2],
176 )
177 }
178}
179
180impl std::ops::AddAssign<Vec3> for Vec3 {
181 fn add_assign(&mut self, rhs: Self) {
182 self.e[0] += rhs.e[0];
183 self.e[1] += rhs.e[1];
184 self.e[2] += rhs.e[2];
185 }
186}
187
188impl std::ops::Neg for Vec3 {
189 type Output = Self;
190
191 fn neg(self) -> Self {
192 Self::new(-self.e[0], -self.e[1], -self.e[2])
193 }
194}
195
196impl std::ops::Sub<Vec3> for Vec3 {
197 type Output = Self;
198
199 fn sub(self, rhs: Self) -> Self {
200 Self::new(
201 self.e[0] - rhs.e[0],
202 self.e[1] - rhs.e[1],
203 self.e[2] - rhs.e[2],
204 )
205 }
206}
207
208impl std::ops::Mul<Float> for Vec3 {
209 type Output = Self;
210
211 fn mul(self, rhs: Float) -> Self {
212 Self::new(self.e[0] * rhs, self.e[1] * rhs, self.e[2] * rhs)
213 }
214}
215
216#[cfg(test)]
217mod test {
218 use super::*;
219
220 #[test]
221 fn test_sample_circle_sq_grid_unit_circle() {
222 let samples = Vec3::sq_grid_in_circ(1.0, 1.0, 0.0, 0.0, 0.0);
223 assert_eq!(samples.len(), 5);
224 }
225
226 #[test]
227 fn test_sample_circle_sq_grid_radius_2_scale_2() {
228 let samples = Vec3::sq_grid_in_circ(2.0, 2.0, 0.0, 0.0, 0.0);
229 assert_eq!(samples.len(), 5);
230 }
231
232 #[test]
233 fn test_sample_circle_sq_grid_radius_2_scale_1() {
234 let samples = Vec3::sq_grid_in_circ(2.0, 1.0, 0.0, 0.0, 0.0);
235 assert_eq!(samples.len(), 13);
236 }
237}