use glam_det::nums::*;
use glam_det::{Vec2x4, Vec3x4};
use crate::shapes::CylinderWide;
pub(crate) const FRAC_1_SQRT_2: f32x4 = f32x4::const_splat(std::f32::consts::FRAC_1_SQRT_2);
pub(super) const EPS_3: f32x4 = f32x4::const_splat(1e-3);
pub(super) const EPS_5: f32x4 = f32x4::const_splat(1e-5);
pub(super) const EPS_6: f32x4 = f32x4::const_splat(1e-6);
pub(super) const EPS_7: f32x4 = f32x4::const_splat(1e-7);
pub(super) const EPS_8: f32x4 = f32x4::const_splat(1e-8);
pub(super) const EPS_10: f32x4 = f32x4::const_splat(1e-10);
pub(super) const EPS_12: f32x4 = f32x4::const_splat(1e-12);
pub(super) const EPS_14: f32x4 = f32x4::const_splat(1e-14);
pub(super) const EPS_15: f32x4 = f32x4::const_splat(1e-15);
#[must_use]
pub fn generate_interior_points(
cylinder: &CylinderWide,
cylinder_local_normal: Vec3x4,
local_closest_on_cylinder: Vec3x4,
) -> (Vec2x4, Vec2x4, Vec2x4, Vec2x4) {
let interpolation_min = f32x4::splat(0.9999);
let inverse_interpolation_span = f32x4::splat(1.0 / 0.00005);
let parallel_weight = ((cylinder_local_normal.y.absf() - interpolation_min)
* inverse_interpolation_span)
.clamp(f32x4::ZERO, f32x4::ONE);
let deepest_weight = f32x4::ONE - parallel_weight;
let replace_x = local_closest_on_cylinder
.x
.absf()
.gt(local_closest_on_cylinder.z.absf());
let replace_0 = local_closest_on_cylinder.x.gt(f32x4::ZERO) & replace_x;
let replace_1 = local_closest_on_cylinder.x.le(f32x4::ZERO) & replace_x;
let replace_2 = local_closest_on_cylinder.z.gt(f32x4::ZERO) & !replace_x;
let replace_3 = local_closest_on_cylinder.z.le(f32x4::ZERO) & !replace_x;
let scaled_radius = parallel_weight * cylinder.radius;
let scaled_closest_x = deepest_weight * local_closest_on_cylinder.x;
let scaled_closest_z = deepest_weight * local_closest_on_cylinder.z;
let interior_0 = Vec2x4::new(
(scaled_closest_x + scaled_radius).select(replace_0, cylinder.radius),
scaled_closest_z.select(replace_0, f32x4::ZERO),
);
let interior_1 = Vec2x4::new(
(scaled_closest_x - scaled_radius).select(replace_1, -cylinder.radius),
scaled_closest_z.select(replace_1, f32x4::ZERO),
);
let interior_2 = Vec2x4::new(
scaled_closest_x.select(replace_2, f32x4::ZERO),
(scaled_closest_z + scaled_radius).select(replace_2, cylinder.radius),
);
let interior_3 = Vec2x4::new(
scaled_closest_x.select(replace_3, f32x4::ZERO),
(scaled_closest_z - scaled_radius).select(replace_3, -cylinder.radius),
);
(interior_0, interior_1, interior_2, interior_3)
}
pub(super) trait NormalizeExt: Sized {
type Length;
fn normalize_and_length_or(&self, default: Self, epsilon: Self::Length)
-> (Self::Length, Self);
#[inline]
fn normalize_or(&self, default: Self, epsilon: Self::Length) -> Self {
self.normalize_and_length_or(default, epsilon).1
}
}
macro_rules! impl_normalize_ext {
($length_type:ty, $($type:ty),*) => {
$(
impl NormalizeExt for $type {
type Length = $length_type;
#[inline]
fn normalize_and_length_or(
&self,
default: Self,
epsilon: Self::Length,
) -> (Self::Length, Self) {
let length = self.length();
let length_recip = length.recip();
(
length,
Self::lane_select(length.gt(epsilon), self * length_recip, default),
)
}
}
)*
};
}
impl_normalize_ext!(f32x4, Vec3x4, Vec2x4);