1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
//! Numeric types used for coordinates and related quantities.

use euclid::{Point3D, Size2D, Size3D, Vector3D};

use crate::math::Cube;

/// Coordinates that are locked to the cube grid.
pub type GridCoordinate = i32;

/// Numeric type in a [`GridSize`].
///
/// TODO: This needs a cleaner name.
pub type GridSizeCoord = u32;

/// Positions that are locked to the cube grid.
pub type GridPoint = Point3D<GridCoordinate, Cube>;

/// Vectors that are locked to the cube grid.
pub type GridVector = Vector3D<GridCoordinate, Cube>;

/// Sizes of grid-aligned objects.
pub type GridSize = Size3D<GridSizeCoord, Cube>;

/// Coordinates that are not locked to the cube grid.
///
/// Note: Because `GridCoordinate = i32` and `FreeCoordinate = f64`, which has
/// more than 32 bits of mantissa, the infallible conversion
/// `From<GridCoordinate> for FreeCoordinate` exists, which is often convenient.
pub type FreeCoordinate = f64;

/// Positions that are not locked to the cube grid but may interact with it.
pub type FreePoint = Point3D<FreeCoordinate, Cube>;

/// Vectors that are not locked to the cube grid but may interact with it.
pub type FreeVector = Vector3D<FreeCoordinate, Cube>;

/// Additional element-wise operations on `euclid` types.
// TODO: Contribute these to `euclid` itself
pub trait VectorOps<O> {
    /// Input vector element type.
    type Elem;
    /// Output vector type.
    type Output;
    /// Apply the function to each element.
    fn map<F: FnMut(Self::Elem) -> O>(self, f: F) -> Self::Output;
    /// Apply the function to each element of the two inputs, pairwise.
    fn zip<F: FnMut(Self::Elem, Self::Elem) -> O>(self, rhs: Self, f: F) -> Self::Output;
}

macro_rules! impl_vector_ops {
    ($vec:ident, ($( $field:ident )*)) => {
        impl<T, O, U> VectorOps<O> for $vec<T, U> {
            type Elem = T;
            type Output = $vec<O, U>;

            #[inline]
            fn map<F: FnMut(Self::Elem) -> O>(self, mut f: F) -> Self::Output {
                $vec::new($(f(self.$field),)*)
            }

            #[inline]
            fn zip<F: FnMut(Self::Elem, Self::Elem) -> O>(
                self,
                rhs: Self,
                mut f: F,
            ) -> Self::Output {
                $vec::new($(f(self.$field, rhs.$field),)*)
            }
        }
    };
}
mod impl_euclid {
    use super::*;
    impl_vector_ops!(Size2D, (width height));
    impl_vector_ops!(Size3D, (width height depth));
}