1use num_complex::Complex32;
37use num_traits::AsPrimitive;
38use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
39use tiny_skia::Point;
40
41pub use std::f32::consts::FRAC_PI_2 as HALF_PI;
42pub use std::f32::consts::PI;
43pub use std::f32::consts::TAU;
44
45pub fn pt<S, T>(x: S, y: T) -> Point
47where
48 S: AsPrimitive<f32>,
49 T: AsPrimitive<f32>,
50{
51 Point::from_xy(x.as_(), y.as_())
52}
53
54pub fn pt3<S, T, U>(x: S, y: T, z: U) -> Point3
55where
56 S: AsPrimitive<f32>,
57 T: AsPrimitive<f32>,
58 U: AsPrimitive<f32>,
59{
60 Point3 {
61 x: x.as_(),
62 y: y.as_(),
63 z: z.as_(),
64 }
65}
66
67pub fn polar<S, T>(theta: S, r: T) -> Point
68where
69 S: AsPrimitive<f32>,
70 T: AsPrimitive<f32>,
71{
72 Point::from_xy(r.as_() * theta.as_().cos(), r.as_() * theta.as_().sin())
73}
74
75pub fn complex(p: Point) -> Complex32 {
76 Complex32::new(p.x, p.y)
77}
78
79pub fn center<S, T>(width: S, height: T) -> Point
80where
81 S: AsPrimitive<f32>,
82 T: AsPrimitive<f32>,
83{
84 Point::from_xy(width.as_() / 2.0, height.as_() / 2.0)
85}
86
87pub trait Algebra: Copy {
89 const ZERO: Self;
90
91 fn scale(self, k: f32) -> Self;
93
94 fn lerp(self, other: Self, t: f32) -> Self;
96
97 fn mag2(self) -> f32;
99
100 fn dist2(self, other: Self) -> f32;
102
103 fn dot(self, other: Self) -> f32;
105
106 fn mag(self) -> f32 {
108 self.mag2().sqrt()
109 }
110
111 fn normalize(self) -> Self {
113 self.scale(1.0 / self.mag())
114 }
115
116 fn average(self, other: Self) -> Self {
118 self.lerp(other, 0.5)
119 }
120
121 fn dist(self, other: Self) -> f32 {
123 self.dist2(other).sqrt()
124 }
125}
126
127impl Algebra for Point {
128 const ZERO: Self = Point { x: 0.0, y: 0.0 };
129
130 fn mag2(self) -> f32 {
131 self.x * self.x + self.y * self.y
132 }
133
134 fn scale(self, k: f32) -> Self {
135 Point::from_xy(k * self.x, k * self.y)
136 }
137
138 fn lerp(self, other: Self, t: f32) -> Self {
139 let x = self.x * (1.0 - t) + t * other.x;
140 let y = self.y * (1.0 - t) + t * other.y;
141 Self::from_xy(x, y)
142 }
143
144 fn dist2(self, other: Self) -> f32 {
145 pt(self.x - other.x, self.y - other.y).mag2()
146 }
147
148 fn dot(self, other: Self) -> f32 {
149 self.x * other.x + self.y * other.y
150 }
151}
152
153#[derive(Clone, Copy, Debug)]
155pub struct Spherical {
156 pub phi: f32,
157 pub theta: f32,
158 pub radius: f32,
159}
160
161impl Spherical {
162 pub fn new(phi: f32, theta: f32, radius: f32) -> Self {
163 Self { phi, theta, radius }
164 }
165}
166
167#[derive(Clone, Copy, Debug)]
169pub struct Point3 {
170 pub x: f32,
171 pub y: f32,
172 pub z: f32,
173}
174
175impl Algebra for Point3 {
176 const ZERO: Self = Point3 {
177 x: 0.0,
178 y: 0.0,
179 z: 0.0,
180 };
181
182 fn scale(self, k: f32) -> Self {
183 self * k
184 }
185
186 fn lerp(self, other: Self, t: f32) -> Self {
187 let x = self.x * (1.0 - t) + t * other.x;
188 let y = self.y * (1.0 - t) + t * other.y;
189 let z = self.z * (1.0 - t) + t * other.z;
190 Point3 { x, y, z }
191 }
192
193 fn mag2(self) -> f32 {
194 self.dot(self)
195 }
196
197 fn dist2(self, other: Self) -> f32 {
198 pt3(self.x - other.x, self.y - other.y, self.z - other.z).mag2()
199 }
200
201 fn dot(self, other: Self) -> f32 {
202 self.x * other.x + self.y * other.y + self.z * other.z
203 }
204}
205
206impl Point3 {
207 pub fn new(x: f32, y: f32, z: f32) -> Self {
208 Self { x, y, z }
209 }
210
211 pub fn to_spherical(&self, center: Point3) -> Spherical {
213 let x = self.x - center.x;
214 let y = self.y - center.y;
215 let z = self.z - center.z;
216 let radius = (x * x + y * y + z * z).sqrt();
217 let theta = (z / radius).acos();
218 let phi = y.atan2(x);
219 Spherical { phi, theta, radius }
220 }
221
222 pub fn rotate_x(&self, theta: f32) -> Self {
224 let x = self.x;
225 let y = self.y * theta.cos() - self.z * theta.sin();
226 let z = self.y * theta.sin() + self.z * theta.cos();
227 Self { x, y, z }
228 }
229
230 pub fn rotate_y(&self, theta: f32) -> Self {
232 let x = self.x * theta.cos() + self.z * theta.sin();
233 let y = self.y;
234 let z = -self.x * theta.sin() + self.z * theta.cos();
235 Self { x, y, z }
236 }
237
238 pub fn rotate_z(&self, theta: f32) -> Self {
240 let x = self.x * theta.cos() - self.y * theta.sin();
241 let y = self.x * theta.sin() + self.y * theta.cos();
242 let z = self.z;
243 Self { x, y, z }
244 }
245}
246
247impl Sub for Point3 {
248 type Output = Point3;
249
250 fn sub(self, rhs: Self) -> Self::Output {
251 Point3::new(self.x - rhs.x, self.y - rhs.y, self.z - rhs.z)
252 }
253}
254
255impl SubAssign for Point3 {
256 fn sub_assign(&mut self, rhs: Self) {
257 *self = *self - rhs;
258 }
259}
260
261impl Add for Point3 {
262 type Output = Point3;
263
264 fn add(self, rhs: Self) -> Self::Output {
265 Point3::new(self.x + rhs.x, self.y + rhs.y, self.z + rhs.z)
266 }
267}
268
269impl AddAssign for Point3 {
270 fn add_assign(&mut self, rhs: Self) {
271 *self = *self + rhs;
272 }
273}
274
275impl Mul<f32> for Point3 {
276 type Output = Point3;
277
278 fn mul(self, rhs: f32) -> Self::Output {
279 Point3::new(self.x * rhs, self.y * rhs, self.z * rhs)
280 }
281}
282
283impl MulAssign<f32> for Point3 {
284 fn mul_assign(&mut self, rhs: f32) {
285 *self = *self * rhs;
286 }
287}
288
289impl Div<f32> for Point3 {
290 type Output = Point3;
291
292 fn div(self, rhs: f32) -> Self::Output {
293 Point3::new(self.x / rhs, self.y / rhs, self.z / rhs)
294 }
295}
296
297impl DivAssign<f32> for Point3 {
298 fn div_assign(&mut self, rhs: f32) {
299 *self = *self / rhs;
300 }
301}
302
303impl Mul<Point3> for f32 {
304 type Output = Point3;
305
306 fn mul(self, rhs: Point3) -> Self::Output {
307 rhs * self
308 }
309}
310
311impl Div<Point3> for f32 {
312 type Output = Point3;
313
314 fn div(self, rhs: Point3) -> Self::Output {
315 rhs / self
316 }
317}