model-converter/src/math/bounding_box.rs

125 lines
3.7 KiB
Rust
Raw Normal View History

2018-02-23 12:04:26 +01:00
//! Module containing the bounding box struct.
use math::Number;
macro_rules! make_bounding_box {
($name: ident, $vector: ident, $size: expr) => {
use math::vector::$vector;
/// Represents a bounding box.
2018-03-12 11:15:51 +01:00
#[derive(Clone)]
2018-02-23 12:04:26 +01:00
pub struct $name<T> {
min: $vector<T>,
max: $vector<T>,
}
impl<T: PartialOrd + Copy + Clone> $name<T> {
/// Creates a bounding box from its min and max coordinates.
pub fn new(min: $vector<T>, max: $vector<T>) -> $name<T> {
$name {
min: min,
max: max,
}
}
/// Enlarges the bounding box so it contains the point passed as parameter.
pub fn add_point(&mut self, point: &$vector<T>) {
for i in 0..$size {
if point[i] < self.min[i] {
self.min[i] = point[i];
}
if point[i] > self.max[i] {
self.max[i] = point[i];
}
}
}
/// Returns the minimum value of the bounding box.
pub fn min(&self) -> $vector<T> {
self.min
}
/// Returns the maximum value of the bounding box.
pub fn max(&self) -> $vector<T> {
self.max
}
2018-03-12 11:15:51 +01:00
/// Returns a mut ref to the min.
pub fn min_mut(&mut self) -> &mut $vector<T> {
&mut self.min
}
/// Returns a mut ref to the max.
pub fn max_mut(&mut self) -> &mut $vector<T> {
&mut self.max
}
2018-02-23 12:04:26 +01:00
}
impl<T: Number> $name<T> {
/// Scales a bounding box from its center.
pub fn scale(&mut self, factor: T) {
let diag = self.max - self.min;
self.min -= diag * factor;
self.max += diag * factor;
}
2018-03-12 11:15:51 +01:00
/// Returns the intersection between two bounding boxes.
pub fn intersection(&self, other: &$name<T>) -> $name<T> {
let mut ret = self.clone();
for i in 0..$size {
if ret.min()[i] > other.min()[i] {
ret.min_mut()[i] = other.min()[i];
}
if ret.max()[i] < other.max()[i] {
ret.max_mut()[i] = other.max()[i];
}
}
ret
}
2018-02-23 12:04:26 +01:00
}
}
}
make_bounding_box!(BoundingBox2, Vector2, 2);
make_bounding_box!(BoundingBox3, Vector3, 3);
make_bounding_box!(BoundingBox4, Vector4, 4);
2018-03-12 11:15:51 +01:00
#[cfg(test)]
mod tests {
macro_rules! assert_delta {
($x:expr, $y:expr, $d:expr) => {
if !($x - $y < $d || $y - $x < $d) { panic!(); }
}
}
use math::vector::Vector2;
use math::bounding_box::BoundingBox2;
#[test]
fn initialization() {
use std::f64::{MIN, MAX};
let mut bounding_box = BoundingBox2::new(
Vector2::new(MAX, MAX),
Vector2::new(MIN, MIN),
);
let v1 = Vector2::new(10.0, 20.0);
bounding_box.add_point(&v1);
assert_delta!(bounding_box.min().x(), v1.x(), 0.01);
assert_delta!(bounding_box.min().y(), v1.y(), 0.01);
assert_delta!(bounding_box.max().x(), v1.x(), 0.01);
assert_delta!(bounding_box.max().y(), v1.y(), 0.01);
let v2 = Vector2::new(20.0, 10.0);
assert_delta!(bounding_box.min().x(), v1.x(), 0.01);
assert_delta!(bounding_box.min().y(), v2.y(), 0.01);
assert_delta!(bounding_box.max().x(), v1.x(), 0.01);
assert_delta!(bounding_box.max().y(), v2.y(), 0.01);
}
}