use std::{marker::PhantomData, ops::Range};
use crate::{Icosphere, IcosphereVertex, triangle_count};
#[derive(Debug, Clone)]
pub struct IcosphereLevels<T, S>
where
T: IcosphereVertex,
S: Icosphere<T>,
{
levels: Vec<S>,
pub min_binning_depth: usize,
pub max_binning_depth: usize,
pub binning_depth_step: usize,
_phantom: PhantomData<T>,
}
impl<T, S> IcosphereLevels<T, S>
where
T: IcosphereVertex,
S: Icosphere<T>,
{
pub fn new(min_binning_depth: usize, level_count: usize, binning_depth_step: usize) -> Self {
let max_binning_depth = min_binning_depth + (level_count - 1) * binning_depth_step;
let mut levels = Vec::with_capacity(max_binning_depth - min_binning_depth + 1);
for binning_depth in min_binning_depth..=max_binning_depth {
levels.push(S::create(binning_depth));
}
Self {
levels,
min_binning_depth,
max_binning_depth,
binning_depth_step,
_phantom: PhantomData,
}
}
pub fn get(&self, level: usize) -> &S {
&self.levels[level * self.binning_depth_step]
}
pub fn get_mut(&mut self, level: usize) -> &mut S {
&mut self.levels[level * self.binning_depth_step]
}
pub fn flattened_chunk_indices(&self, level: usize, chunk_index: usize) -> Vec<u32> {
let mut indices = vec![0u32; 3 * self.chunk_size()]; let subchunk_indices = self.subchunk_indices(chunk_index);
for triangle_index in subchunk_indices {
let ico = self.get(level);
indices[(triangle_index * 3)..(triangle_index * 3 + 3)]
.copy_from_slice(&ico.triangle(triangle_index));
}
indices
}
pub fn binning_depth_at_level(&self, level: usize) -> usize {
self.min_binning_depth + level * self.binning_depth_step
}
pub fn level_of_binning_depth(&self, binning_depth: usize) -> Option<usize> {
if binning_depth < self.min_binning_depth
|| binning_depth >= self.binning_depth_at_level(self.levels.len())
|| (binning_depth - self.min_binning_depth) % self.binning_depth_step != 0
{
return None;
}
Some((binning_depth - self.min_binning_depth) / self.binning_depth_step)
}
pub fn level_count(&self) -> usize {
((self.max_binning_depth - self.min_binning_depth) / self.binning_depth_step) + 1
}
pub fn chunk_size(&self) -> usize {
1 << (2 * self.binning_depth_step)
}
pub fn chunk_count(&self, level: usize) -> usize {
if self.binning_depth_at_level(level) == 0 {
triangle_count(0)
} else {
let binning_depth = self.binning_depth_at_level(level - 1);
triangle_count(binning_depth)
}
}
pub fn subchunk_indices(&self, chunk_index: usize) -> Range<usize> {
let size = self.chunk_size();
let start = chunk_index * size;
let end = start + size;
start..end
}
pub fn chunk_indices(&self, level: usize) -> Range<usize> {
0..self.chunk_count(level)
}
}