1use schemars::JsonSchema;
2use serde::{Deserialize, Serialize};
3
4mod convert;
5mod only;
6mod uniform;
7mod zero;
8
9#[repr(C)]
11#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, Default)]
12#[serde(rename = "Point2d")]
13#[serde(rename_all = "snake_case")]
14#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
15#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
16#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
17pub struct Point2d<T = f32> {
18 #[allow(missing_docs)]
19 pub x: T,
20 #[allow(missing_docs)]
21 pub y: T,
22}
23
24impl std::fmt::Display for Point2d<f64> {
25 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26 write!(f, "({}, {})", self.x, self.y)
27 }
28}
29
30impl<T: PartialEq> PartialEq for Point2d<T> {
31 fn eq(&self, other: &Self) -> bool {
32 self.x == other.x && self.y == other.y
33 }
34}
35
36impl<T> Point2d<T> {
37 pub fn with_z(self, z: T) -> Point3d<T> {
39 let Self { x, y } = self;
40 Point3d { x, y, z }
41 }
42
43 pub fn map<U, F>(self, mut f: F) -> Point2d<U>
51 where
52 F: FnMut(T) -> U,
53 {
54 let Self { x, y } = self;
55 Point2d { x: f(x), y: f(y) }
56 }
57}
58
59#[repr(C)]
61#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq, Default)]
62#[serde(rename = "Point3d")]
63#[serde(rename_all = "snake_case")]
64#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
65#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
66#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
67pub struct Point3d<T = f32> {
68 #[allow(missing_docs)]
69 pub x: T,
70 #[allow(missing_docs)]
71 pub y: T,
72 #[allow(missing_docs)]
73 pub z: T,
74}
75
76impl std::fmt::Display for Point3d<f64> {
77 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78 write!(f, "({}, {}, {})", self.x, self.y, self.z)
79 }
80}
81
82impl From<euler::Vec3> for Point3d<f32> {
83 fn from(v: euler::Vec3) -> Self {
84 Self { x: v.x, y: v.y, z: v.z }
85 }
86}
87
88impl<T> Point3d<T> {
89 pub fn from_2d(Point2d { x, y }: Point2d<T>, z: T) -> Self {
91 Self { x, y, z }
92 }
93
94 pub fn with_w(self, w: T) -> Point4d<T> {
96 let Self { x, y, z } = self;
97 Point4d { x, y, z, w }
98 }
99
100 pub fn map<U, F>(self, mut f: F) -> Point3d<U>
119 where
120 F: FnMut(T) -> U,
121 {
122 let Self { x, y, z } = self;
123 Point3d {
124 x: f(x),
125 y: f(y),
126 z: f(z),
127 }
128 }
129}
130
131#[repr(C)]
133#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema)]
134#[serde(rename = "Point4d")]
135#[serde(rename_all = "snake_case")]
136#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
137#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
138#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
139pub struct Point4d<T = f32> {
140 #[allow(missing_docs)]
141 pub x: T,
142 #[allow(missing_docs)]
143 pub y: T,
144 #[allow(missing_docs)]
145 pub z: T,
146 #[allow(missing_docs)]
147 pub w: T,
148}
149
150impl std::fmt::Display for Point4d<f64> {
151 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
152 write!(f, "({}, {}, {}, {})", self.x, self.y, self.z, self.w)
153 }
154}
155impl<T> Point4d<T> {
156 pub fn map<U, F>(self, mut f: F) -> Point4d<U>
177 where
178 F: FnMut(T) -> U,
179 {
180 let Self { x, y, z, w } = self;
181 Point4d {
182 x: f(x),
183 y: f(y),
184 z: f(z),
185 w: f(w),
186 }
187 }
188}
189impl<T> Point4d<T>
190where
191 T: Copy,
192{
193 pub const fn uniform_3d(xyz: T, w: T) -> Self {
196 Self {
197 x: xyz,
198 y: xyz,
199 z: xyz,
200 w,
201 }
202 }
203}
204
205pub type Quaternion = Point4d;
207
208impl Default for Quaternion {
209 fn default() -> Self {
211 Self {
212 x: 0.0,
213 y: 0.0,
214 z: 0.0,
215 w: 1.0,
216 }
217 }
218}
219
220impl<T: PartialEq> PartialEq for Point4d<T> {
221 fn eq(&self, other: &Self) -> bool {
222 self.x == other.x && self.y == other.y && self.z == other.z && self.w == other.w
223 }
224}
225
226macro_rules! impl_arithmetic {
227 ($typ:ident, $op:ident, $op_assign:ident, $method:ident, $method_assign:ident, $($i:ident),*) => {
228 impl<T> std::ops::$op<$typ<T>> for $typ<T>
230 where
231 T: std::ops::$op<Output = T>,
232 {
233 type Output = $typ<T>;
234
235 fn $method(self, rhs: $typ<T>) -> Self::Output {
236 Self {
237 $(
238 $i: self.$i.$method(rhs.$i),
239 )*
240 }
241 }
242 }
243 impl<T> std::ops::$op_assign for $typ<T>
245 where
246 T: std::ops::$op_assign<T>,
247 {
248
249 fn $method_assign(&mut self, other: Self) {
250 $(
251 self.$i.$method_assign(other.$i);
252 )*
253 }
254 }
255 };
256}
257
258macro_rules! impl_scalar_arithmetic {
259 ($typ:ident, $op:ident, $op_assign:ident, $method:ident, $method_assign:ident, $($i:ident),*) => {
260 impl<T> std::ops::$op<T> for $typ<T>
262 where
263 T: std::ops::$op<Output = T> + Copy,
264 {
265 type Output = $typ<T>;
266
267 fn $method(self, rhs: T) -> Self::Output {
268 Self {
269 $(
270 $i: self.$i.$method(rhs),
271 )*
272 }
273 }
274 }
275 impl<T> std::ops::$op_assign<T> for $typ<T>
277 where
278 T: std::ops::$op_assign<T> + Copy,
279 {
280
281 fn $method_assign(&mut self, other: T) {
282 $(
283 self.$i.$method_assign(other);
284 )*
285 }
286 }
287 };
288}
289
290impl_arithmetic!(Point2d, Add, AddAssign, add, add_assign, x, y);
291impl_arithmetic!(Point3d, Add, AddAssign, add, add_assign, x, y, z);
292impl_arithmetic!(Point2d, Sub, SubAssign, sub, sub_assign, x, y);
293impl_arithmetic!(Point3d, Sub, SubAssign, sub, sub_assign, x, y, z);
294impl_arithmetic!(Point2d, Mul, MulAssign, mul, mul_assign, x, y);
295impl_arithmetic!(Point3d, Mul, MulAssign, mul, mul_assign, x, y, z);
296impl_arithmetic!(Point2d, Div, DivAssign, div, div_assign, x, y);
297impl_arithmetic!(Point3d, Div, DivAssign, div, div_assign, x, y, z);
298impl_scalar_arithmetic!(Point2d, Mul, MulAssign, mul, mul_assign, x, y);
299impl_scalar_arithmetic!(Point3d, Mul, MulAssign, mul, mul_assign, x, y, z);
300impl_scalar_arithmetic!(Point2d, Div, DivAssign, div, div_assign, x, y);
301impl_scalar_arithmetic!(Point3d, Div, DivAssign, div, div_assign, x, y, z);
302
303#[cfg(test)]
304mod tests {
305 use super::*;
306
307 #[test]
308 fn test_math() {
309 let actual = Point2d { x: 1.0, y: 2.0 } + Point2d { x: 10.0, y: 20.0 };
310 let expected = Point2d { x: 11.0, y: 22.0 };
311 assert_eq!(actual, expected);
312 }
313
314 #[test]
315 fn test_math_assign() {
316 let mut p = Point2d { x: 1.0, y: 2.0 };
317 p += Point2d { x: 10.0, y: 20.0 };
318 let expected = Point2d { x: 11.0, y: 22.0 };
319 assert_eq!(p, expected);
320 }
321
322 #[test]
323 fn test_scaling() {
324 let actual = Point2d { x: 1.0, y: 2.0 } * 3.0;
325 let expected = Point2d { x: 3.0, y: 6.0 };
326 assert_eq!(actual, expected);
327 }
328 #[test]
329 fn test_scaling_assign() {
330 let mut actual = Point2d { x: 1.0, y: 2.0 };
331 actual *= 3.0;
332 let expected = Point2d { x: 3.0, y: 6.0 };
333 assert_eq!(actual, expected);
334 }
335}