use glam_det::{Isometry3, Point3, Vec3, Vec3x4};
pub use phys_geom::shape::Cuboid;
use crate::ray::{Raycast, RaycastHitResult};
use crate::traits::{
BaseShapeWide, ContainsPoint, ContainsResult, CreateShapeWide, Expansion, MinkowskiSupport,
MinkowskiSupportResult, MinkowskiSupportResultWide, MinkowskiSupportWide,
SignedDistanceToPoint,
};
use crate::{CuboidWide, Ray, ShapeContainer};
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[allow(dead_code)]
enum PlaneNormalAxis {
X,
Y,
Z,
}
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct PlanerCuboid {
value: Cuboid,
plane_normal_axis: PlaneNormalAxis,
}
impl Default for PlanerCuboid {
fn default() -> Self {
Self {
value: Cuboid::new([1.0, 0.01, 1.0]),
plane_normal_axis: PlaneNormalAxis::Y,
}
}
}
impl MinkowskiSupport for PlanerCuboid {
fn support_point(&self, direction: Vec3, transform: &Isometry3) -> MinkowskiSupportResult {
self.value.support_point(direction, transform)
}
}
impl MinkowskiSupportWide for PlanerCuboidWide {
fn support_point_local(
&self,
local_direction: Vec3x4,
_: Option<&ShapeContainer>,
) -> MinkowskiSupportResultWide {
self.value.support_point_local(local_direction, None)
}
}
impl Expansion for PlanerCuboid {
#[inline]
fn max_radius_and_max_angular_expansion(&self) -> (f32, f32) {
self.value.max_radius_and_max_angular_expansion()
}
}
impl Raycast for PlanerCuboid {
fn raycast(
&self,
local_ray: Ray,
max_distance: f32,
discard_inside_hit: bool,
) -> Option<RaycastHitResult> {
self.value
.raycast(local_ray, max_distance, discard_inside_hit)
}
}
impl ContainsPoint for PlanerCuboid {
#[inline]
fn contains_point_with_threshold(&self, local_point: Point3, threshold: f32) -> ContainsResult {
self.value
.contains_point_with_threshold(local_point, threshold)
}
}
impl SignedDistanceToPoint for PlanerCuboid {
fn signed_distance_to_point(&self, local_point: Point3) -> f32 {
self.value.signed_distance_to_point(local_point)
}
}
#[derive(Debug)]
pub struct PlanerCuboidWide {
pub value: CuboidWide,
}
impl Default for PlanerCuboidWide {
#[inline]
fn default() -> Self {
Self {
value: CuboidWide::default(),
}
}
}
impl BaseShapeWide for PlanerCuboidWide {
type TShape = PlanerCuboid;
}
macro_rules! impl_planer_cuboid_wide {
($($num:tt),*) => {
$(
impl CreateShapeWide<$num> for PlanerCuboidWide {
fn create<'a>(iter: impl Iterator<Item=&'a Self::TShape> + Clone) -> Self where Self::TShape: 'a {
Self {
value: <CuboidWide as CreateShapeWide<$num>>::create(iter.map(|shape| &shape.value)),
}
}
}
)*
};
}
impl_planer_cuboid_wide!(1, 2, 3, 4);
#[cfg(test)]
mod tests {
use approx_det::assert_relative_eq;
use super::*;
use crate::glam::{Isometry3, Point3, Vec3};
#[test]
fn default_values_and_expansion() {
let pc = PlanerCuboid::default();
let he = pc.value.half_length();
assert_relative_eq!(he[0], 0.5);
assert_relative_eq!(he[1], 0.005);
assert_relative_eq!(he[2], 0.5);
assert_eq!(pc.plane_normal_axis, PlaneNormalAxis::Y);
let (max_r, max_ang) = pc.max_radius_and_max_angular_expansion();
assert!(max_r >= 0.0);
assert!(max_ang >= 0.0);
}
#[test]
fn minkowski_support_and_distance_and_contains() {
let pc = PlanerCuboid::default();
let iso = Isometry3::default();
let dir = Vec3::new(1.0, 0.0, 0.0);
let sp = pc.support_point(dir, &iso);
assert!(sp.point.x >= 0.0);
let inside = Point3::new(0.0, 0.0, 0.0);
let sd_inside = pc.signed_distance_to_point(inside);
assert!(sd_inside <= 0.0);
let outside = Point3::new(10.0, 0.0, 0.0);
let sd_outside = pc.signed_distance_to_point(outside);
assert!(sd_outside >= 0.0);
let contains = pc.contains_point_with_threshold(inside, 1.0e-5);
assert!(matches!(contains, ContainsResult::Inside));
}
#[test]
fn wide_support_and_create_shape_wide() {
let shapes = [
PlanerCuboid::default(),
PlanerCuboid::default(),
PlanerCuboid::default(),
PlanerCuboid::default(),
];
let _w1: PlanerCuboidWide = <PlanerCuboidWide as CreateShapeWide<1>>::create(shapes.iter());
let _w2: PlanerCuboidWide = <PlanerCuboidWide as CreateShapeWide<2>>::create(shapes.iter());
let _w3: PlanerCuboidWide = <PlanerCuboidWide as CreateShapeWide<3>>::create(shapes.iter());
let _w4: PlanerCuboidWide = <PlanerCuboidWide as CreateShapeWide<4>>::create(shapes.iter());
let wide = PlanerCuboidWide::default();
let dir4 = crate::traits::ArrayGetter::<4>::get_vec3x4_from_iter(
[
Vec3::new(1.0, 0.0, 0.0),
Vec3::new(1.0, 0.0, 0.0),
Vec3::new(1.0, 0.0, 0.0),
Vec3::new(1.0, 0.0, 0.0),
]
.into_iter(),
);
let sp4 = wide.support_point_local(dir4, None);
let px = sp4.point.x;
let py = sp4.point.y;
let pz = sp4.point.z;
let _ = (px, py, pz); }
}