use crate::data::{DataSetAttributes, FieldData, Points};
use crate::types::{BoundingBox, VtkError};
#[derive(Debug, Clone)]
pub struct ExplicitStructuredGrid {
dimensions: [usize; 3],
pub points: Points<f64>,
cell_visibility: Vec<bool>,
point_data: DataSetAttributes,
cell_data: DataSetAttributes,
field_data: FieldData,
}
impl ExplicitStructuredGrid {
pub fn new(dims: [usize; 3]) -> Self {
let num_cells = (dims[0].saturating_sub(1))
* (dims[1].saturating_sub(1))
* (dims[2].saturating_sub(1));
Self {
dimensions: dims,
points: Points::new(),
cell_visibility: vec![true; num_cells],
point_data: DataSetAttributes::new(),
cell_data: DataSetAttributes::new(),
field_data: FieldData::new(),
}
}
pub fn from_points(dims: [usize; 3], points: Points<f64>) -> Result<Self, VtkError> {
let expected = dims[0] * dims[1] * dims[2];
if points.len() != expected {
return Err(VtkError::InvalidData(format!(
"expected {} points for {:?} grid, got {}",
expected, dims, points.len()
)));
}
let mut grid = Self::new(dims);
grid.points = points;
Ok(grid)
}
pub fn dimensions(&self) -> [usize; 3] {
self.dimensions
}
pub fn num_points(&self) -> usize {
self.dimensions[0] * self.dimensions[1] * self.dimensions[2]
}
pub fn num_cells(&self) -> usize {
(self.dimensions[0].saturating_sub(1))
* (self.dimensions[1].saturating_sub(1))
* (self.dimensions[2].saturating_sub(1))
}
pub fn num_visible_cells(&self) -> usize {
self.cell_visibility.iter().filter(|&&v| v).count()
}
pub fn blank_cell(&mut self, i: usize, j: usize, k: usize) {
let idx = self.cell_index(i, j, k);
if idx < self.cell_visibility.len() {
self.cell_visibility[idx] = false;
}
}
pub fn unblank_cell(&mut self, i: usize, j: usize, k: usize) {
let idx = self.cell_index(i, j, k);
if idx < self.cell_visibility.len() {
self.cell_visibility[idx] = true;
}
}
pub fn is_cell_visible(&self, i: usize, j: usize, k: usize) -> bool {
let idx = self.cell_index(i, j, k);
idx < self.cell_visibility.len() && self.cell_visibility[idx]
}
pub fn cell_visibility(&self) -> &[bool] {
&self.cell_visibility
}
pub fn set_cell_visibility(&mut self, vis: Vec<bool>) {
self.cell_visibility = vis;
}
pub fn cell_index(&self, i: usize, j: usize, k: usize) -> usize {
let ni = self.dimensions[0].saturating_sub(1);
let nj = self.dimensions[1].saturating_sub(1);
k * ni * nj + j * ni + i
}
pub fn point_index(&self, i: usize, j: usize, k: usize) -> usize {
let ni = self.dimensions[0];
let nj = self.dimensions[1];
k * ni * nj + j * ni + i
}
pub fn cell_point_ids(&self, i: usize, j: usize, k: usize) -> [usize; 8] {
[
self.point_index(i, j, k),
self.point_index(i + 1, j, k),
self.point_index(i + 1, j + 1, k),
self.point_index(i, j + 1, k),
self.point_index(i, j, k + 1),
self.point_index(i + 1, j, k + 1),
self.point_index(i + 1, j + 1, k + 1),
self.point_index(i, j + 1, k + 1),
]
}
pub fn bounds(&self) -> BoundingBox {
let mut bb = BoundingBox {
x_min: f64::INFINITY,
x_max: f64::NEG_INFINITY,
y_min: f64::INFINITY,
y_max: f64::NEG_INFINITY,
z_min: f64::INFINITY,
z_max: f64::NEG_INFINITY,
};
for i in 0..self.points.len() {
let p = self.points.get(i);
bb.x_min = bb.x_min.min(p[0]);
bb.x_max = bb.x_max.max(p[0]);
bb.y_min = bb.y_min.min(p[1]);
bb.y_max = bb.y_max.max(p[1]);
bb.z_min = bb.z_min.min(p[2]);
bb.z_max = bb.z_max.max(p[2]);
}
bb
}
pub fn point_data(&self) -> &DataSetAttributes {
&self.point_data
}
pub fn point_data_mut(&mut self) -> &mut DataSetAttributes {
&mut self.point_data
}
pub fn cell_data(&self) -> &DataSetAttributes {
&self.cell_data
}
pub fn cell_data_mut(&mut self) -> &mut DataSetAttributes {
&mut self.cell_data
}
pub fn field_data(&self) -> &FieldData {
&self.field_data
}
pub fn field_data_mut(&mut self) -> &mut FieldData {
&mut self.field_data
}
}
#[cfg(test)]
mod tests {
use super::*;
fn make_grid_2x2x2() -> ExplicitStructuredGrid {
let dims = [2, 2, 2];
let mut pts = Points::new();
for k in 0..2 {
for j in 0..2 {
for i in 0..2 {
pts.push([i as f64, j as f64, k as f64]);
}
}
}
ExplicitStructuredGrid::from_points(dims, pts).unwrap()
}
#[test]
fn basic_grid() {
let g = make_grid_2x2x2();
assert_eq!(g.num_points(), 8);
assert_eq!(g.num_cells(), 1);
assert_eq!(g.num_visible_cells(), 1);
}
#[test]
fn blanking() {
let mut g = ExplicitStructuredGrid::new([3, 3, 3]);
assert_eq!(g.num_cells(), 8);
assert_eq!(g.num_visible_cells(), 8);
g.blank_cell(0, 0, 0);
assert_eq!(g.num_visible_cells(), 7);
assert!(!g.is_cell_visible(0, 0, 0));
assert!(g.is_cell_visible(1, 0, 0));
g.unblank_cell(0, 0, 0);
assert_eq!(g.num_visible_cells(), 8);
}
#[test]
fn cell_point_ids() {
let g = ExplicitStructuredGrid::new([3, 3, 2]);
let ids = g.cell_point_ids(0, 0, 0);
assert_eq!(ids[0], 0);
assert_eq!(ids[1], 1);
}
#[test]
fn point_count_mismatch() {
let pts = Points::new();
let result = ExplicitStructuredGrid::from_points([3, 3, 3], pts);
assert!(result.is_err());
}
#[test]
fn bounds() {
let g = make_grid_2x2x2();
let bb = g.bounds();
assert_eq!(bb.x_min, 0.0);
assert_eq!(bb.x_max, 1.0);
}
}