use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct IndexedPoint3D {
pub x: f64,
pub y: f64,
pub z: f64,
pub row_id: u64,
}
impl IndexedPoint3D {
pub fn from_point3d(p: &crate::types::Point3D, row_id: u64) -> Self {
Self {
x: p.x,
y: p.y,
z: p.z,
row_id,
}
}
pub fn distance_squared(&self, other: &[f64; 3]) -> f64 {
let dx = self.x - other[0];
let dy = self.y - other[1];
let dz = self.z - other[2];
dx * dx + dy * dy + dz * dz
}
pub fn as_array(&self) -> [f64; 3] {
[self.x, self.y, self.z]
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Octant {
Inner {
center: [f64; 3],
extent: f64,
children: Box<[Option<Box<Octant>>; 8]>,
size: usize,
},
Leaf {
center: [f64; 3],
extent: f64,
leaf_id: u64,
point_count: u32,
},
}
pub fn octant_code(center: &[f64; 3], point: &[f64; 3]) -> usize {
let mut code = 0u8;
if point[0] >= center[0] {
code |= 1;
}
if point[1] >= center[1] {
code |= 2;
}
if point[2] >= center[2] {
code |= 4;
}
code as usize
}
pub fn child_center(parent_center: &[f64; 3], parent_extent: f64, code: usize) -> [f64; 3] {
let half = parent_extent / 2.0;
let mut center = *parent_center;
if code & 1 != 0 {
center[0] += half;
} else {
center[0] -= half;
}
if code & 2 != 0 {
center[1] += half;
} else {
center[1] -= half;
}
if code & 4 != 0 {
center[2] += half;
} else {
center[2] -= half;
}
center
}
impl Octant {
pub fn new_leaf(center: [f64; 3], extent: f64, leaf_id: u64) -> Self {
Octant::Leaf {
center,
extent,
leaf_id,
point_count: 0,
}
}
pub fn new_inner(center: [f64; 3], extent: f64) -> Self {
Octant::Inner {
center,
extent,
children: Box::new([None, None, None, None, None, None, None, None]),
size: 0,
}
}
pub fn size(&self) -> usize {
match self {
Octant::Inner { size, .. } => *size,
Octant::Leaf { point_count, .. } => *point_count as usize,
}
}
pub fn extent(&self) -> f64 {
match self {
Octant::Inner { extent, .. } | Octant::Leaf { extent, .. } => *extent,
}
}
pub fn center(&self) -> &[f64; 3] {
match self {
Octant::Inner { center, .. } | Octant::Leaf { center, .. } => center,
}
}
pub fn leaf_id(&self) -> Option<u64> {
match self {
Octant::Leaf { leaf_id, .. } => Some(*leaf_id),
_ => None,
}
}
pub fn recount_size(&mut self) {
if let Octant::Inner { children, size, .. } = self {
*size = 0;
for c in children.iter().flatten() {
*size += c.size();
}
}
}
pub fn memory_usage(&self) -> usize {
match self {
Octant::Leaf { .. } => std::mem::size_of::<Octant>(),
Octant::Inner { children, .. } => {
let mut total = std::mem::size_of::<Octant>();
for c in children.iter().flatten() {
total += c.memory_usage();
}
total
}
}
}
}
pub fn overlaps(center: &[f64; 3], extent: f64, min: &[f64; 3], max: &[f64; 3]) -> bool {
center[0] + extent >= min[0]
&& center[0] - extent <= max[0]
&& center[1] + extent >= min[1]
&& center[1] - extent <= max[1]
&& center[2] + extent >= min[2]
&& center[2] - extent <= max[2]
}
pub fn min_dist_sq_to_octant(center: &[f64; 3], extent: f64, point: &[f64; 3]) -> f64 {
let mut dist_sq = 0.0f64;
for i in 0..3 {
let lo = center[i] - extent;
let hi = center[i] + extent;
if point[i] < lo {
dist_sq += (point[i] - lo).powi(2);
} else if point[i] > hi {
dist_sq += (point[i] - hi).powi(2);
}
}
dist_sq
}