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