1use crate::{
5 primitives::bounding::BoundingBox, primitives::mesh::MeshCollection,
6 primitives::nvector::NVector,
7};
8use burn::prelude::*;
9use itertools::Itertools;
10use vtkio::model::*;
11
12pub trait ToVtk {
13 fn to_vtk(&self) -> Vtk;
14}
15
16impl<const D: usize, B: Backend> ToVtk for Tensor<B, D> {
17 fn to_vtk(&self) -> Vtk {
18 assert_eq!(self.dims()[1], 3);
19 let points: Vec<[f32; 3]> = self
20 .clone()
21 .into_data()
22 .as_slice::<f32>()
23 .unwrap()
24 .chunks(3)
25 .map(|chunk| [chunk[0], chunk[1], chunk[2]])
26 .filter(|chunk| chunk.iter().all(|&x| x < f32::MAX))
27 .collect();
28 assert!(!points.is_empty());
29 Vtk {
31 version: Version::new_legacy(2, 0),
32 title: String::from("Points"),
33 byte_order: ByteOrder::LittleEndian,
34 file_path: None,
35 data: DataSet::inline(PolyDataPiece {
36 points: points.iter().flatten().copied().collect::<Vec<_>>().into(),
37 verts: Some(VertexNumbers::XML {
38 connectivity: (0u64..points.len() as u64).collect(),
39 offsets: (1..points.len() as u64 + 1).collect(),
40 }),
41 lines: None,
42 polys: None,
43 strips: None,
44 data: Attributes {
45 point: vec![],
46 cell: vec![],
47 },
48 }),
49 }
50 }
51}
52
53fn add_bounding_box_to_polydata(
54 bbox: &BoundingBox<3>,
55 points: &mut Vec<NVector<3>>,
56 lines: &mut Vec<Vec<u64>>,
57) {
58 let start_index = points.len() as u64;
59 points.extend(bbox.corners());
61
62 let edges = [
73 (0u64, 1u64),
74 (1, 3),
75 (3, 2),
76 (2, 0), (4, 5),
78 (5, 7),
79 (7, 6),
80 (6, 4), (0, 4),
82 (1, 5),
83 (2, 6),
84 (3, 7), ];
86
87 for (a, b) in &edges {
88 lines.push(vec![start_index + a, start_index + b]);
89 }
90}
91
92impl ToVtk for MeshCollection {
93 fn to_vtk(&self) -> Vtk {
94 Vtk {
95 version: Version::new(),
96 title: "Mesh Collection".into(),
97 byte_order: ByteOrder::BigEndian,
98 data: DataSet::inline(UnstructuredGridPiece {
99 points: self
100 .vertices()
101 .flat_map(|vertex| vertex.into_iter())
102 .collect_vec()
103 .into(),
104 cells: Cells {
105 cell_verts: VertexNumbers::XML {
106 connectivity: (0u64..self.num_vertices() as u64).collect_vec(),
107 offsets: (0..self.num_triangles())
108 .map(|i| (i + 1) as u64 * 3)
109 .collect_vec(),
110 },
111 types: vec![CellType::Triangle; self.num_triangles()],
112 },
113 data: Attributes::new(),
114 }),
115 file_path: None,
116 }
117 }
118}
119
120impl ToVtk for BoundingBox<3> {
121 fn to_vtk(&self) -> Vtk {
122 let mut points = vec![];
123 let mut lines = vec![];
124
125 add_bounding_box_to_polydata(self, &mut points, &mut lines);
127
128 let data = DataSet::inline(PolyDataPiece {
129 points: points.as_flattened().iter().copied().collect_vec().into(),
130 lines: Some(VertexNumbers::XML {
131 connectivity: lines.iter().flatten().copied().collect_vec(),
132 offsets: (0..lines.len()).map(|i| (i as u64 + 1) * 2).collect_vec(),
133 }),
134 ..Default::default()
135 });
136
137 Vtk {
138 version: Version::new(),
139 title: "Bounding Box".into(),
140 byte_order: ByteOrder::BigEndian,
141 data,
142 file_path: None,
143 }
144 }
145}
146
147#[cfg(test)]
148mod tests {
149 use super::*;
150
151 use crate::primitives::mesh::{MeshCollection, Triangle, TriangleMesh};
152
153 #[test]
154 fn test_triangle_mesh_to_vtk() {
155 let vertices = Triangle::new([[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]);
156 let mesh: MeshCollection = TriangleMesh::new(vec![vertices]).into();
157 mesh.to_vtk();
158 }
159
160 #[test]
161 fn test_bounding_box_to_vtk() {
162 let bounds =
163 crate::primitives::bounding::BoundingBox::new([-1.0, -1.0, -1.0], [1.0, 1.0, 1.0]);
164 bounds.to_vtk();
165 }
166}