bevy_spatial/
point.rs

1//! The different point Traits and Types used by ``bevy_spatial``
2//!
3//! - [`Scalar`] is a Trait based on [`num_traits`] which is implemented for all numeric types used in Points.
4//! - [`SpatialPoint`] is a Trait that represents a point in space and the Entity it was created from.
5//!   It defines some, common methods needed while working with these points in different spatial datastructures.
6//! - [`IntoSpatialPoint`] is a Trait which is implemented for vector coordinate types for which a corresponding Point type exists.
7//!   Needs a [`Entity`] to include in the Point type.
8//! - [`VecFromTransform`] and [`VecFromGlobalTransform`] used to extract the translation from the corresponding Transform.
9//!   Used for automatically updating the spatial datastructure.
10
11use bevy::{math::Vec3A, prelude::*};
12use num_traits::{Bounded, Num, Signed};
13use std::fmt::Debug;
14use typenum::Unsigned;
15
16/// Trait implemented for all numeric types used in Points.
17pub trait Scalar: Bounded + Num + Clone + Copy + Signed + PartialOrd + Debug {}
18impl<T> Scalar for T where T: Bounded + Num + Clone + Copy + Signed + PartialOrd + Debug {}
19
20/// Represents a point in space and the Entity it was created from.
21///
22/// Implements a bunch of common methods needed while working with these points in different spatial datastructures.
23#[allow(clippy::module_name_repetitions)]
24pub trait SpatialPoint: Copy + Clone + PartialEq + Debug {
25    /// The Scalar type of a vector, example: [`f32`], [`f64`]
26    type Scalar: Scalar;
27
28    /// The vector type itself, for example [`Vec3`]
29    type Vec: Send + Sync + IntoSpatialPoint;
30
31    /// The dimension of this vector, like [`typenum::U2`] [`typenum::U3`]
32    type Dimension: Unsigned;
33
34    /// Get the value at this index.
35    /// Used for datastructure specific implementations.
36    ///
37    /// `nth` is always smaller than [`Self::Dimension`].
38    fn at(&self, nth: usize) -> Self::Scalar;
39
40    /// Get the squared distance of this point to another point of the same type.
41    fn distance_squared(&self, other: &Self) -> Self::Scalar;
42
43    /// Get the elementwise minimum between this and another point
44    fn min_point(&self, other: &Self) -> Self::Vec;
45
46    /// Get the elementwise maximum between this and another point
47    fn max_point(&self, other: &Self) -> Self::Vec;
48
49    /// Get the Entity associated with this point.
50    fn entity(&self) -> Option<Entity>;
51
52    /// Get a this points vector.
53    fn vec(&self) -> Self::Vec;
54}
55
56/// Trait implemented for vector coordinate types for which a corresponding Point type exists.
57/// Used to convert from the vector coordinate types to the corresponding Point type by providing a Entity
58#[allow(clippy::module_name_repetitions)]
59pub trait IntoSpatialPoint: Send + Sync + Sized + Copy {
60    /// The resulting point type, for example [`Point3`]
61    type Point: SpatialPoint + From<(Entity, Self)> + Copy;
62
63    /// Converts from the implementing type to the point type with its Entity filled.
64    fn into_spatial_point(self, e: Entity) -> Self::Point
65    where
66        Self::Point: From<(Entity, Self)>,
67    {
68        (e, self).into()
69    }
70}
71macro_rules! impl_spatial_point {
72    ($pointname:ident, $bvec:ty, $unit:ty, $dim:ty, $diml:literal) => {
73        /// Newtype over bevy/glam vectors, needed to allow implementing foreign spatial datastructure traits.
74        #[derive(Clone, Copy, Debug, Default, PartialEq)]
75        pub struct $pointname {
76            /// The vector of this Point
77            pub vec: $bvec,
78            /// The Entity associated with this Point
79            pub entity: Option<Entity>,
80        }
81
82        impl $pointname {
83            fn new(vec: $bvec, entity: Entity) -> Self {
84                $pointname {
85                    vec,
86                    entity: Some(entity),
87                }
88            }
89
90            fn from_vec(vec: $bvec) -> Self {
91                $pointname { vec, entity: None }
92            }
93        }
94
95        impl SpatialPoint for $pointname {
96            type Scalar = $unit;
97            type Vec = $bvec;
98            type Dimension = $dim;
99
100            #[inline]
101            fn at(&self, nth: usize) -> Self::Scalar {
102                self.vec[nth]
103            }
104
105            #[inline]
106            fn distance_squared(&self, other: &Self) -> Self::Scalar {
107                self.vec.distance_squared(other.vec)
108            }
109
110            #[inline]
111            fn min_point(&self, other: &Self) -> Self::Vec {
112                self.vec.min(other.vec)
113            }
114
115            #[inline]
116            fn max_point(&self, other: &Self) -> Self::Vec {
117                self.vec.max(other.vec)
118            }
119
120            #[inline]
121            fn entity(&self) -> Option<Entity> {
122                self.entity
123            }
124
125            #[inline]
126            fn vec(&self) -> Self::Vec {
127                self.vec
128            }
129        }
130
131        impl From<(Entity, $bvec)> for $pointname {
132            fn from(value: (Entity, $bvec)) -> Self {
133                $pointname::new(value.1, value.0)
134            }
135        }
136
137        impl From<($bvec, Entity)> for $pointname {
138            fn from(value: ($bvec, Entity)) -> Self {
139                $pointname::new(value.0, value.1)
140            }
141        }
142
143        impl From<$bvec> for $pointname {
144            fn from(value: $bvec) -> Self {
145                $pointname::from_vec(value)
146            }
147        }
148
149        impl IntoSpatialPoint for $bvec {
150            type Point = $pointname;
151        }
152    };
153}
154
155impl_spatial_point!(Point2, bevy::math::Vec2, f32, typenum::consts::U2, 2);
156impl_spatial_point!(Point3, bevy::math::Vec3, f32, typenum::consts::U3, 3);
157impl_spatial_point!(Point3A, bevy::math::Vec3A, f32, typenum::consts::U3, 3);
158impl_spatial_point!(PointD2, bevy::math::DVec2, f64, typenum::consts::U2, 2);
159impl_spatial_point!(PointD3, bevy::math::DVec3, f64, typenum::consts::U3, 3);
160
161/// Helper trait for extracting the translation of a [`Transform`] to a specific vector type
162/// Used for automatically updating the spatial datastructure.
163pub trait VecFromTransform: IntoSpatialPoint {
164    /// Create this vector type from a [`Transform`]
165    fn from_transform(t: &Transform) -> Self;
166}
167
168impl VecFromTransform for Vec2 {
169    fn from_transform(t: &Transform) -> Self {
170        t.translation.truncate()
171    }
172}
173impl VecFromTransform for Vec3 {
174    fn from_transform(t: &Transform) -> Self {
175        t.translation
176    }
177}
178impl VecFromTransform for Vec3A {
179    fn from_transform(t: &Transform) -> Self {
180        t.translation.into()
181    }
182}
183
184/// Helper trait for extracting the translation of a [`GlobalTransform`] to a specific vector type
185/// Used for automatically updating the spatial datastructure.
186
187pub trait VecFromGlobalTransform: IntoSpatialPoint {
188    /// Create this vector type from a [`GlobalTransform`]
189    fn from_transform(t: &GlobalTransform) -> Self;
190}
191
192impl VecFromGlobalTransform for Vec2 {
193    fn from_transform(t: &GlobalTransform) -> Self {
194        t.translation().truncate()
195    }
196}
197impl VecFromGlobalTransform for Vec3 {
198    fn from_transform(t: &GlobalTransform) -> Self {
199        t.translation()
200    }
201}
202impl VecFromGlobalTransform for Vec3A {
203    fn from_transform(t: &GlobalTransform) -> Self {
204        t.translation().into()
205    }
206}