1use schemars::JsonSchema;
2use serde::{Deserialize, Serialize};
3
4mod convert;
5mod only;
6mod uniform;
7mod zero;
8
9#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, Default)]
11#[serde(rename = "Point2d")]
12#[serde(rename_all = "snake_case")]
13#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
14#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
15pub struct Point2d<T = f32> {
16 #[allow(missing_docs)]
17 pub x: T,
18 #[allow(missing_docs)]
19 pub y: T,
20}
21
22impl std::fmt::Display for Point2d<f64> {
23 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24 write!(f, "({}, {})", self.x, self.y)
25 }
26}
27
28impl<T: PartialEq> PartialEq for Point2d<T> {
29 fn eq(&self, other: &Self) -> bool {
30 self.x == other.x && self.y == other.y
31 }
32}
33
34impl<T> Point2d<T> {
35 pub fn with_z(self, z: T) -> Point3d<T> {
37 let Self { x, y } = self;
38 Point3d { x, y, z }
39 }
40
41 pub fn map<U, F>(self, mut f: F) -> Point2d<U>
49 where
50 F: FnMut(T) -> U,
51 {
52 let Self { x, y } = self;
53 Point2d { x: f(x), y: f(y) }
54 }
55}
56
57#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq, Default)]
59#[serde(rename = "Point3d")]
60#[serde(rename_all = "snake_case")]
61#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
62#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
63pub struct Point3d<T = f32> {
64 #[allow(missing_docs)]
65 pub x: T,
66 #[allow(missing_docs)]
67 pub y: T,
68 #[allow(missing_docs)]
69 pub z: T,
70}
71
72impl std::fmt::Display for Point3d<f64> {
73 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
74 write!(f, "({}, {}, {})", self.x, self.y, self.z)
75 }
76}
77
78impl From<euler::Vec3> for Point3d<f32> {
79 fn from(v: euler::Vec3) -> Self {
80 Self { x: v.x, y: v.y, z: v.z }
81 }
82}
83
84impl<T> Point3d<T> {
85 pub fn from_2d(Point2d { x, y }: Point2d<T>, z: T) -> Self {
87 Self { x, y, z }
88 }
89
90 pub fn with_w(self, w: T) -> Point4d<T> {
92 let Self { x, y, z } = self;
93 Point4d { x, y, z, w }
94 }
95
96 pub fn map<U, F>(self, mut f: F) -> Point3d<U>
104 where
105 F: FnMut(T) -> U,
106 {
107 let Self { x, y, z } = self;
108 Point3d {
109 x: f(x),
110 y: f(y),
111 z: f(z),
112 }
113 }
114}
115
116#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema)]
118#[serde(rename = "Point4d")]
119#[serde(rename_all = "snake_case")]
120#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
121#[cfg_attr(feature = "ts-rs", ts(export_to = "ModelingCmd.ts"))]
122pub struct Point4d<T = f32> {
123 #[allow(missing_docs)]
124 pub x: T,
125 #[allow(missing_docs)]
126 pub y: T,
127 #[allow(missing_docs)]
128 pub z: T,
129 #[allow(missing_docs)]
130 pub w: T,
131}
132
133impl std::fmt::Display for Point4d<f64> {
134 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
135 write!(f, "({}, {}, {}, {})", self.x, self.y, self.z, self.w)
136 }
137}
138impl<T> Point4d<T> {
139 pub fn map<U, F>(self, mut f: F) -> Point4d<U>
147 where
148 F: FnMut(T) -> U,
149 {
150 let Self { x, y, z, w } = self;
151 Point4d {
152 x: f(x),
153 y: f(y),
154 z: f(z),
155 w: f(w),
156 }
157 }
158}
159impl<T> Point4d<T>
160where
161 T: Copy,
162{
163 pub const fn uniform_3d(xyz: T, w: T) -> Self {
166 Self {
167 x: xyz,
168 y: xyz,
169 z: xyz,
170 w,
171 }
172 }
173}
174
175pub type Quaternion = Point4d;
177
178impl Default for Quaternion {
179 fn default() -> Self {
181 Self {
182 x: 0.0,
183 y: 0.0,
184 z: 0.0,
185 w: 1.0,
186 }
187 }
188}
189
190impl<T: PartialEq> PartialEq for Point4d<T> {
191 fn eq(&self, other: &Self) -> bool {
192 self.x == other.x && self.y == other.y && self.z == other.z && self.w == other.w
193 }
194}
195
196macro_rules! impl_arithmetic {
197 ($typ:ident, $op:ident, $op_assign:ident, $method:ident, $method_assign:ident, $($i:ident),*) => {
198 impl<T> std::ops::$op<$typ<T>> for $typ<T>
200 where
201 T: std::ops::$op<Output = T>,
202 {
203 type Output = $typ<T>;
204
205 fn $method(self, rhs: $typ<T>) -> Self::Output {
206 Self {
207 $(
208 $i: self.$i.$method(rhs.$i),
209 )*
210 }
211 }
212 }
213 impl<T> std::ops::$op_assign for $typ<T>
215 where
216 T: std::ops::$op_assign<T>,
217 {
218
219 fn $method_assign(&mut self, other: Self) {
220 $(
221 self.$i.$method_assign(other.$i);
222 )*
223 }
224 }
225 };
226}
227
228macro_rules! impl_scalar_arithmetic {
229 ($typ:ident, $op:ident, $op_assign:ident, $method:ident, $method_assign:ident, $($i:ident),*) => {
230 impl<T> std::ops::$op<T> for $typ<T>
232 where
233 T: std::ops::$op<Output = T> + Copy,
234 {
235 type Output = $typ<T>;
236
237 fn $method(self, rhs: T) -> Self::Output {
238 Self {
239 $(
240 $i: self.$i.$method(rhs),
241 )*
242 }
243 }
244 }
245 impl<T> std::ops::$op_assign<T> for $typ<T>
247 where
248 T: std::ops::$op_assign<T> + Copy,
249 {
250
251 fn $method_assign(&mut self, other: T) {
252 $(
253 self.$i.$method_assign(other);
254 )*
255 }
256 }
257 };
258}
259
260impl_arithmetic!(Point2d, Add, AddAssign, add, add_assign, x, y);
261impl_arithmetic!(Point3d, Add, AddAssign, add, add_assign, x, y, z);
262impl_arithmetic!(Point2d, Sub, SubAssign, sub, sub_assign, x, y);
263impl_arithmetic!(Point3d, Sub, SubAssign, sub, sub_assign, x, y, z);
264impl_arithmetic!(Point2d, Mul, MulAssign, mul, mul_assign, x, y);
265impl_arithmetic!(Point3d, Mul, MulAssign, mul, mul_assign, x, y, z);
266impl_arithmetic!(Point2d, Div, DivAssign, div, div_assign, x, y);
267impl_arithmetic!(Point3d, Div, DivAssign, div, div_assign, x, y, z);
268impl_scalar_arithmetic!(Point2d, Mul, MulAssign, mul, mul_assign, x, y);
269impl_scalar_arithmetic!(Point3d, Mul, MulAssign, mul, mul_assign, x, y, z);
270impl_scalar_arithmetic!(Point2d, Div, DivAssign, div, div_assign, x, y);
271impl_scalar_arithmetic!(Point3d, Div, DivAssign, div, div_assign, x, y, z);
272
273#[cfg(test)]
274mod tests {
275 use super::*;
276
277 #[test]
278 fn test_math() {
279 let actual = Point2d { x: 1.0, y: 2.0 } + Point2d { x: 10.0, y: 20.0 };
280 let expected = Point2d { x: 11.0, y: 22.0 };
281 assert_eq!(actual, expected);
282 }
283
284 #[test]
285 fn test_math_assign() {
286 let mut p = Point2d { x: 1.0, y: 2.0 };
287 p += Point2d { x: 10.0, y: 20.0 };
288 let expected = Point2d { x: 11.0, y: 22.0 };
289 assert_eq!(p, expected);
290 }
291
292 #[test]
293 fn test_scaling() {
294 let actual = Point2d { x: 1.0, y: 2.0 } * 3.0;
295 let expected = Point2d { x: 3.0, y: 6.0 };
296 assert_eq!(actual, expected);
297 }
298 #[test]
299 fn test_scaling_assign() {
300 let mut actual = Point2d { x: 1.0, y: 2.0 };
301 actual *= 3.0;
302 let expected = Point2d { x: 3.0, y: 6.0 };
303 assert_eq!(actual, expected);
304 }
305}