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::{Isometry3, UnitQuat, Vec3};

use super::traits::OverlapTest;
use crate::traits::MinkowskiSupport;
use crate::{ConvexHull, ConvexHullId, InfinitePlane, ShapeContainer};

pub(super) fn convex_hull_infinite_plane_overlap_test(
    a: ConvexHullId,
    _: InfinitePlane,
    speculative_margin: f32,
    offset_b_to_a: Vec3,
    orientation_a: UnitQuat,
    orientation_b: UnitQuat,
    container: Option<&ShapeContainer>,
) -> bool {
    let transform_a = Isometry3::from_rotation_translation(orientation_a, Vec3::ZERO);
    let transform_b = Isometry3::from_rotation_translation(orientation_b, offset_b_to_a);
    let a_to_b_transform = transform_b.inverse() * transform_a;
    let container = container.expect("ShapeContainer is required for ConvexHull");
    let convex_a = container.get::<ConvexHull>(a).expect("invalid shape id");

    let direction = Vec3::NEG_Y;
    let convex_in_b_support = convex_a.support_point(direction, &a_to_b_transform);
    let support_point_in_b = convex_in_b_support.point;

    if support_point_in_b.y <= speculative_margin {
        return true;
    }

    false
}

impl OverlapTest<InfinitePlane> for ConvexHullId {
    #[inline]
    fn overlap_test(
        &self,
        target: &InfinitePlane,
        offset_target: Vec3,
        orientation: UnitQuat,
        orientation_target: UnitQuat,
        container: Option<&ShapeContainer>,
    ) -> bool {
        convex_hull_infinite_plane_overlap_test(
            *self,
            *target,
            0.0001_f32,
            offset_target,
            orientation,
            orientation_target,
            container,
        )
    }
}

#[cfg(test)]
mod tests {

    use glam_det::Vec3;
    use wasm_bindgen_test::wasm_bindgen_test;

    use super::*;
    use crate::overlap::test_overlap_test::test_overlap_test;
    use crate::shapes::CuboidExt;
    use crate::{ConvexHull, Cuboid, ShapeContainer};

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

        let b = InfinitePlane::default();
        let a = Cuboid::new(Vec3::splat(4.0));
        let points_a = (0..8).map(|i| a.get_vertex(i)).collect::<Vec<_>>();
        let a = ConvexHull::new_unchecked(&points_a);
        let mut container = ShapeContainer::default();
        let a = container.add(a);

        assert!(test_overlap_test(
            &a,
            &b,
            Vec3::new(0.0, 2.0, 0.0),
            UnitQuat::IDENTITY,
            UnitQuat::IDENTITY,
            Some(&container)
        ));

        assert!(test_overlap_test(
            &a,
            &b,
            Vec3::new(0.0, 2.1, 0.0),
            UnitQuat::IDENTITY,
            UnitQuat::IDENTITY,
            Some(&container)
        ));

        assert!(!test_overlap_test(
            &a,
            &b,
            Vec3::new(0.0, -2.1, 0.0),
            UnitQuat::IDENTITY,
            UnitQuat::IDENTITY,
            Some(&container)
        ));

        assert!(test_overlap_test(
            &a,
            &b,
            Vec3::new(0.0, 0.0, 0.0),
            UnitQuat::IDENTITY,
            UnitQuat::IDENTITY,
            Some(&container)
        ));

        assert!(test_overlap_test(
            &a,
            &b,
            Vec3::new(2.1, 0.0, 2.1),
            UnitQuat::IDENTITY,
            UnitQuat::IDENTITY,
            Some(&container)
        ));

        assert!(!test_overlap_test(
            &a,
            &b,
            Vec3::new(0.0, -2.85, 0.0),
            UnitQuat::from_euler_default(45f32.to_radians(), 0f32.to_radians(), 0f32.to_radians(),),
            UnitQuat::from_euler_default(45f32.to_radians(), 0f32.to_radians(), 0f32.to_radians(),),
            Some(&container)
        ));

        assert!(!test_overlap_test(
            &a,
            &b,
            Vec3::new(0.0, -4.1, 0.0),
            UnitQuat::from_euler_default(45f32.to_radians(), 0f32.to_radians(), 0f32.to_radians(),),
            UnitQuat::IDENTITY,
            Some(&container)
        ));
    }
}