parry3d/utils/
obb.rs

1use crate::math::{Isometry, Point, Real, Rotation, Translation, Vector, DIM};
2use crate::shape::Cuboid;
3
4/// Computes an oriented bounding box for the given set of points.
5///
6/// The returned OBB is not guaranteed to be the smallest enclosing OBB.
7/// Though it should be a pretty good on for most purposes.
8pub fn obb(pts: &[Point<Real>]) -> (Isometry<Real>, Cuboid) {
9    let cov = crate::utils::cov(pts);
10    let mut eigv = cov.symmetric_eigen().eigenvectors;
11
12    if eigv.determinant() < 0.0 {
13        eigv = -eigv;
14    }
15
16    let mut mins = Vector::repeat(Real::MAX);
17    let mut maxs = Vector::repeat(-Real::MAX);
18
19    for pt in pts {
20        for i in 0..DIM {
21            let dot = eigv.column(i).dot(&pt.coords);
22            mins[i] = mins[i].min(dot);
23            maxs[i] = maxs[i].max(dot);
24        }
25    }
26
27    #[cfg(feature = "dim2")]
28    let rot = Rotation::from_rotation_matrix(&na::Rotation2::from_matrix_unchecked(eigv));
29    #[cfg(feature = "dim3")]
30    let rot = Rotation::from_rotation_matrix(&na::Rotation3::from_matrix_unchecked(eigv));
31
32    (
33        rot * Translation::from((maxs + mins) / 2.0),
34        Cuboid::new((maxs - mins) / 2.0),
35    )
36}