use source::{HermiteSource, Source};
use marching_cubes_tables::CORNERS;
pub struct PointCloud {
size: usize,
layers: [Vec<f32>; 2],
}
impl PointCloud {
pub fn new(size: usize) -> Self {
PointCloud {
size,
layers: [vec![0f32; size * size], vec![0f32; size * size]],
}
}
pub fn extract_midpoints<S>(&mut self, source: &S, vertices: &mut Vec<f32>)
where
S: Source,
{
self.extract_impl(source, |x: f32, y: f32, z: f32| {
vertices.push(x);
vertices.push(y);
vertices.push(z);
});
}
pub fn extract_midpoints_with_normals<S>(&mut self, source: &S, vertices: &mut Vec<f32>)
where
S: HermiteSource,
{
self.extract_impl(source, |x: f32, y: f32, z: f32| {
let n = source.sample_normal(x, y, z);
vertices.push(x);
vertices.push(y);
vertices.push(z);
vertices.push(n.x);
vertices.push(n.y);
vertices.push(n.z);
});
}
fn extract_impl<S, E>(&mut self, source: &S, mut extract: E)
where
S: Source,
E: FnMut(f32, f32, f32) -> (),
{
let size_minus_one = self.size - 1;
let one_over_size = 1.0 / (size_minus_one as f32);
for y in 0usize..self.size {
for x in 0..self.size {
self.layers[0][y * self.size + x] =
source.sample(x as f32 * one_over_size, y as f32 * one_over_size, 0.0);
}
}
let mut values = [0f32; 8];
for z in 0..self.size {
for y in 0..self.size {
for x in 0..self.size {
self.layers[1][y * self.size + x] = source.sample(
x as f32 * one_over_size,
y as f32 * one_over_size,
(z + 1) as f32 * one_over_size,
);
}
}
for y in 0..size_minus_one {
for x in 0..size_minus_one {
for i in 0..8 {
values[i] = self.layers[CORNERS[i][2]]
[(y + CORNERS[i][1]) * self.size + x + CORNERS[i][0]];
}
let mut cube_index = 0;
for i in 0usize..8 {
if values[i] <= 0.0 {
cube_index |= 1 << i;
}
}
if cube_index == 0 || cube_index == 255 {
continue;
}
let px = (x as f32 + 0.5) * one_over_size;
let py = (y as f32 + 0.5) * one_over_size;
let pz = (z as f32 + 0.5) * one_over_size;
extract(px, py, pz);
}
}
self.layers.swap(0, 1);
}
}
}