use bevy_math::{Vec2, Vec3, Vec3A, Vec4, VectorSpace};
use crate::cells::WithGradient;
pub trait LengthFunction<T: VectorSpace<Scalar = f32>> {
fn max_for_element_max(&self, element_max: f32) -> f32;
#[inline]
fn length_of(&self, vec: T) -> f32 {
self.length_from_ordering(self.length_ordering(vec))
}
fn length_ordering(&self, vec: T) -> f32;
fn length_from_ordering(&self, ordering: f32) -> f32;
}
pub trait DifferentiableLengthFunction<T: VectorSpace<Scalar = f32>>: LengthFunction<T> {
fn length_and_gradient_of(&self, vec: T) -> WithGradient<f32, T>;
}
#[derive(Default, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
#[cfg_attr(feature = "debug", derive(Debug))]
pub struct EuclideanLength;
#[derive(Default, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
#[cfg_attr(feature = "debug", derive(Debug))]
pub struct EuclideanSqrdLength;
#[derive(Default, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
#[cfg_attr(feature = "debug", derive(Debug))]
pub struct ManhattanLength;
#[derive(Default, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
#[cfg_attr(feature = "debug", derive(Debug))]
pub struct HybridLength;
#[derive(Default, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
#[cfg_attr(feature = "debug", derive(Debug))]
pub struct ChebyshevLength;
#[derive(Clone, Copy, PartialEq)]
#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
#[cfg_attr(feature = "debug", derive(Debug))]
pub struct MinkowskiLength(pub f32);
impl Default for MinkowskiLength {
fn default() -> Self {
Self(0.5)
}
}
macro_rules! impl_distances {
($t:path) => {
impl LengthFunction<$t> for EuclideanLength {
#[inline]
fn max_for_element_max(&self, element_max: f32) -> f32 {
element_max * <$t>::SQRT_NUM_ELEMENTS
}
#[inline]
fn length_ordering(&self, vec: $t) -> f32 {
vec.length_squared()
}
#[inline]
fn length_from_ordering(&self, ordering: f32) -> f32 {
bevy_math::ops::sqrt(ordering)
}
}
impl DifferentiableLengthFunction<$t> for EuclideanLength {
#[inline]
fn length_and_gradient_of(&self, vec: $t) -> WithGradient<f32, $t> {
WithGradient {
value: bevy_math::ops::sqrt(vec.length_squared()),
gradient: vec
/ crate::rng::force_float_non_zero(bevy_math::ops::sqrt(
vec.length_squared(),
)),
}
}
}
impl LengthFunction<$t> for EuclideanSqrdLength {
#[inline]
fn max_for_element_max(&self, element_max: f32) -> f32 {
element_max * element_max * <$t>::NUM_ELEMENTS
}
#[inline]
fn length_ordering(&self, vec: $t) -> f32 {
vec.length_squared()
}
#[inline]
fn length_from_ordering(&self, ordering: f32) -> f32 {
ordering
}
}
impl DifferentiableLengthFunction<$t> for EuclideanSqrdLength {
#[inline]
fn length_and_gradient_of(&self, vec: $t) -> WithGradient<f32, $t> {
WithGradient {
value: vec.length_squared(),
gradient: vec * 2.0,
}
}
}
impl LengthFunction<$t> for ManhattanLength {
#[inline]
fn max_for_element_max(&self, element_max: f32) -> f32 {
element_max * <$t>::NUM_ELEMENTS
}
#[inline]
fn length_ordering(&self, vec: $t) -> f32 {
vec.abs().element_sum()
}
#[inline]
fn length_from_ordering(&self, ordering: f32) -> f32 {
ordering
}
}
impl DifferentiableLengthFunction<$t> for ManhattanLength {
#[inline]
fn length_and_gradient_of(&self, vec: $t) -> WithGradient<f32, $t> {
WithGradient {
value: vec.abs().element_sum(),
gradient: vec,
}
}
}
impl LengthFunction<$t> for HybridLength {
#[inline]
fn max_for_element_max(&self, element_max: f32) -> f32 {
element_max * 2.0 * element_max * <$t>::NUM_ELEMENTS
}
#[inline]
fn length_ordering(&self, vec: $t) -> f32 {
vec.length_squared() + vec.abs().element_sum()
}
#[inline]
fn length_from_ordering(&self, ordering: f32) -> f32 {
ordering
}
}
impl DifferentiableLengthFunction<$t> for HybridLength {
#[inline]
fn length_and_gradient_of(&self, vec: $t) -> WithGradient<f32, $t> {
WithGradient {
value: vec.length_squared() + vec.abs().element_sum(),
gradient: vec * 3.0,
}
}
}
impl LengthFunction<$t> for ChebyshevLength {
#[inline]
fn max_for_element_max(&self, element_max: f32) -> f32 {
element_max
}
#[inline]
fn length_ordering(&self, vec: $t) -> f32 {
vec.abs().max_element()
}
#[inline]
fn length_from_ordering(&self, ordering: f32) -> f32 {
ordering
}
}
impl LengthFunction<$t> for MinkowskiLength {
#[inline]
fn max_for_element_max(&self, element_max: f32) -> f32 {
element_max * <$t>::NUM_ELEMENTS
}
#[inline]
fn length_ordering(&self, vec: $t) -> f32 {
vec.abs().powf(self.0).element_sum()
}
#[inline]
fn length_from_ordering(&self, ordering: f32) -> f32 {
ordering.powf(1.0 / self.0)
}
}
};
}
impl_distances!(Vec2);
impl_distances!(Vec3);
impl_distances!(Vec3A);
impl_distances!(Vec4);
pub trait ElementalVectorSpace: VectorSpace<Scalar = f32> {
const NUM_ELEMENTS: f32;
const SQRT_NUM_ELEMENTS: f32;
}
impl ElementalVectorSpace for Vec2 {
const NUM_ELEMENTS: f32 = 2.0;
const SQRT_NUM_ELEMENTS: f32 = core::f32::consts::SQRT_2;
}
impl ElementalVectorSpace for Vec3 {
const NUM_ELEMENTS: f32 = 3.0;
const SQRT_NUM_ELEMENTS: f32 = 1.732_050_8;
}
impl ElementalVectorSpace for Vec3A {
const NUM_ELEMENTS: f32 = 3.0;
const SQRT_NUM_ELEMENTS: f32 = 1.732_050_8;
}
impl ElementalVectorSpace for Vec4 {
const NUM_ELEMENTS: f32 = 4.0;
const SQRT_NUM_ELEMENTS: f32 = 1.0;
}