use std::ops::Add;
use nalgebra::{ClosedAdd, Vector3};
use num_traits::AsPrimitive;
use crate::{NodePoint, TreeIndex};
#[repr(transparent)]
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
pub struct Octant(pub(crate) u8);
impl Octant {
pub fn all() -> impl Iterator<Item = Self> {
(0..8).into_iter().map(Self)
}
pub fn new(i: bool, j: bool, k: bool) -> Self {
Self((i as u8 * 0b100) | (j as u8 * 0b010) | (k as u8))
}
#[inline]
pub fn i(self) -> u8 {
self.0 & 0b100
}
#[inline]
pub fn j(self) -> u8 {
self.0 & 0b010
}
#[inline]
pub fn k(self) -> u8 {
self.0 & 0b001
}
pub fn vector(self) -> Vector3<u8> {
Vector3::new(self.i(), self.j(), self.k())
}
}
impl From<Octant> for usize {
fn from(oct: Octant) -> Self {
oct.0 as usize
}
}
impl From<Octant> for u8 {
fn from(oct: Octant) -> Self {
oct.0
}
}
impl<Idx: TreeIndex + From<u8> + ClosedAdd> Add<Octant> for &NodePoint<Idx> {
type Output = NodePoint<Idx>;
#[inline]
fn add(self, o: Octant) -> Self::Output {
NodePoint::new(
self.0.x + o.i().into(),
self.0.y + o.j().into(),
self.0.z + o.k().into(),
self.0.w + 1u8.into(),
)
}
}
impl<Idx: TreeIndex> Add<Octant> for NodePoint<Idx>
where
u8: AsPrimitive<Idx>,
{
type Output = NodePoint<Idx>;
#[inline]
fn add(self, o: Octant) -> Self::Output {
Self::new(
self.0.x + o.i().as_(),
self.0.y + o.j().as_(),
self.0.z + o.k().as_(),
self.0.w + Idx::one(),
)
}
}