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