Skip to main content

qualia_core_db/render/physics/
material.rs

1//! Material, mass, and momentum for an artefact — the `P` (physical momentum) the STELLAR §C
2//! Manifold-Coordinate carries, applied here to a rendered body. Zero-alloc, deterministic.
3
4use super::aabb::Aabb;
5
6/// Bulk material properties of an artefact.
7#[derive(Clone, Copy, Debug, PartialEq)]
8pub struct Material {
9    /// Density in mass per unit volume (units are the caller's; consistent within a scene).
10    pub density: f32,
11    /// Whether the material resists compression (paired with `Admission::min_extent` upstream).
12    pub incompressible: bool,
13}
14
15impl Material {
16    pub const fn new(density: f32, incompressible: bool) -> Self {
17        Material {
18            density,
19            incompressible,
20        }
21    }
22}
23
24/// A physical body: a material filling a bounding box, with a linear velocity.
25#[derive(Clone, Copy, Debug)]
26pub struct Body {
27    pub material: Material,
28    pub aabb: Aabb,
29    pub velocity: [f32; 3],
30}
31
32impl Body {
33    pub fn new(material: Material, aabb: Aabb, velocity: [f32; 3]) -> Self {
34        Body {
35            material,
36            aabb,
37            velocity,
38        }
39    }
40
41    /// Mass = density × enclosed volume.
42    #[inline]
43    pub fn mass(&self) -> f32 {
44        self.material.density * self.aabb.volume()
45    }
46
47    /// Linear momentum `P = m·v` — the kinetic quantity stored in the Manifold-Coordinate.
48    #[inline]
49    pub fn momentum(&self) -> [f32; 3] {
50        let m = self.mass();
51        [
52            self.velocity[0] * m,
53            self.velocity[1] * m,
54            self.velocity[2] * m,
55        ]
56    }
57
58    /// Kinetic energy `½·m·|v|²`.
59    #[inline]
60    pub fn kinetic_energy(&self) -> f32 {
61        let v2 = self.velocity[0] * self.velocity[0]
62            + self.velocity[1] * self.velocity[1]
63            + self.velocity[2] * self.velocity[2];
64        0.5 * self.mass() * v2
65    }
66}
67
68#[cfg(test)]
69mod tests {
70    use super::*;
71
72    #[test]
73    fn mass_is_density_times_volume() {
74        let b = Body::new(
75            Material::new(2.0, true),
76            Aabb::new([0.0, 0.0, 0.0], [1.0, 2.0, 3.0]), // volume 6
77            [0.0, 0.0, 0.0],
78        );
79        assert_eq!(b.mass(), 12.0);
80    }
81
82    #[test]
83    fn momentum_and_energy() {
84        let b = Body::new(
85            Material::new(1.0, false),
86            Aabb::new([0.0, 0.0, 0.0], [1.0, 1.0, 1.0]), // volume 1, mass 1
87            [3.0, 0.0, 4.0],
88        );
89        assert_eq!(b.momentum(), [3.0, 0.0, 4.0]);
90        assert_eq!(b.kinetic_energy(), 0.5 * 25.0); // |v|² = 25
91    }
92}