Here's a cute little problem. I have a Vec<glam::Vec3>
and I want the maximum and minimum values of the x, y, and z values, to get the bounding box of a mesh. Obviously I can do this with a "for" loop. Or I could have six iterator passes of "min" and "max" calls, which is inefficient. Is there some idiomatic and efficient way to do this in Rust?
Iterator::fold, where the accumulator is a (min, max) pair: ((x,y,z), (x,y,z))?
Since you want an axis-aligned bounding box (AABB), I would define an AAB (axis-aligned box) type and write appropriate functions for it, after which the desired operation is straightforwardly expressed as:
points.into_iter().map(Aab::from_point).reduce(Aab::union)
Full code:
use glam::Vec3;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Aab {
pub min: Vec3,
pub max: Vec3,
}
impl Aab {
pub fn from_point(point: Vec3) -> Self {
Self {
min: point,
max: point,
}
}
/// Returns [`None`] if there are no points.
pub fn bounding_box_of(points: impl IntoIterator<Item = Vec3>) -> Option<Self> {
points.into_iter().map(Self::from_point).reduce(Self::union)
}
pub fn union(self, other: Self) -> Self {
Self {
min: self.min.min(other.min),
max: self.max.max(other.max),
}
}
}
#[test]
fn points_test() {
assert_eq!(
Aab::bounding_box_of([Vec3::new(0., 10., 0.), Vec3::new(10., 0., 5.)]),
Some(Aab {
min: Vec3::new(0., 0., 0.),
max: Vec3::new(10., 10., 5.),
})
)
}
This could be done with reduce()
without the struct, but with considerably more bother inside closures. Note that I use reduce()
rather than fold()
because the min/max of zero items is undefined.
Conveniently, glam
already has element-wise min and max functions to help us with this implementation.
That approach works and I'm now using it. Thanks.
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.