nphysics3d/volumetric/
volumetric_compound.rs

1use num::Zero;
2
3use crate::math::{AngularInertia, Point};
4use crate::volumetric::{InertiaTensor, Volumetric};
5use na::{self, RealField};
6use ncollide::shape::Compound;
7
8impl<N: RealField + Copy> Volumetric<N> for Compound<N> {
9    fn area(&self) -> N {
10        let mut stot: N = na::zero();
11
12        for &(_, ref s) in self.shapes().iter() {
13            stot += s.area()
14        }
15
16        stot
17    }
18
19    fn volume(&self) -> N {
20        let mut vtot: N = na::zero();
21
22        for &(_, ref s) in self.shapes().iter() {
23            vtot += s.volume()
24        }
25
26        vtot
27    }
28
29    fn center_of_mass(&self) -> Point<N> {
30        let mut mtot = N::zero();
31        let mut ctot = Point::origin();
32        let mut gtot = Point::origin(); // geometric center.
33
34        let shapes = self.shapes();
35
36        for &(ref m, ref s) in shapes.iter() {
37            let (mpart, cpart, _) = s.mass_properties(na::one());
38
39            mtot += mpart;
40            ctot += (*m * cpart * mpart).coords;
41            gtot += (*m * cpart).coords;
42        }
43
44        if mtot.is_zero() {
45            gtot
46        } else {
47            ctot / mtot
48        }
49    }
50
51    fn unit_angular_inertia(&self) -> AngularInertia<N> {
52        let mut itot = AngularInertia::zero();
53
54        let com = self.center_of_mass();
55        let shapes = self.shapes();
56
57        for &(ref m, ref s) in shapes.iter() {
58            let (mpart, cpart, ipart) = s.mass_properties(na::one());
59
60            itot += ipart
61                .to_world_space(m)
62                .to_relative_wrt_point(mpart, &(*m * cpart + (-com.coords)));
63        }
64
65        itot
66    }
67
68    /// The mass properties of this `CompoundData`.
69    ///
70    /// If `density` is not zero, it will be multiplied with the density of every object of the
71    /// compound shape.
72    fn mass_properties(&self, density: N) -> (N, Point<N>, AngularInertia<N>) {
73        let mut itot = AngularInertia::zero();
74        let mut ctot = Point::origin();
75        let mut gtot = Point::origin(); // geometric center.
76        let mut mtot = N::zero();
77
78        let shapes = self.shapes();
79        let props: Vec<_> = shapes
80            .iter()
81            .map(|&(_, ref s)| s.mass_properties(na::one()))
82            .collect();
83
84        for (&(ref m, _), &(ref mpart, ref cpart, _)) in shapes.iter().zip(props.iter()) {
85            mtot += *mpart;
86            ctot += (*m * *cpart * *mpart).coords;
87            gtot += (*m * *cpart).coords;
88        }
89
90        if mtot.is_zero() {
91            ctot = gtot;
92        } else {
93            ctot /= mtot;
94        }
95
96        for (&(ref m, _), &(ref mpart, ref cpart, ref ipart)) in shapes.iter().zip(props.iter()) {
97            itot += ipart
98                .to_world_space(m)
99                .to_relative_wrt_point(*mpart, &(*m * *cpart + (-ctot.coords)));
100        }
101
102        (mtot * density, ctot, itot * density)
103    }
104}