use super::children::*;
use std::fmt::{Debug, Formatter};
use std::fmt;
use std::cmp::{min, max};
use num::abs;
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct OctCoord {
base: BaseCoord,
scale: u8
}
impl OctCoord {
pub fn suboctant(self, coord: BaseCoord) -> Option<SubOctant> {
if
childnt(self.base.comps[0], self.scale, coord.comps[0]) ||
childnt(self.base.comps[1], self.scale, coord.comps[1]) ||
childnt(self.base.comps[2], self.scale, coord.comps[2]) {
None
} else {
let x = Pole::from_bit((coord.comps[0] >> (self.scale - 1)) & 0x1).unwrap();
let y = Pole::from_bit((coord.comps[1] >> (self.scale - 1)) & 0x1).unwrap();
let z = Pole::from_bit((coord.comps[2] >> (self.scale - 1)) & 0x1).unwrap();
Some(SubOctant::new([x, y, z]))
}
}
pub fn to_base(self) -> BaseCoord {
let x = self.base.comps[0] << self.scale;
let y = self.base.comps[1] << self.scale;
let z = self.base.comps[2] << self.scale;
BaseCoord {
comps: [x, y, z]
}
}
pub fn closest_suboctant(self, coord: BaseCoord) -> SubOctant {
let x = closest_pole(self.base.comps[0], self.scale, coord.comps[0]);
let y = closest_pole(self.base.comps[1], self.scale, coord.comps[1]);
let z = closest_pole(self.base.comps[2], self.scale, coord.comps[2]);
SubOctant::new([x, y, z])
}
}
impl Debug for OctCoord {
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
f.write_str(&format!("{:?}*2^{}", self.base, self.scale))
}
}
fn closest_pole(oct_comp: u64, oct_scale: u8, base_comp: u64) -> Pole {
let max_bit = 0x1 << 63;
let mut oct_comp = oct_comp << oct_scale;
let mut base_comp = base_comp;
for _ in 0..min(64 - oct_scale, 63) {
if (oct_comp & max_bit) != (base_comp & max_bit) {
return Pole::from_bit((base_comp & max_bit) >> 63).unwrap();
}
oct_comp <<= 1;
base_comp <<= 1;
}
Pole::from_bit((base_comp & max_bit) >> 63).unwrap()
}
fn childnt(scaled_comp: u64, scale: u8, base_comp: u64) -> bool {
(base_comp >> scale) != scaled_comp
}
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct BaseCoord {
pub comps: [u64; 3]
}
impl BaseCoord {
pub fn lowest_common_octant(self, other: BaseCoord) -> OctCoord {
let (x_comp, x_scale) = commonize_component(self.comps[0], other.comps[0]);
let (y_comp, y_scale) = commonize_component(self.comps[1], other.comps[1]);
let (z_comp, z_scale) = commonize_component(self.comps[2], other.comps[2]);
let scale = max(max(x_scale, y_scale), z_scale);
let x = x_comp >> (scale - x_scale);
let y = y_comp >> (scale - y_scale);
let z = z_comp >> (scale - z_scale);
OctCoord {
base: BaseCoord {
comps: [x, y, z],
},
scale
}
}
pub fn manhattan_dist(self, other: BaseCoord) -> u64 {
abs(self.comps[0] as i64 - other.comps[0] as i64) as u64 +
abs(self.comps[1] as i64 - other.comps[1] as i64) as u64 +
abs(self.comps[2] as i64 - other.comps[2] as i64) as u64
}
}
impl Debug for BaseCoord {
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
f.write_str(&format!("[{},{},{}]", self.comps[0], self.comps[1], self.comps[2]))
}
}
impl From<[u64; 3]> for BaseCoord {
fn from(comps: [u64; 3]) -> Self {
BaseCoord {
comps
}
}
}
impl Into<[u64; 3]> for BaseCoord {
fn into(self) -> [u64; 3] {
self.comps
}
}
fn commonize_component(mut a: u64, mut b: u64) -> (u64, u8) {
let mut scale = 0;
while a != b {
scale += 1;
a >>= 1;
b >>= 1;
}
(a, scale)
}