all_is_cubes_base/math/
coord.rs

1//! Numeric types used for coordinates and related quantities.
2
3use euclid::{Box3D, Point3D, Size2D, Size3D, Vector3D};
4
5use crate::math::Cube;
6
7/// Coordinates that are locked to the cube grid.
8pub type GridCoordinate = i32;
9
10/// Numeric type in a [`GridSize`].
11///
12/// TODO: This needs a cleaner name.
13pub type GridSizeCoord = u32;
14
15/// Positions that are locked to the cube grid.
16pub type GridPoint = Point3D<GridCoordinate, Cube>;
17
18/// Vectors that are locked to the cube grid.
19pub type GridVector = Vector3D<GridCoordinate, Cube>;
20
21/// Sizes of grid-aligned objects.
22pub type GridSize = Size3D<GridSizeCoord, Cube>;
23
24/// Coordinates that are not locked to the cube grid.
25///
26/// Note: Because `GridCoordinate = i32` and `FreeCoordinate = f64`, which has
27/// more than 32 bits of mantissa, the infallible conversion
28/// `From<GridCoordinate> for FreeCoordinate` exists, which is often convenient.
29pub type FreeCoordinate = f64;
30
31/// Positions that are not locked to the cube grid but may interact with it.
32pub type FreePoint = Point3D<FreeCoordinate, Cube>;
33
34/// Vectors that are not locked to the cube grid but may interact with it.
35pub type FreeVector = Vector3D<FreeCoordinate, Cube>;
36
37/// Additional element-wise operations on `euclid` types.
38// TODO: Contribute these to `euclid` itself
39pub trait VectorOps<O> {
40    /// Input vector element type.
41    type Elem;
42    /// Output vector type.
43    type Output;
44    /// Apply the function to each element.
45    fn map<F: FnMut(Self::Elem) -> O>(self, f: F) -> Self::Output;
46    /// Apply the function to each element of the two inputs, pairwise.
47    fn zip<F: FnMut(Self::Elem, Self::Elem) -> O>(self, rhs: Self, f: F) -> Self::Output;
48}
49
50mod impl_euclid {
51    use super::*;
52
53    macro_rules! impl_vector_ops {
54        ($vec:ident, ($( $field:ident )*)) => {
55            impl<T, O, U> VectorOps<O> for $vec<T, U> {
56                type Elem = T;
57                type Output = $vec<O, U>;
58
59                #[inline]
60                fn map<F: FnMut(Self::Elem) -> O>(self, mut f: F) -> Self::Output {
61                    $vec::new($(f(self.$field),)*)
62                }
63
64                #[inline]
65                fn zip<F: FnMut(Self::Elem, Self::Elem) -> O>(
66                    self,
67                    rhs: Self,
68                    mut f: F,
69                ) -> Self::Output {
70                    $vec::new($(f(self.$field, rhs.$field),)*)
71                }
72            }
73        };
74    }
75
76    // TODO: contribute inherent methods for this to euclid
77    impl_vector_ops!(Size2D, (width height));
78    impl_vector_ops!(Size3D, (width height depth));
79
80    // TODO: contribute inherent methods for this (at least map()) to euclid
81    impl<T, O: Copy, U> VectorOps<O> for Box3D<T, U> {
82        type Elem = T;
83        type Output = Box3D<O, U>;
84
85        #[inline]
86        fn map<F: FnMut(Self::Elem) -> O>(self, mut f: F) -> Self::Output {
87            Box3D {
88                min: self.min.map(&mut f),
89                max: self.max.map(&mut f),
90            }
91        }
92
93        #[inline]
94        fn zip<F: FnMut(Self::Elem, Self::Elem) -> O>(self, rhs: Self, mut f: F) -> Self::Output {
95            Box3D {
96                min: self.min.zip(rhs.min, &mut f).to_point(),
97                max: self.max.zip(rhs.max, &mut f).to_point(),
98            }
99        }
100    }
101}