#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Axis<const D: usize>(u8);
impl<const D: usize> Axis<D> {
pub const fn new(i: u8) -> Self {
assert!(i.count_ones() == 1);
assert!(i.trailing_zeros() < D as u32);
Self(i)
}
pub fn index(self) -> usize {
self.0.trailing_zeros() as usize
}
pub const fn array() -> [Self; D] {
let mut out = [Axis(0); D];
let mut i = 0;
loop {
if i == D {
break;
}
out[i] = Axis::new(1 << i);
i += 1;
}
out
}
}
impl Axis<3> {
pub const fn next(self) -> Self {
let u = self.0 << 1;
if u > Z.0 { X } else { Axis(u) }
}
}
pub const X: Axis<3> = Axis(1);
pub const Y: Axis<3> = Axis(2);
pub const Z: Axis<3> = Axis(4);
impl<const D: usize> std::ops::Mul<bool> for Axis<D> {
type Output = Self;
fn mul(self, rhs: bool) -> Self {
if rhs { self } else { Axis(0) }
}
}
impl<const D: usize> std::ops::BitAnd<Corner<D>> for Axis<D> {
type Output = bool;
fn bitand(self, rhs: Corner<D>) -> bool {
(self.0 & rhs.0) != 0
}
}
impl<const D: usize> std::ops::BitOr<Axis<D>> for Axis<D> {
type Output = Corner<D>;
fn bitor(self, rhs: Axis<D>) -> Self::Output {
Corner::new(self.0 | rhs.0)
}
}
impl<const D: usize> std::ops::BitOr<Corner<D>> for Axis<D> {
type Output = Corner<D>;
fn bitor(self, rhs: Corner<D>) -> Self::Output {
Corner::new(self.0 | rhs.0)
}
}
impl<const D: usize> From<Axis<D>> for Corner<D> {
fn from(a: Axis<D>) -> Self {
Corner::new(a.0)
}
}
#[derive(Copy, Clone, Debug)]
pub struct Corner<const D: usize>(u8);
impl<const D: usize> Corner<D> {
pub const fn new(i: u8) -> Self {
assert!(i < (1 << D));
Self(i)
}
pub fn index(self) -> usize {
self.0 as usize
}
pub fn get(self) -> u8 {
self.0
}
pub fn iter() -> impl Iterator<Item = Self> {
(0..(1 << D)).map(Corner)
}
}
impl<const D: usize> std::ops::BitAnd<Axis<D>> for Corner<D> {
type Output = bool;
fn bitand(self, rhs: Axis<D>) -> bool {
(self.0 & rhs.0) != 0
}
}
impl<const D: usize> std::ops::BitOr<Corner<D>> for Corner<D> {
type Output = Self;
fn bitor(self, rhs: Self) -> Self {
Corner::new(self.0 | rhs.0)
}
}
impl<const D: usize> std::ops::BitOr<Axis<D>> for Corner<D> {
type Output = Self;
fn bitor(self, rhs: Axis<D>) -> Self {
Corner::new(self.0 | rhs.0)
}
}
#[derive(Copy, Clone, Debug)]
pub struct DirectedEdge {
start: Corner<3>,
end: Corner<3>,
}
impl DirectedEdge {
pub const fn new(start: Corner<3>, end: Corner<3>) -> Self {
assert!(start.0 != end.0);
assert!((start.0 ^ end.0).count_ones() == 1);
Self { start, end }
}
pub fn start(self) -> Corner<3> {
self.start
}
pub fn end(self) -> Corner<3> {
self.end
}
pub fn to_undirected(self) -> Edge {
let t = Axis(self.start.0 ^ self.end.0);
let u = t.next();
let v = u.next();
#[allow(clippy::bool_to_int_with_if)]
Edge::new(
(t.0.trailing_zeros() as u8) * 4
+ if self.start & v { 2 } else { 0 }
+ if self.start & u { 1 } else { 0 },
)
}
}
#[derive(Copy, Clone, Debug)]
pub struct Edge(u8);
impl Edge {
pub const fn new(i: u8) -> Self {
assert!(i < 12);
Self(i)
}
pub fn index(&self) -> usize {
self.0 as usize
}
pub fn corners(&self) -> (Corner<3>, Corner<3>) {
use super::frame::{Frame, XYZ, YZX, ZXY};
let (t, u, v) = match self.0 / 4 {
0 => XYZ::frame(),
1 => YZX::frame(),
2 => ZXY::frame(),
_ => unreachable!("invalid edge index"),
};
#[allow(clippy::manual_is_multiple_of)]
let u = u * ((self.0 % 4) % 2 != 0);
let v = v * ((self.0 % 4) / 2 != 0);
(u | v, t | u | v)
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Offset(pub u8);
#[derive(Copy, Clone, Debug)]
pub struct Intersection {
pub vert: Offset,
pub edge: Offset,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct CellMask<const D: usize>(u8);
impl<const D: usize> CellMask<D> {
const MASK: u8 = ((1u16 << (1 << D)) - 1) as u8;
pub const fn new(i: u8) -> Self {
if i & !Self::MASK != 0 {
panic!();
}
Self(i)
}
pub fn index(&self) -> usize {
self.0 as usize
}
pub fn count_ones(&self) -> u32 {
self.0.count_ones()
}
}
impl<const N: usize> std::ops::BitAnd<Corner<N>> for CellMask<N> {
type Output = bool;
fn bitand(self, c: Corner<N>) -> bool {
(self.0 & (1 << c.index())) != 0
}
}