1use facet::{ConstTypeId, Facet};
9use strum::IntoDiscriminant;
10
11use fidget_core::context::Tree;
12
13#[derive(thiserror::Error, Debug)]
15pub enum Error {
16 #[error("vector is too short to convert to an axis (length: {0})")]
18 TooShort(f64),
19
20 #[error("vector is too long to convert to an axis (length: {0})")]
22 TooLong(f64),
23
24 #[error("could not normalize vector due to an invalid length")]
26 BadLength,
27
28 #[error("wrong type; expected {expected}, got {actual}")]
30 WrongType {
31 expected: Type,
33 actual: Type,
35 },
36}
37
38#[derive(Copy, Clone, Debug, PartialEq, Facet)]
40#[allow(missing_docs)]
41pub struct Vec2 {
42 pub x: f64,
43 pub y: f64,
44}
45
46impl From<nalgebra::Vector2<f64>> for Vec2 {
47 fn from(value: nalgebra::Vector2<f64>) -> Self {
48 Self {
49 x: value.x,
50 y: value.y,
51 }
52 }
53}
54
55impl From<Vec2> for nalgebra::Vector2<f64> {
56 fn from(value: Vec2) -> Self {
57 Self::new(value.x, value.y)
58 }
59}
60
61impl From<f64> for Vec2 {
62 fn from(value: f64) -> Self {
63 Self { x: value, y: value }
64 }
65}
66
67impl Vec2 {
68 pub fn new(x: f64, y: f64) -> Self {
70 Self { x, y }
71 }
72 pub fn norm(&self) -> f64 {
74 (self.x.powi(2) + self.y.powi(2)).sqrt()
75 }
76 fn combine<F: Fn(f64, f64) -> f64>(self, rhs: Self, f: F) -> Self {
77 Self {
78 x: f(self.x, rhs.x),
79 y: f(self.y, rhs.y),
80 }
81 }
82 fn map<F: Fn(f64) -> f64>(self, f: F) -> Self {
83 Self {
84 x: f(self.x),
85 y: f(self.y),
86 }
87 }
88}
89
90#[derive(Copy, Clone, Debug, PartialEq, Facet)]
94#[allow(missing_docs)]
95pub struct Vec3 {
96 pub x: f64,
97 pub y: f64,
98 pub z: f64,
99}
100
101impl From<nalgebra::Vector3<f64>> for Vec3 {
102 fn from(value: nalgebra::Vector3<f64>) -> Self {
103 Self {
104 x: value.x,
105 y: value.y,
106 z: value.z,
107 }
108 }
109}
110
111impl From<Vec3> for nalgebra::Vector3<f64> {
112 fn from(value: Vec3) -> Self {
113 Self::new(value.x, value.y, value.z)
114 }
115}
116
117impl From<f64> for Vec3 {
118 fn from(value: f64) -> Self {
119 Self {
120 x: value,
121 y: value,
122 z: value,
123 }
124 }
125}
126
127impl Vec3 {
128 pub fn new(x: f64, y: f64, z: f64) -> Self {
130 Self { x, y, z }
131 }
132 pub fn norm(&self) -> f64 {
134 (self.x.powi(2) + self.y.powi(2) + self.z.powi(2)).sqrt()
135 }
136 fn combine<F: Fn(f64, f64) -> f64>(self, rhs: Self, f: F) -> Self {
137 Self {
138 x: f(self.x, rhs.x),
139 y: f(self.y, rhs.y),
140 z: f(self.z, rhs.z),
141 }
142 }
143 fn map<F: Fn(f64) -> f64>(self, f: F) -> Self {
144 Self {
145 x: f(self.x),
146 y: f(self.y),
147 z: f(self.z),
148 }
149 }
150}
151
152#[derive(Copy, Clone, Debug, PartialEq, Facet)]
156#[allow(missing_docs)]
157pub struct Vec4 {
158 pub x: f64,
159 pub y: f64,
160 pub z: f64,
161 pub w: f64,
162}
163
164impl From<nalgebra::Vector4<f64>> for Vec4 {
165 fn from(value: nalgebra::Vector4<f64>) -> Self {
166 Self {
167 x: value.x,
168 y: value.y,
169 z: value.z,
170 w: value.w,
171 }
172 }
173}
174
175impl From<Vec4> for nalgebra::Vector4<f64> {
176 fn from(value: Vec4) -> Self {
177 Self::new(value.x, value.y, value.z, value.w)
178 }
179}
180
181impl From<f64> for Vec4 {
182 fn from(value: f64) -> Self {
183 Self {
184 x: value,
185 y: value,
186 z: value,
187 w: value,
188 }
189 }
190}
191
192impl Vec4 {
193 fn combine<F: Fn(f64, f64) -> f64>(self, rhs: Self, f: F) -> Self {
194 Self {
195 x: f(self.x, rhs.x),
196 y: f(self.y, rhs.y),
197 z: f(self.z, rhs.z),
198 w: f(self.w, rhs.w),
199 }
200 }
201 fn map<F: Fn(f64) -> f64>(self, f: F) -> Self {
202 Self {
203 x: f(self.x),
204 y: f(self.y),
205 z: f(self.z),
206 w: f(self.w),
207 }
208 }
209}
210
211macro_rules! impl_binary {
214 ($ty:ident, $op:ident, $base_fn:ident) => {
215 impl std::ops::$op<$ty> for $ty {
216 type Output = $ty;
217
218 fn $base_fn(self, rhs: $ty) -> Self {
219 self.combine(rhs, |a, b| a.$base_fn(b))
220 }
221 }
222 impl std::ops::$op<$ty> for f64 {
223 type Output = $ty;
224 fn $base_fn(self, rhs: $ty) -> $ty {
225 $ty::from(self).$base_fn(rhs)
226 }
227 }
228 impl std::ops::$op<f64> for $ty {
229 type Output = $ty;
230 fn $base_fn(self, rhs: f64) -> $ty {
231 self.$base_fn($ty::from(rhs))
232 }
233 }
234 };
235 ($ty:ident, $base_fn:ident, $f:expr) => {
236 pub fn $base_fn<R>(self, rhs: R) -> Self
237 where
238 $ty: From<R>,
239 {
240 self.combine($ty::from(rhs), $f)
241 }
242 };
243 ($ty:ident, $base_fn:ident) => {
244 impl_binary!($ty, $base_fn, |a, b| a.$base_fn(b));
245 };
246}
247
248macro_rules! impl_unary {
249 ($ty:ident, $op:ident, $base_fn:ident) => {
250 impl std::ops::$op for $ty {
251 type Output = $ty;
252 fn $base_fn(self) -> $ty {
253 self.map(std::ops::$op::$base_fn)
254 }
255 }
256 };
257 ($ty:ident, $base_fn:ident, $f:expr) => {
258 pub fn $base_fn(self) -> Self {
259 self.map($f)
260 }
261 };
262 ($ty:ident, $base_fn:ident) => {
263 impl_unary!($ty, $base_fn, |a| a.$base_fn());
264 };
265}
266
267macro_rules! impl_all {
268 ($ty:ident) => {
269 impl_binary!($ty, Add, add);
270 impl_binary!($ty, Mul, mul);
271 impl_binary!($ty, Sub, sub);
272 impl_binary!($ty, Div, div);
273 impl_unary!($ty, Neg, neg);
274
275 #[allow(missing_docs)]
276 impl $ty {
277 impl_binary!($ty, min);
278 impl_binary!($ty, max);
279 impl_unary!($ty, sqrt);
280 impl_unary!($ty, abs);
281 }
282 };
283}
284
285impl_all!(Vec2);
286impl_all!(Vec3);
287impl_all!(Vec4);
288
289#[derive(Copy, Clone, Debug, PartialEq, Facet)]
293pub struct Axis(Vec3);
294
295impl TryFrom<Vec3> for Axis {
296 type Error = Error;
297 fn try_from(value: Vec3) -> Result<Self, Self::Error> {
298 let norm = value.norm();
299 if norm.is_nan() {
300 Err(Error::BadLength)
301 } else if norm < 1e-8 {
302 Err(Error::TooShort(norm))
303 } else if norm > 1e8 {
304 Err(Error::TooLong(norm))
305 } else {
306 Ok(Self(value / norm))
307 }
308 }
309}
310
311impl Axis {
312 pub fn vec(&self) -> &Vec3 {
314 &self.0
315 }
316 pub const X: Self = Axis(Vec3 {
318 x: 1.0,
319 y: 0.0,
320 z: 0.0,
321 });
322 pub const Y: Self = Axis(Vec3 {
324 x: 0.0,
325 y: 1.0,
326 z: 0.0,
327 });
328 pub const Z: Self = Axis(Vec3 {
330 x: 0.0,
331 y: 0.0,
332 z: 1.0,
333 });
334}
335
336#[derive(Copy, Clone, Debug, PartialEq, Facet)]
338pub struct Plane {
339 pub axis: Axis,
341 pub offset: f64,
343}
344
345impl Plane {
346 pub const XY: Self = Plane {
348 axis: Axis::Y,
349 offset: 0.0,
350 };
351 pub const YZ: Self = Plane {
353 axis: Axis::X,
354 offset: 0.0,
355 };
356 pub const ZX: Self = Plane {
358 axis: Axis::Y,
359 offset: 0.0,
360 };
361}
362
363impl From<Plane> for Tree {
364 fn from(v: Plane) -> Self {
365 let (x, y, z) = Tree::axes();
366 let a = v.axis.vec();
367 x * a.x + y * a.y + z * a.z - v.offset
368 }
369}
370
371#[derive(Debug, strum::EnumDiscriminants)]
375#[strum_discriminants(name(Type), derive(enum_map::Enum), allow(missing_docs))]
376#[allow(missing_docs)]
377pub enum Value {
378 Float(f64),
379 Vec2(Vec2),
380 Vec3(Vec3),
381 Vec4(Vec4),
382 Axis(Axis),
383 Plane(Plane),
384 Tree(Tree),
385 VecTree(Vec<Tree>),
386}
387
388impl Value {
389 pub fn put<'facet>(self, builder: &mut facet::Partial<'facet>, i: usize) {
394 match self {
395 Value::Float(v) => builder.set_nth_field(i, v),
396 Value::Vec2(v) => builder.set_nth_field(i, v),
397 Value::Vec3(v) => builder.set_nth_field(i, v),
398 Value::Vec4(v) => builder.set_nth_field(i, v),
399 Value::Axis(v) => builder.set_nth_field(i, v),
400 Value::Plane(v) => builder.set_nth_field(i, v),
401 Value::Tree(v) => builder.set_nth_field(i, v),
402 Value::VecTree(v) => builder.set_nth_field(i, v),
403 }
404 .unwrap();
405 }
406}
407
408macro_rules! try_from_type {
409 ($ty:ty, $name:ident) => {
410 impl<'a> TryFrom<&'a Value> for &'a $ty {
411 type Error = $crate::types::Error;
412 fn try_from(v: &'a Value) -> Result<&'a $ty, Self::Error> {
413 if let Value::$name(f) = v {
414 Ok(f)
415 } else {
416 Err(Self::Error::WrongType {
417 expected: Type::$name,
418 actual: v.discriminant(),
419 })
420 }
421 }
422 }
423 };
424 ($ty:ident) => {
425 try_from_type!($ty, $ty);
426 };
427}
428
429try_from_type!(f64, Float);
430try_from_type!(Vec2);
431try_from_type!(Vec3);
432try_from_type!(Vec4);
433try_from_type!(Tree);
434try_from_type!(Plane);
435try_from_type!(Axis);
436try_from_type!(Vec<Tree>, VecTree);
437
438impl std::fmt::Display for Type {
439 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
440 let s = match self {
441 Type::Float => "f64",
442 Type::Vec2 => "Vec2",
443 Type::Vec3 => "Vec3",
444 Type::Vec4 => "Vec4",
445 Type::Axis => "Axis",
446 Type::Plane => "Plane",
447 Type::Tree => "Tree",
448 Type::VecTree => "Vec<Tree>",
449 };
450 write!(f, "{s}")
451 }
452}
453
454impl TryFrom<facet::ConstTypeId> for Type {
456 type Error = facet::ConstTypeId;
457 fn try_from(t: facet::ConstTypeId) -> Result<Self, Self::Error> {
458 if t == ConstTypeId::of::<f64>() {
459 Ok(Self::Float)
460 } else if t == ConstTypeId::of::<Vec2>() {
461 Ok(Self::Vec2)
462 } else if t == ConstTypeId::of::<Vec3>() {
463 Ok(Self::Vec3)
464 } else if t == ConstTypeId::of::<Vec4>() {
465 Ok(Self::Vec4)
466 } else if t == ConstTypeId::of::<Axis>() {
467 Ok(Self::Axis)
468 } else if t == ConstTypeId::of::<Plane>() {
469 Ok(Self::Plane)
470 } else if t == ConstTypeId::of::<Tree>() {
471 Ok(Self::Tree)
472 } else if t == ConstTypeId::of::<Vec<Tree>>() {
473 Ok(Self::VecTree)
474 } else {
475 Err(t)
476 }
477 }
478}
479
480impl Type {
481 pub unsafe fn build_from_default_fn(
486 &self,
487 f: unsafe fn(facet::PtrUninit) -> facet::PtrMut,
488 ) -> Value {
489 unsafe {
490 match self {
491 Type::Float => Value::Float(eval_default_fn(f)),
492 Type::Vec2 => Value::Vec2(eval_default_fn(f)),
493 Type::Vec3 => Value::Vec3(eval_default_fn(f)),
494 Type::Vec4 => Value::Vec4(eval_default_fn(f)),
495 Type::Axis => Value::Axis(eval_default_fn(f)),
496 Type::Plane => Value::Plane(eval_default_fn(f)),
497 Type::Tree => Value::Tree(eval_default_fn(f)),
498 Type::VecTree => Value::VecTree(eval_default_fn(f)),
499 }
500 }
501 }
502}
503
504pub unsafe fn eval_default_fn<T>(
509 f: unsafe fn(facet::PtrUninit) -> facet::PtrMut,
510) -> T {
511 let mut v = std::mem::MaybeUninit::<T>::uninit();
512 let ptr = facet::PtrUninit::new(&mut v);
513 unsafe { f(ptr) };
515 unsafe { v.assume_init() }
517}