bevy_math/sampling/mesh_sampling.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
//! Functionality related to random sampling from triangle meshes.
use crate::{
primitives::{Measured2d, Triangle3d},
ShapeSample, Vec3,
};
use rand::Rng;
use rand_distr::{Distribution, WeightedAliasIndex, WeightedError};
/// A [distribution] that caches data to allow fast sampling from a collection of triangles.
/// Generally used through [`sample`] or [`sample_iter`].
///
/// [distribution]: Distribution
/// [`sample`]: Distribution::sample
/// [`sample_iter`]: Distribution::sample_iter
///
/// Example
/// ```
/// # use bevy_math::{Vec3, primitives::*};
/// # use bevy_math::sampling::mesh_sampling::UniformMeshSampler;
/// # use rand::{SeedableRng, rngs::StdRng, distributions::Distribution};
/// let faces = Tetrahedron::default().faces();
/// let sampler = UniformMeshSampler::try_new(faces).unwrap();
/// let rng = StdRng::seed_from_u64(8765309);
/// // 50 random points on the tetrahedron:
/// let samples: Vec<Vec3> = sampler.sample_iter(rng).take(50).collect();
/// ```
pub struct UniformMeshSampler {
triangles: Vec<Triangle3d>,
face_distribution: WeightedAliasIndex<f32>,
}
impl Distribution<Vec3> for UniformMeshSampler {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Vec3 {
let face_index = self.face_distribution.sample(rng);
self.triangles[face_index].sample_interior(rng)
}
}
impl UniformMeshSampler {
/// Construct a new [`UniformMeshSampler`] from a list of [triangles].
///
/// Returns an error if the distribution of areas for the collection of triangles could not be formed
/// (most notably if the collection has zero surface area).
///
/// [triangles]: Triangle3d
pub fn try_new<T: IntoIterator<Item = Triangle3d>>(
triangles: T,
) -> Result<Self, WeightedError> {
let triangles: Vec<Triangle3d> = triangles.into_iter().collect();
let areas = triangles.iter().map(Measured2d::area).collect();
WeightedAliasIndex::new(areas).map(|face_distribution| Self {
triangles,
face_distribution,
})
}
}