use geometry_tag::BoxTag;
use geometry_trait::{
Box as BoxTrait, Geometry, IndexedAccess, Point as PointTrait, PointMut, corner,
};
#[derive(Debug, Default, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Box<P: PointTrait> {
corners: [P; 2],
}
impl<P: PointTrait> Box<P> {
#[must_use]
pub const fn from_corners(min: P, max: P) -> Self {
Self {
corners: [min, max],
}
}
#[must_use]
pub const fn min(&self) -> &P {
&self.corners[corner::MIN]
}
#[must_use]
pub const fn max(&self) -> &P {
&self.corners[corner::MAX]
}
}
impl<P: PointTrait> Geometry for Box<P> {
type Kind = BoxTag;
type Point = P;
}
impl<P: PointMut> IndexedAccess for Box<P> {
#[inline]
fn get_indexed<const I: usize, const D: usize>(&self) -> P::Scalar {
self.corners[I].get::<D>()
}
#[inline]
fn set_indexed<const I: usize, const D: usize>(&mut self, value: P::Scalar) {
self.corners[I].set::<D>(value);
}
}
impl<P: PointMut> BoxTrait for Box<P> {}
#[cfg(test)]
mod tests {
use super::Box;
use crate::point::Point2D;
use geometry_cs::Cartesian;
use geometry_tag::BoxTag;
use geometry_trait::{Geometry, IndexedAccess, check_box, corner};
#[test]
fn box_round_trip_all_four_slots() {
let mut b = Box::from_corners(
Point2D::<f64, Cartesian>::default(),
Point2D::<f64, Cartesian>::default(),
);
b.set_indexed::<{ corner::MIN }, 0>(1.0);
b.set_indexed::<{ corner::MIN }, 1>(2.0);
b.set_indexed::<{ corner::MAX }, 0>(3.0);
b.set_indexed::<{ corner::MAX }, 1>(4.0);
assert_eq!(
b.get_indexed::<{ corner::MIN }, 0>().to_bits(),
1.0_f64.to_bits()
);
assert_eq!(
b.get_indexed::<{ corner::MIN }, 1>().to_bits(),
2.0_f64.to_bits()
);
assert_eq!(
b.get_indexed::<{ corner::MAX }, 0>().to_bits(),
3.0_f64.to_bits()
);
assert_eq!(
b.get_indexed::<{ corner::MAX }, 1>().to_bits(),
4.0_f64.to_bits()
);
}
#[test]
fn box_min_and_max_accessors() {
use geometry_trait::Point as PointTrait;
let lo = Point2D::<f64, Cartesian>::new(1.0, 2.0);
let hi = Point2D::<f64, Cartesian>::new(3.0, 4.0);
let b = Box::from_corners(lo, hi);
assert_eq!(b.min().get::<0>().to_bits(), 1.0_f64.to_bits());
assert_eq!(b.min().get::<1>().to_bits(), 2.0_f64.to_bits());
assert_eq!(b.max().get::<0>().to_bits(), 3.0_f64.to_bits());
assert_eq!(b.max().get::<1>().to_bits(), 4.0_f64.to_bits());
}
#[test]
fn box_kind_is_box_tag() {
fn k<T: Geometry<Kind = BoxTag>>() {}
k::<Box<Point2D<f64, Cartesian>>>();
}
#[test]
fn box_satisfies_concept() {
check_box::<Box<Point2D<f64, Cartesian>>>();
}
}