#mass #inertia #trimesh

no-std polyhedral_mass_properties

Calculation of mass properties for triangle meshes

4 releases

0.2.2 Aug 15, 2024
0.2.1 Aug 15, 2024
0.2.0 Aug 15, 2024
0.1.0 Aug 13, 2024

#40 in Data formats


Used in mass-props

AGPL-3.0

24KB
282 lines

Polyhedral Mass Properties

Calculates the mass properties (mass, center of mass and inertia matrix/tensor) of triangle meshes.

The algorithm is based on the paper "Computing the Moment of Inertia of a Solid Defined by a Triangle Mesh" by Michael Kallay (Code).

Documentation

Documentation with examples is available on docs.rs 📚️

Demo binary

The binary mass-props uses this library to calculate the mass properties of meshes in glTF files. You can try it out to test the output of this library.


lib.rs:

Calculates the mass properties (mass, center of mass and inertia matrix/tensor) of triangle meshes.

The algorithm is based on the paper "Computing the Moment of Inertia of a Solid Defined by a Triangle Mesh" by Michael Kallay (Code).

How it works

Each triangle in the mesh has its own contribution (TriangleContrib) to the mass properties of the whole mesh. These contributions can be calculated independently and then summed up (O(N) where N is the number of triangles in the mesh).

The sum can then be converted to the actual mass properties (MassProperties) with MassProperties::from_contrib_sum (O(1)).

Examples

With vertices: &[[f64; 3]] and indices: &[usize]:

#
#
#
let contribution_sum = indices
    .chunks_exact(3)
    .map(|indices| {
        TriangleContrib::new(
            vertices[indices[0]],
            vertices[indices[1]],
            vertices[indices[2]],
        )
    })
    .sum();
let mass_properties = MassProperties::from_contrib_sum(contribution_sum);

Iterator

If indices is an iterator over usize with a known length (e.g. implements ExactSizeIterator), you can do the following without needing to collect the indices first:

#
#
#
let contribution_sum = (0..indices.len() / 3)
    .map(|_| {
        TriangleContrib::new(
            vertices[indices.next().unwrap()],
            vertices[indices.next().unwrap()],
            vertices[indices.next().unwrap()],
        )
    })
    .sum();
let mass_properties = MassProperties::from_contrib_sum(contribution_sum);

Multi-threading with Rayon

Calculating the mass properties can be easily multi-threaded by using Rayon.

#
#
#
use rayon::prelude::*;

let contribution_sum = indices
    .par_chunks_exact(3) // par_chunks_exact instead of chunks_exact
    .map(|indices| {
        TriangleContrib::new(
            vertices[indices[0]],
            vertices[indices[1]],
            vertices[indices[2]],
        )
    })
    .sum();
let mass_properties = MassProperties::from_contrib_sum(contribution_sum);
Multi-threading has some overhead and can even be slower for small meshes, especially if you can iterate over the indices instead of collecting them first for Rayon. Benchmark the multi-threaded version for your use case first before using it.

Feature flags

  • std: Enable the usage of the standard library. Enabled by fma and gltf.
  • fma: Use FMA instructions for better performance. Needs to be compiled with RUSTFLAGS="-C target-cpu=native".
  • serde: Implement the Serialize and Deserialize traits for Inertia and MassProperties.
  • gltf: Enable calculating the mass properties for gltf/glb files using MassProperties::from_gltf.

Dependencies

~0–0.8MB
~17K SLoC