pasture_algorithms/
bounds.rs

1use anyhow::{Context, Result};
2use pasture_core::{
3    containers::{BorrowedBuffer, BorrowedBufferExt},
4    layout::attributes::POSITION_3D,
5    math::AABB,
6    nalgebra::{Point3, Vector3},
7};
8
9/// Calculate the bounding box of the points in the given `buffer`. Returns `None` if the buffer contains zero
10/// points, or if the `PointLayout` of the buffer does not contain the `POSITION_3D` attribute
11pub fn calculate_bounds<'a, T: BorrowedBuffer<'a>>(buffer: &'a T) -> Option<AABB<f64>> {
12    if buffer.len() == 0 {
13        return None;
14    }
15    let position_attribute = match buffer
16        .point_layout()
17        .get_attribute_by_name(POSITION_3D.name())
18    {
19        Some(a) => a,
20        None => return None,
21    };
22
23    if position_attribute.datatype() == POSITION_3D.datatype() {
24        Some(calculate_bounds_from_default_positions(buffer))
25    } else {
26        calculate_bounds_from_custom_positions(buffer).ok()
27    }
28}
29
30fn calculate_bounds_from_default_positions<'a, T: BorrowedBuffer<'a>>(buffer: &'a T) -> AABB<f64> {
31    let mut pos_min = Point3::new(f64::MAX, f64::MAX, f64::MAX);
32    let mut pos_max = Point3::new(f64::MIN, f64::MIN, f64::MIN);
33    for pos in buffer.view_attribute::<Vector3<f64>>(&POSITION_3D) {
34        if pos.x < pos_min.x {
35            pos_min.x = pos.x;
36        }
37        if pos.y < pos_min.y {
38            pos_min.y = pos.y;
39        }
40        if pos.z < pos_min.z {
41            pos_min.z = pos.z;
42        }
43        if pos.x > pos_max.x {
44            pos_max.x = pos.x;
45        }
46        if pos.y > pos_max.y {
47            pos_max.y = pos.y;
48        }
49        if pos.z > pos_max.z {
50            pos_max.z = pos.z;
51        }
52    }
53    AABB::from_min_max(pos_min, pos_max)
54}
55
56fn calculate_bounds_from_custom_positions<'a, T: BorrowedBuffer<'a>>(
57    buffer: &'a T,
58) -> Result<AABB<f64>> {
59    let mut pos_min = Point3::new(f64::MAX, f64::MAX, f64::MAX);
60    let mut pos_max = Point3::new(f64::MIN, f64::MIN, f64::MIN);
61    let attribute_view = buffer
62        .view_attribute_with_conversion::<Vector3<f64>>(&POSITION_3D)
63        .context("Can't convert POSITION_3D attribute to Vector3<f64>")?;
64    for pos in attribute_view {
65        if pos.x < pos_min.x {
66            pos_min.x = pos.x;
67        }
68        if pos.y < pos_min.y {
69            pos_min.y = pos.y;
70        }
71        if pos.z < pos_min.z {
72            pos_min.z = pos.z;
73        }
74        if pos.x > pos_max.x {
75            pos_max.x = pos.x;
76        }
77        if pos.y > pos_max.y {
78            pos_max.y = pos.y;
79        }
80        if pos.z > pos_max.z {
81            pos_max.z = pos.z;
82        }
83    }
84    Ok(AABB::from_min_max(pos_min, pos_max))
85}