anput-physics 0.22.3

Physics plugin for Anput ECS
Documentation
use crate::{
    Scalar,
    components::BodyAccessInfo,
    density_fields::{DensityField, DensityRange},
};
use std::cmp::Ordering;
use vek::{Aabb, Vec3};

pub struct AabbDensityField {
    pub aabb: Aabb<Scalar>,
    pub density: Scalar,
}

impl DensityField for AabbDensityField {
    fn aabb(&self, _: &BodyAccessInfo) -> Aabb<Scalar> {
        self.aabb
    }

    fn density_at_point(&self, point: Vec3<Scalar>, _: &BodyAccessInfo) -> Scalar {
        if self.aabb.contains_point(point) {
            self.density
        } else {
            0.0
        }
    }

    fn density_at_region(&self, region: Aabb<Scalar>, _: &BodyAccessInfo) -> DensityRange {
        if self.aabb.contains_aabb(region) {
            DensityRange::converged(self.density)
        } else if self.aabb.collides_with_aabb(region) {
            DensityRange {
                min: 0.0,
                max: self.density,
            }
        } else {
            Default::default()
        }
    }

    fn normal_at_point(
        &self,
        point: Vec3<Scalar>,
        _: Vec3<Scalar>,
        _: &BodyAccessInfo,
    ) -> Vec3<Scalar> {
        let size = self.aabb.size().into_array();
        [
            (
                size[0],
                (point.x - self.aabb.min.x).abs(),
                Vec3::new(-1.0, 0.0, 0.0),
            ),
            (
                size[1],
                (point.y - self.aabb.min.y).abs(),
                Vec3::new(0.0, -1.0, 0.0),
            ),
            (
                size[2],
                (point.z - self.aabb.min.z).abs(),
                Vec3::new(0.0, 0.0, -1.0),
            ),
            (
                size[0],
                (self.aabb.max.x - point.x).abs(),
                Vec3::new(1.0, 0.0, 0.0),
            ),
            (
                size[1],
                (self.aabb.max.y - point.y).abs(),
                Vec3::new(0.0, 1.0, 0.0),
            ),
            (
                size[2],
                (self.aabb.max.z - point.z).abs(),
                Vec3::new(0.0, 0.0, 1.0),
            ),
        ]
        .into_iter()
        .filter(|(size, _, _)| *size > Scalar::EPSILON)
        .min_by(|(_, a, _), (_, b, _)| a.partial_cmp(b).unwrap_or(Ordering::Equal))
        .map(|(_, _, normal)| normal)
        .unwrap_or_default()
    }
}