use crate::resources::volume_mesh::{CELL_SENTINEL, VolumeMeshData};
use crate::GlyphItem;
pub fn volume_mesh_vertex_vectors_to_glyphs(
positions: &[[f32; 3]],
vectors: &[[f32; 3]],
scale: f32,
) -> GlyphItem {
let n = positions.len().min(vectors.len());
let mut glyph_positions = Vec::with_capacity(n);
let mut glyph_vectors = Vec::with_capacity(n);
for i in 0..n {
glyph_positions.push(positions[i]);
glyph_vectors.push(vectors[i]);
}
GlyphItem {
positions: glyph_positions,
vectors: glyph_vectors,
scale,
..Default::default()
}
}
pub fn volume_mesh_cell_vectors_to_glyphs(
data: &VolumeMeshData,
cell_vectors: &[[f32; 3]],
scale: f32,
) -> GlyphItem {
let n = data.cells.len().min(cell_vectors.len());
let mut glyph_positions = Vec::with_capacity(n);
let mut glyph_vectors = Vec::with_capacity(n);
for c in 0..n {
let cell = &data.cells[c];
let valid: Vec<usize> = cell
.iter()
.filter(|&&idx| idx != CELL_SENTINEL)
.map(|&idx| idx as usize)
.filter(|&idx| idx < data.positions.len())
.collect();
if valid.is_empty() {
continue;
}
let mut centroid = [0.0f32; 3];
for &vi in &valid {
let p = data.positions[vi];
centroid[0] += p[0];
centroid[1] += p[1];
centroid[2] += p[2];
}
let inv = 1.0 / valid.len() as f32;
centroid[0] *= inv;
centroid[1] *= inv;
centroid[2] *= inv;
glyph_positions.push(centroid);
glyph_vectors.push(cell_vectors[c]);
}
GlyphItem {
positions: glyph_positions,
vectors: glyph_vectors,
scale,
..Default::default()
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashMap;
#[test]
fn vertex_vectors_length_matches() {
let positions = vec![[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]];
let vectors = vec![[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]];
let item = volume_mesh_vertex_vectors_to_glyphs(&positions, &vectors, 1.0);
assert_eq!(item.positions.len(), 2);
assert_eq!(item.vectors.len(), 2);
}
#[test]
fn vertex_vectors_mismatched_truncates() {
let positions = vec![[0.0; 3]; 5];
let vectors = vec![[1.0, 0.0, 0.0]; 3];
let item = volume_mesh_vertex_vectors_to_glyphs(&positions, &vectors, 1.0);
assert_eq!(item.positions.len(), 3);
}
#[test]
fn vertex_vectors_scale_forwarded() {
let item = volume_mesh_vertex_vectors_to_glyphs(
&[[0.0; 3]],
&[[1.0, 0.0, 0.0]],
3.5,
);
assert!((item.scale - 3.5).abs() < 1e-6);
}
#[test]
fn cell_vectors_tet_centroid() {
let data = VolumeMeshData {
positions: vec![
[0.0, 0.0, 0.0],
[4.0, 0.0, 0.0],
[0.0, 4.0, 0.0],
[0.0, 0.0, 4.0],
],
cells: vec![[0, 1, 2, 3, CELL_SENTINEL, CELL_SENTINEL, CELL_SENTINEL, CELL_SENTINEL]],
cell_scalars: HashMap::new(),
cell_colors: HashMap::new(),
};
let cell_vectors = vec![[1.0, 0.0, 0.0]];
let item = volume_mesh_cell_vectors_to_glyphs(&data, &cell_vectors, 1.0);
assert_eq!(item.positions.len(), 1);
let c = item.positions[0];
assert!((c[0] - 1.0).abs() < 1e-4);
assert!((c[1] - 1.0).abs() < 1e-4);
assert!((c[2] - 1.0).abs() < 1e-4);
}
#[test]
fn cell_vectors_empty_data() {
let data = VolumeMeshData {
positions: vec![],
cells: vec![],
cell_scalars: HashMap::new(),
cell_colors: HashMap::new(),
};
let item = volume_mesh_cell_vectors_to_glyphs(&data, &[], 1.0);
assert!(item.positions.is_empty());
}
}