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>
106 where
107 F: FnMut(T) -> U,
108 {
109 let Self { x, y, z } = self;
110 Point3d {
111 x: f(x),
112 y: f(y),
113 z: f(z),
114 }
115 }
116}
117
118#[repr(C)]
120#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema)]
121#[serde(rename = "Point4d")]
122#[serde(rename_all = "snake_case")]
123#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
124#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
125pub struct Point4d<T = f32> {
126 #[allow(missing_docs)]
127 pub x: T,
128 #[allow(missing_docs)]
129 pub y: T,
130 #[allow(missing_docs)]
131 pub z: T,
132 #[allow(missing_docs)]
133 pub w: T,
134}
135
136impl std::fmt::Display for Point4d<f64> {
137 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
138 write!(f, "({}, {}, {}, {})", self.x, self.y, self.z, self.w)
139 }
140}
141impl<T> Point4d<T> {
142 pub fn map<U, F>(self, mut f: F) -> Point4d<U>
150 where
151 F: FnMut(T) -> U,
152 {
153 let Self { x, y, z, w } = self;
154 Point4d {
155 x: f(x),
156 y: f(y),
157 z: f(z),
158 w: f(w),
159 }
160 }
161}
162impl<T> Point4d<T>
163where
164 T: Copy,
165{
166 pub const fn uniform_3d(xyz: T, w: T) -> Self {
169 Self {
170 x: xyz,
171 y: xyz,
172 z: xyz,
173 w,
174 }
175 }
176}
177
178pub type Quaternion = Point4d;
180
181impl Default for Quaternion {
182 fn default() -> Self {
184 Self {
185 x: 0.0,
186 y: 0.0,
187 z: 0.0,
188 w: 1.0,
189 }
190 }
191}
192
193impl<T: PartialEq> PartialEq for Point4d<T> {
194 fn eq(&self, other: &Self) -> bool {
195 self.x == other.x && self.y == other.y && self.z == other.z && self.w == other.w
196 }
197}
198
199macro_rules! impl_arithmetic {
200 ($typ:ident, $op:ident, $op_assign:ident, $method:ident, $method_assign:ident, $($i:ident),*) => {
201 impl<T> std::ops::$op<$typ<T>> for $typ<T>
203 where
204 T: std::ops::$op<Output = T>,
205 {
206 type Output = $typ<T>;
207
208 fn $method(self, rhs: $typ<T>) -> Self::Output {
209 Self {
210 $(
211 $i: self.$i.$method(rhs.$i),
212 )*
213 }
214 }
215 }
216 impl<T> std::ops::$op_assign for $typ<T>
218 where
219 T: std::ops::$op_assign<T>,
220 {
221
222 fn $method_assign(&mut self, other: Self) {
223 $(
224 self.$i.$method_assign(other.$i);
225 )*
226 }
227 }
228 };
229}
230
231macro_rules! impl_scalar_arithmetic {
232 ($typ:ident, $op:ident, $op_assign:ident, $method:ident, $method_assign:ident, $($i:ident),*) => {
233 impl<T> std::ops::$op<T> for $typ<T>
235 where
236 T: std::ops::$op<Output = T> + Copy,
237 {
238 type Output = $typ<T>;
239
240 fn $method(self, rhs: T) -> Self::Output {
241 Self {
242 $(
243 $i: self.$i.$method(rhs),
244 )*
245 }
246 }
247 }
248 impl<T> std::ops::$op_assign<T> for $typ<T>
250 where
251 T: std::ops::$op_assign<T> + Copy,
252 {
253
254 fn $method_assign(&mut self, other: T) {
255 $(
256 self.$i.$method_assign(other);
257 )*
258 }
259 }
260 };
261}
262
263impl_arithmetic!(Point2d, Add, AddAssign, add, add_assign, x, y);
264impl_arithmetic!(Point3d, Add, AddAssign, add, add_assign, x, y, z);
265impl_arithmetic!(Point2d, Sub, SubAssign, sub, sub_assign, x, y);
266impl_arithmetic!(Point3d, Sub, SubAssign, sub, sub_assign, x, y, z);
267impl_arithmetic!(Point2d, Mul, MulAssign, mul, mul_assign, x, y);
268impl_arithmetic!(Point3d, Mul, MulAssign, mul, mul_assign, x, y, z);
269impl_arithmetic!(Point2d, Div, DivAssign, div, div_assign, x, y);
270impl_arithmetic!(Point3d, Div, DivAssign, div, div_assign, x, y, z);
271impl_scalar_arithmetic!(Point2d, Mul, MulAssign, mul, mul_assign, x, y);
272impl_scalar_arithmetic!(Point3d, Mul, MulAssign, mul, mul_assign, x, y, z);
273impl_scalar_arithmetic!(Point2d, Div, DivAssign, div, div_assign, x, y);
274impl_scalar_arithmetic!(Point3d, Div, DivAssign, div, div_assign, x, y, z);
275
276#[cfg(test)]
277mod tests {
278 use super::*;
279
280 #[test]
281 fn test_math() {
282 let actual = Point2d { x: 1.0, y: 2.0 } + Point2d { x: 10.0, y: 20.0 };
283 let expected = Point2d { x: 11.0, y: 22.0 };
284 assert_eq!(actual, expected);
285 }
286
287 #[test]
288 fn test_math_assign() {
289 let mut p = Point2d { x: 1.0, y: 2.0 };
290 p += Point2d { x: 10.0, y: 20.0 };
291 let expected = Point2d { x: 11.0, y: 22.0 };
292 assert_eq!(p, expected);
293 }
294
295 #[test]
296 fn test_scaling() {
297 let actual = Point2d { x: 1.0, y: 2.0 } * 3.0;
298 let expected = Point2d { x: 3.0, y: 6.0 };
299 assert_eq!(actual, expected);
300 }
301 #[test]
302 fn test_scaling_assign() {
303 let mut actual = Point2d { x: 1.0, y: 2.0 };
304 actual *= 3.0;
305 let expected = Point2d { x: 3.0, y: 6.0 };
306 assert_eq!(actual, expected);
307 }
308}