Skip to main content

vtk_pure_rs/data/
unstructured_grid.rs

1use crate::types::{BoundingBox, CellType};
2
3use crate::data::{CellArray, DataSetAttributes, FieldData, Points};
4use crate::data::traits::{DataObject, DataSet};
5
6/// Arbitrary mixed-cell mesh with explicit point coordinates and cell connectivity.
7///
8/// Analogous to VTK's `vtkUnstructuredGrid`. Each cell has a type (from `CellType`)
9/// and point connectivity stored in a shared `CellArray`. Cell types are stored in
10/// a parallel array.
11#[derive(Debug, Clone, Default)]
12pub struct UnstructuredGrid {
13    pub points: Points<f64>,
14    cells: CellArray,
15    cell_types: Vec<CellType>,
16    point_data: DataSetAttributes,
17    cell_data: DataSetAttributes,
18    field_data: FieldData,
19}
20
21impl UnstructuredGrid {
22    pub fn new() -> Self {
23        Self::default()
24    }
25
26    /// Add a cell with the given type and point indices.
27    pub fn push_cell(&mut self, cell_type: CellType, point_ids: &[i64]) {
28        self.cells.push_cell(point_ids);
29        self.cell_types.push(cell_type);
30    }
31
32    /// Get the type of cell at the given index.
33    pub fn cell_type(&self, idx: usize) -> CellType {
34        self.cell_types[idx]
35    }
36
37    /// Get the point indices for cell at the given index.
38    pub fn cell_points(&self, idx: usize) -> &[i64] {
39        self.cells.cell(idx)
40    }
41
42    /// Get all cell types.
43    pub fn cell_types(&self) -> &[CellType] {
44        &self.cell_types
45    }
46
47    /// Get the underlying cell array.
48    pub fn cells(&self) -> &CellArray {
49        &self.cells
50    }
51
52    pub fn point_data(&self) -> &DataSetAttributes {
53        &self.point_data
54    }
55
56    pub fn point_data_mut(&mut self) -> &mut DataSetAttributes {
57        &mut self.point_data
58    }
59
60    pub fn cell_data(&self) -> &DataSetAttributes {
61        &self.cell_data
62    }
63
64    pub fn cell_data_mut(&mut self) -> &mut DataSetAttributes {
65        &mut self.cell_data
66    }
67
68    /// Create from points and tetrahedra.
69    pub fn from_tetrahedra(points: Vec<[f64; 3]>, tets: Vec<[i64; 4]>) -> Self {
70        let mut ug = Self::new();
71        ug.points = Points::from_vec(points);
72        for tet in &tets {
73            ug.push_cell(CellType::Tetra, tet);
74        }
75        ug
76    }
77
78    /// Create from points and hexahedra.
79    pub fn from_hexahedra(points: Vec<[f64; 3]>, hexes: Vec<[i64; 8]>) -> Self {
80        let mut ug = Self::new();
81        ug.points = Points::from_vec(points);
82        for hex in &hexes {
83            ug.push_cell(CellType::Hexahedron, hex);
84        }
85        ug
86    }
87
88    /// Builder: add a point data array.
89    pub fn with_point_array(mut self, array: crate::data::AnyDataArray) -> Self {
90        let name = array.name().to_string();
91        self.point_data.add_array(array);
92        if self.point_data.scalars().is_none() {
93            self.point_data.set_active_scalars(&name);
94        }
95        self
96    }
97
98    /// Builder: add a cell data array.
99    pub fn with_cell_array(mut self, array: crate::data::AnyDataArray) -> Self {
100        self.cell_data.add_array(array);
101        self
102    }
103}
104
105impl DataObject for UnstructuredGrid {
106    fn field_data(&self) -> &FieldData {
107        &self.field_data
108    }
109
110    fn field_data_mut(&mut self) -> &mut FieldData {
111        &mut self.field_data
112    }
113}
114
115impl DataSet for UnstructuredGrid {
116    fn num_points(&self) -> usize {
117        self.points.len()
118    }
119
120    fn num_cells(&self) -> usize {
121        self.cells.num_cells()
122    }
123
124    fn point(&self, idx: usize) -> [f64; 3] {
125        self.points.get(idx)
126    }
127
128    fn bounds(&self) -> BoundingBox {
129        self.points.bounds()
130    }
131
132    fn point_data(&self) -> &DataSetAttributes {
133        &self.point_data
134    }
135
136    fn point_data_mut(&mut self) -> &mut DataSetAttributes {
137        &mut self.point_data
138    }
139
140    fn cell_data(&self) -> &DataSetAttributes {
141        &self.cell_data
142    }
143
144    fn cell_data_mut(&mut self) -> &mut DataSetAttributes {
145        &mut self.cell_data
146    }
147}
148
149impl std::fmt::Display for UnstructuredGrid {
150    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
151        write!(f, "UnstructuredGrid: {} points, {} cells, {} point arrays",
152            self.points.len(), self.cells.num_cells(), self.point_data.num_arrays())
153    }
154}
155
156#[cfg(test)]
157mod tests {
158    use super::*;
159
160    #[test]
161    fn single_tetrahedron() {
162        let mut grid = UnstructuredGrid::new();
163        grid.points.push([0.0, 0.0, 0.0]);
164        grid.points.push([1.0, 0.0, 0.0]);
165        grid.points.push([0.5, 1.0, 0.0]);
166        grid.points.push([0.5, 0.5, 1.0]);
167
168        grid.push_cell(CellType::Tetra, &[0, 1, 2, 3]);
169
170        assert_eq!(grid.num_points(), 4);
171        assert_eq!(grid.num_cells(), 1);
172        assert_eq!(grid.cell_type(0), CellType::Tetra);
173        assert_eq!(grid.cell_points(0), &[0, 1, 2, 3]);
174    }
175
176    #[test]
177    fn mixed_cells() {
178        let mut grid = UnstructuredGrid::new();
179        for i in 0..8 {
180            let x = (i % 2) as f64;
181            let y = ((i / 2) % 2) as f64;
182            let z = (i / 4) as f64;
183            grid.points.push([x, y, z]);
184        }
185
186        // A hexahedron
187        grid.push_cell(CellType::Hexahedron, &[0, 1, 3, 2, 4, 5, 7, 6]);
188        // A triangle on the top face
189        grid.push_cell(CellType::Triangle, &[4, 5, 7]);
190
191        assert_eq!(grid.num_cells(), 2);
192        assert_eq!(grid.cell_type(0), CellType::Hexahedron);
193        assert_eq!(grid.cell_type(1), CellType::Triangle);
194    }
195}