phys-collision 2.0.1-beta.0

Provides collision detection ability
// Copyright (C) 2020-2025 phys-collision authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use glam_det::nums::num_traits::*;
use glam_det::{Dot, Isometry3, Point3, UnitVec3, UnitVec3x4, Vec3};
pub use phys_geom::shape::InfinitePlane;

use crate::traits::*;

const NORMAL: UnitVec3 = UnitVec3::Y;
pub trait InfinitePlaneExt {
    fn distance(&self, p: Point3) -> f32;
}

impl InfinitePlaneExt for InfinitePlane {
    #[inline]
    fn distance(&self, p: Point3) -> f32 {
        p.as_vec3().dot(NORMAL)
    }
}

impl ContainsPoint for InfinitePlane {
    #[inline]
    fn contains_point_with_threshold(&self, local_point: Point3, threshold: f32) -> ContainsResult {
        let distance = local_point.y;
        let abs_distance = distance.absf();

        if abs_distance < threshold {
            ContainsResult::Surface
        } else if distance > 0.0 {
            ContainsResult::Outside
        } else {
            ContainsResult::Inside
        }
    }
}

impl SignedDistanceToPoint for InfinitePlane {
    #[inline]
    fn signed_distance_to_point(&self, local_point: Point3) -> f32 {
        self.distance(local_point)
    }
}

impl MinkowskiSupport for InfinitePlane {
    #[allow(unused)]
    fn support_point(&self, direction: Vec3, transform: &Isometry3) -> MinkowskiSupportResult {
        todo!("issue #1197") // TODO: implement MinkowskiSupport for infinite_plane (#1197)
    }
}

impl Expansion for InfinitePlane {
    #[inline]
    fn max_radius_and_max_angular_expansion(&self) -> (f32, f32) {
        (0f32, 0f32)
    }
}

#[derive(Default, Debug)]
pub struct InfinitePlaneWide {}

impl InfinitePlaneWide {
    pub const NORMAL: UnitVec3x4 = UnitVec3x4::Y;
}

impl BaseShapeWide for InfinitePlaneWide {
    type TShape = InfinitePlane;
}

macro_rules! impl_infinite_plane_wide {
    ($($num:tt),*) => {
        $(
           impl CreateShapeWide<$num> for InfinitePlaneWide {
                fn create<'a>(_iter: impl Iterator<Item=&'a Self::TShape> + Clone) -> Self where Self::TShape: 'a {
                    InfinitePlaneWide::default()
                }
           }
        )*
    };
}

impl_infinite_plane_wide!(1, 2, 3, 4);

#[cfg(test)]
mod tests {
    use approx_det::assert_relative_eq;
    use glam_det::Point3;
    use wasm_bindgen_test::*;

    use crate::traits::*;
    use crate::{InfinitePlane, Shape, ShapeContainer};

    #[test]
    #[wasm_bindgen_test]
    fn test_contains_point_and_distance() {
        let _ = env_logger::builder().is_test(true).try_init();

        let container = ShapeContainer::default();
        let infinite_plane =
            Shape::InfinitePlane(InfinitePlane::default()).into_shape_ref(&container);

        macro_rules! test_both {
            ($point:expr, $res:expr, $distance:expr) => {
                assert_eq!(infinite_plane.contains_point($point), $res);
                assert_relative_eq!(infinite_plane.signed_distance_to_point($point), $distance);
            };
        }

        test_both!(
            Point3::new(0.0f32, 0.0f32, 0.0f32),
            ContainsResult::Surface,
            0.0f32
        );

        test_both!(
            Point3::new(1.0f32, 0.0f32, 0.0f32),
            ContainsResult::Surface,
            0.0f32
        );

        test_both!(
            Point3::new(1.0f32, 1.0f32, 0.0f32),
            ContainsResult::Outside,
            1.0f32
        );

        test_both!(
            Point3::new(1.0f32, -1.0f32, 0.0f32),
            ContainsResult::Inside,
            -1.0f32
        );
    }

    #[test]
    #[wasm_bindgen_test]
    fn test_compute_expand() {
        let _ = env_logger::builder().is_test(true).try_init();

        let shape = InfinitePlane::default();
        let (max_radius, max_angular_expansion) = shape.max_radius_and_max_angular_expansion();
        assert_relative_eq!(max_radius, 0f32);
        assert_relative_eq!(max_angular_expansion, 0f32);
    }
}