dynamis-model 0.4.2

GPU-driven physics engine
Documentation
use dynamis_model::{BodyDesc, ColliderDesc, ConstraintDesc, Shape, inverse_inertia_diagonal};
use std::panic::{AssertUnwindSafe, catch_unwind};

#[test]
fn shape_constructors_reject_degenerate_geometry() {
    assert!(catch_unwind(|| Shape::sphere(0.0)).is_err());
    assert!(catch_unwind(|| Shape::sphere(-1.0)).is_err());
    assert!(catch_unwind(|| Shape::cuboid([1.0, 0.0, 1.0])).is_err());
    assert!(catch_unwind(|| Shape::cuboid([1.0, 1.0, -1.0])).is_err());
    assert!(catch_unwind(|| Shape::capsule(0.0, 1.0)).is_err());
    assert!(catch_unwind(|| Shape::capsule(1.0, -0.5)).is_err());
    assert!(catch_unwind(|| Shape::cylinder(0.0, 1.0)).is_err());
    assert!(catch_unwind(|| Shape::cylinder(1.0, -0.5)).is_err());
}

#[test]
fn body_descs_validate_inputs() {
    assert!(catch_unwind(|| BodyDesc::sphere(0.5).orientation([1.0, 1.0, 0.0, 0.0])).is_err());
    assert!(catch_unwind(|| BodyDesc::sphere(0.5).mass(-1.0)).is_err());
    assert!(catch_unwind(|| BodyDesc::sphere(0.5).friction(-0.1)).is_err());
    assert!(
        catch_unwind(|| {
            let mut desc = BodyDesc::sphere(0.5);
            for _ in 0..4 {
                desc = desc.collider(ColliderDesc::new(Shape::sphere(0.1)));
            }
            desc
        })
        .is_err()
    );
    let default = BodyDesc::sphere(0.5);
    assert_eq!(default.collision_group, 1);
    assert_eq!(default.collision_mask, u32::MAX);
    assert_eq!(default.mass, 1.0);
}

#[test]
fn collider_descs_validate_inputs() {
    assert!(
        catch_unwind(|| {
            ColliderDesc::new(Shape::sphere(0.5)).rotation([0.0, 1.0, 1.0, 0.0]);
        })
        .is_err()
    );
    assert!(catch_unwind(|| ColliderDesc::new(Shape::sphere(0.5)).friction(-1.0)).is_err());
}

#[test]
fn constraint_descs_validate_inputs() {
    assert!(catch_unwind(|| ConstraintDesc::distance([0.0; 3], [0.0; 3], -1.0)).is_err());
    assert!(catch_unwind(|| ConstraintDesc::revolute([0.0; 3], [0.0; 3], [0.0; 3])).is_err());
    assert!(catch_unwind(|| ConstraintDesc::prismatic([0.0; 3], [0.0; 3], [0.0; 3])).is_err());
    assert!(
        catch_unwind(
            || ConstraintDesc::revolute([0.0; 3], [0.0; 3], [1.0, 0.0, 0.0]).limit(1.0, 0.0)
        )
        .is_err()
    );
    assert!(
        catch_unwind(|| { ConstraintDesc::distance([0.0; 3], [0.0; 3], 1.0).spring(-1.0, 0.5) })
            .is_err()
    );
    assert!(
        catch_unwind(|| { ConstraintDesc::distance([0.0; 3], [0.0; 3], 1.0).spring(1.0, -0.5) })
            .is_err()
    );
}

#[test]
fn inverse_inertia_diagonal_follows_shape_mass() {
    assert_eq!(
        inverse_inertia_diagonal(&Shape::sphere(0.5), 0.0, None),
        [0.0; 3]
    );
    let sphere = inverse_inertia_diagonal(&Shape::sphere(0.5), 1.0, None);
    let expected = 1.0 / (0.4 * 0.25);
    assert!((sphere[0] - expected).abs() < 1e-6);
    let box_inertia = inverse_inertia_diagonal(&Shape::cuboid([0.5, 0.5, 0.5]), 1.0, None);
    let box_expected = 1.0 / (1.0 / 6.0);
    assert!((box_inertia[0] - box_expected).abs() < 1e-6);
    let static_geometry = catch_unwind(AssertUnwindSafe(|| {
        inverse_inertia_diagonal(
            &Shape::hull(dynamis_model::ShapeSourceHandle {
                id: 0,
                generation: 1,
            }),
            1.0,
            None,
        )
    }));
    assert!(
        static_geometry.is_err(),
        "world-geometry inertia needs bounds"
    );
    let with_bounds = inverse_inertia_diagonal(
        &Shape::hull(dynamis_model::ShapeSourceHandle {
            id: 0,
            generation: 1,
        }),
        1.0,
        Some(([0.0; 3], [2.0, 2.0, 2.0])),
    );
    assert!(with_bounds.iter().all(|inverse| *inverse > 0.0));
}

#[test]
fn bounding_radius_matches_shape_extent() {
    assert!((Shape::sphere(0.5).bounding_radius() - 0.5).abs() < 1e-6);
    assert!(
        (Shape::cuboid([1.0, 2.0, 3.0]).bounding_radius() - (1.0f32 + 4.0 + 9.0).sqrt()).abs()
            < 1e-6
    );
    assert!((Shape::capsule(0.3, 1.0).bounding_radius() - (1.0f32 + 0.09).sqrt()).abs() < 1e-6);
    assert!(
        Shape::mesh(dynamis_model::ShapeSourceHandle {
            id: 0,
            generation: 1
        })
        .bounding_radius()
            == 0.0
    );
}