use bevy::{math::Vec3A, prelude::*};
use num_traits::{Bounded, Num, Signed};
use std::fmt::Debug;
use typenum::Unsigned;
pub trait Scalar: Bounded + Num + Clone + Copy + Signed + PartialOrd + Debug {}
impl<T> Scalar for T where T: Bounded + Num + Clone + Copy + Signed + PartialOrd + Debug {}
#[allow(clippy::module_name_repetitions)]
pub trait SpatialPoint: Copy + Clone + PartialEq + Debug {
type Scalar: Scalar;
type Vec: Send + Sync + IntoSpatialPoint;
type Dimension: Unsigned;
fn at(&self, nth: usize) -> Self::Scalar;
fn distance_squared(&self, other: &Self) -> Self::Scalar;
fn min_point(&self, other: &Self) -> Self::Vec;
fn max_point(&self, other: &Self) -> Self::Vec;
fn entity(&self) -> Option<Entity>;
fn vec(&self) -> Self::Vec;
}
#[allow(clippy::module_name_repetitions)]
pub trait IntoSpatialPoint: Send + Sync + Sized + Copy {
type Point: SpatialPoint + From<(Entity, Self)> + Copy;
fn into_spatial_point(self, e: Entity) -> Self::Point
where
Self::Point: From<(Entity, Self)>,
{
(e, self).into()
}
}
macro_rules! impl_spatial_point {
($pointname:ident, $bvec:ty, $unit:ty, $dim:ty, $diml:literal) => {
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct $pointname {
/// The vector of this Point
pub vec: $bvec,
pub entity: Option<Entity>,
}
impl $pointname {
fn new(vec: $bvec, entity: Entity) -> Self {
$pointname {
vec,
entity: Some(entity),
}
}
fn from_vec(vec: $bvec) -> Self {
$pointname { vec, entity: None }
}
}
impl SpatialPoint for $pointname {
type Scalar = $unit;
type Vec = $bvec;
type Dimension = $dim;
#[inline]
fn at(&self, nth: usize) -> Self::Scalar {
self.vec[nth]
}
#[inline]
fn distance_squared(&self, other: &Self) -> Self::Scalar {
self.vec.distance_squared(other.vec)
}
#[inline]
fn min_point(&self, other: &Self) -> Self::Vec {
self.vec.min(other.vec)
}
#[inline]
fn max_point(&self, other: &Self) -> Self::Vec {
self.vec.max(other.vec)
}
#[inline]
fn entity(&self) -> Option<Entity> {
self.entity
}
#[inline]
fn vec(&self) -> Self::Vec {
self.vec
}
}
impl From<(Entity, $bvec)> for $pointname {
fn from(value: (Entity, $bvec)) -> Self {
$pointname::new(value.1, value.0)
}
}
impl From<($bvec, Entity)> for $pointname {
fn from(value: ($bvec, Entity)) -> Self {
$pointname::new(value.0, value.1)
}
}
impl From<$bvec> for $pointname {
fn from(value: $bvec) -> Self {
$pointname::from_vec(value)
}
}
impl IntoSpatialPoint for $bvec {
type Point = $pointname;
}
};
}
impl_spatial_point!(Point2, bevy::math::Vec2, f32, typenum::consts::U2, 2);
impl_spatial_point!(Point3, bevy::math::Vec3, f32, typenum::consts::U3, 3);
impl_spatial_point!(Point3A, bevy::math::Vec3A, f32, typenum::consts::U3, 3);
impl_spatial_point!(PointD2, bevy::math::DVec2, f64, typenum::consts::U2, 2);
impl_spatial_point!(PointD3, bevy::math::DVec3, f64, typenum::consts::U3, 3);
pub trait VecFromTransform: IntoSpatialPoint {
fn from_transform(t: &Transform) -> Self;
}
impl VecFromTransform for Vec2 {
fn from_transform(t: &Transform) -> Self {
t.translation.truncate()
}
}
impl VecFromTransform for Vec3 {
fn from_transform(t: &Transform) -> Self {
t.translation
}
}
impl VecFromTransform for Vec3A {
fn from_transform(t: &Transform) -> Self {
t.translation.into()
}
}
pub trait VecFromGlobalTransform: IntoSpatialPoint {
fn from_transform(t: &GlobalTransform) -> Self;
}
impl VecFromGlobalTransform for Vec2 {
fn from_transform(t: &GlobalTransform) -> Self {
t.translation().truncate()
}
}
impl VecFromGlobalTransform for Vec3 {
fn from_transform(t: &GlobalTransform) -> Self {
t.translation()
}
}
impl VecFromGlobalTransform for Vec3A {
fn from_transform(t: &GlobalTransform) -> Self {
t.translation().into()
}
}