use num::Zero;
use std::cmp;
use cube::space::{LogWidth, Partition, Spatial, AABB};
use math::{LowerBound, UPoint3, UVector3, UpperBound};
pub struct Cursor {
origin: UPoint3,
width: LogWidth,
span: UVector3,
}
impl Cursor {
fn new(origin: &UPoint3, width: LogWidth, span: &UVector3) -> Self {
Cursor {
origin: *origin,
width: width,
span: *span,
}
}
pub fn at_point(point: &UPoint3, width: LogWidth) -> Self {
Cursor::at_point_with_span(point, width, &UVector3::zero())
}
pub fn at_point_with_span(point: &UPoint3, width: LogWidth, span: &UVector3) -> Self {
let partition = Partition::at_point(point, width);
Cursor::new(partition.origin(), width, span)
}
pub fn from_point_to_point(start: &UPoint3, end: &UPoint3, width: LogWidth) -> Self {
let (start, end) = {
(
Partition::at_point(&start.lower_bound(end), width),
Partition::at_point(&start.upper_bound(end), width),
)
};
let span = (end.origin() - start.origin()) / width.exp();
Cursor::new(start.origin(), width, &span)
}
pub fn at_cube<C>(cube: &C) -> Self
where
C: Spatial,
{
Cursor::at_point(cube.partition().origin(), cube.partition().width())
}
pub fn at_cube_with_span<C>(cube: &C, span: &UVector3) -> Self
where
C: Spatial,
{
Cursor::at_point_with_span(cube.partition().origin(), cube.partition().width(), span)
}
pub fn from_cube_to_cube<S, E>(start: &S, end: &E) -> Self
where
S: Spatial,
E: Spatial,
{
let width = cmp::min(start.partition().width(), end.partition().width());
let aabb = start.aabb().union(&end.aabb());
Cursor::from_point_to_point(&aabb.origin, &aabb.endpoint(), width)
}
pub fn origin(&self) -> &UPoint3 {
&self.origin
}
pub fn width(&self) -> LogWidth {
self.width
}
pub fn span(&self) -> &UVector3 {
&self.span
}
pub fn extent(&self) -> UVector3 {
((self.span + UVector3::new(1, 1, 1)) * self.width.exp()) - UVector3::new(1, 1, 1)
}
pub fn aabb(&self) -> AABB {
AABB::new(self.origin, self.extent())
}
}