use super::{BoundingBox, HasBoundingBox, coordinates, point};
use crate::Point;
use crate::surfaces::{
BSplineSurface, Cone, Cylinder, ElementarySurface, Plane, Sphere, Surface, Torus,
};
fn centered(center: Point, half: [f64; 3]) -> BoundingBox {
let c = coordinates(center);
BoundingBox {
min: point(std::array::from_fn(|k| c[k] - half[k])),
max: point(std::array::from_fn(|k| c[k] + half[k])),
}
}
impl HasBoundingBox for Plane {
fn bounding_box(&self) -> Option<BoundingBox> {
None
}
}
impl HasBoundingBox for Cylinder {
fn bounding_box(&self) -> Option<BoundingBox> {
None
}
}
impl HasBoundingBox for Cone {
fn bounding_box(&self) -> Option<BoundingBox> {
None
}
}
impl HasBoundingBox for Sphere {
fn bounding_box(&self) -> Option<BoundingBox> {
Some(centered(self.center(), [self.radius(); 3]))
}
}
impl HasBoundingBox for Torus {
fn bounding_box(&self) -> Option<BoundingBox> {
let frame = self.frame();
let (x, y) = (frame.x_direction(), frame.y_direction());
let (x, y) = ([x.x, x.y, x.z], [y.x, y.y, y.z]);
let (major, minor) = (self.major_radius(), self.minor_radius());
Some(centered(
self.center(),
std::array::from_fn(|k| major * x[k].hypot(y[k]) + minor),
))
}
}
impl HasBoundingBox for BSplineSurface {
fn bounding_box(&self) -> Option<BoundingBox> {
BoundingBox::from_points(self.poles().iter().copied())
}
}
impl HasBoundingBox for Surface {
fn bounding_box(&self) -> Option<BoundingBox> {
match self {
Surface::Plane(s) => s.bounding_box(),
Surface::Cylinder(s) => s.bounding_box(),
Surface::Cone(s) => s.bounding_box(),
Surface::Sphere(s) => s.bounding_box(),
Surface::Torus(s) => s.bounding_box(),
Surface::BSpline(s) => s.bounding_box(),
}
}
}
impl HasBoundingBox for ElementarySurface {
fn bounding_box(&self) -> Option<BoundingBox> {
match self {
ElementarySurface::Plane(s) => s.bounding_box(),
ElementarySurface::Cylinder(s) => s.bounding_box(),
ElementarySurface::Cone(s) => s.bounding_box(),
ElementarySurface::Sphere(s) => s.bounding_box(),
ElementarySurface::Torus(s) => s.bounding_box(),
}
}
}