honeycomb_core/cmap/dim2/
serialize.rs1use std::{any::TypeId, collections::BTreeMap};
2
3use vtkio::{
4 model::{
5 ByteOrder, CellType, DataSet, Piece, UnstructuredGridPiece, Version, VertexNumbers, Vtk,
6 },
7 IOBuffer,
8};
9
10use crate::cmap::{
11 CMap2, DartIdType, EdgeIdType, FaceIdType, Orbit2, OrbitPolicy, VertexIdType, NULL_DART_ID,
12};
13use crate::geometry::CoordsFloat;
14
15impl<T: CoordsFloat + 'static> CMap2<T> {
17 pub fn serialize(&self, mut writer: impl std::fmt::Write) {
27 let n_darts = self.n_darts();
28 writeln!(writer, "[META]").expect("E: couldn't write to file");
29 writeln!(
30 writer,
31 "{} {} {}",
32 env!("CARGO_PKG_VERSION"), 2,
34 n_darts - 1
35 )
36 .expect("E: couldn't write to file");
37 writeln!(writer).expect("E: couldn't write to file"); writeln!(writer, "[BETAS]").expect("E: couldn't write to file");
40 let width = n_darts.to_string().len();
41 let mut b0 = String::with_capacity(n_darts * 2);
42 let mut b1 = String::with_capacity(n_darts * 2);
43 let mut b2 = String::with_capacity(n_darts * 2);
44 std::thread::scope(|s| {
45 s.spawn(|| {
46 use std::fmt::Write;
48 let mut buf = String::new();
49 (0..n_darts as DartIdType).for_each(|d| {
50 write!(&mut buf, "{:>width$} ", self.beta::<0>(d))
51 .expect("E: couldn't write to file");
52 b0.push_str(buf.as_str());
53 buf.clear();
54 });
55 });
56 s.spawn(|| {
57 use std::fmt::Write;
59 let mut buf = String::new();
60 (0..n_darts as DartIdType).for_each(|d| {
61 write!(&mut buf, "{:>width$} ", self.beta::<1>(d))
62 .expect("E: couldn't write to file");
63 b1.push_str(buf.as_str());
64 buf.clear();
65 });
66 });
67 s.spawn(|| {
68 use std::fmt::Write;
70 let mut buf = String::new();
71 (0..n_darts as DartIdType).for_each(|d| {
72 write!(&mut buf, "{:>width$} ", self.beta::<2>(d))
73 .expect("E: couldn't write to file");
74 b2.push_str(buf.as_str());
75 buf.clear();
76 });
77 });
78 });
79 writeln!(writer, "{}", b0.trim()).expect("E: couldn't write to file");
80 writeln!(writer, "{}", b1.trim()).expect("E: couldn't write to file");
81 writeln!(writer, "{}", b2.trim()).expect("E: couldn't write to file");
82 writeln!(writer).expect("E: couldn't write to file"); writeln!(writer, "[UNUSED]").expect("E: couldn't write to file");
85 self.unused_darts
86 .iter()
87 .enumerate()
88 .filter(|(_, v)| v.read_atomic())
89 .for_each(|(i, _)| {
90 write!(writer, "{i} ").unwrap();
91 });
92 writeln!(writer).expect("E: couldn't write to file"); writeln!(writer).expect("E: couldn't write to file"); writeln!(writer, "[VERTICES]").expect("E: couldn't write to file");
96 self.iter_vertices().for_each(|v| {
97 if let Some(val) = self.force_read_vertex(v) {
98 writeln!(
99 writer,
100 "{v} {} {}",
101 val.0.to_f64().unwrap(),
102 val.1.to_f64().unwrap(),
103 )
104 .expect("E: couldn't write to file");
105 }
106 });
107 }
108
109 pub fn to_vtk_binary(&self, writer: impl std::io::Write) {
119 let vtk_struct = Vtk {
121 version: Version::Legacy { major: 2, minor: 0 },
122 title: "cmap".to_string(),
123 byte_order: ByteOrder::BigEndian,
124 data: DataSet::UnstructuredGrid {
125 meta: None,
126 pieces: vec![Piece::Inline(Box::new(build_unstructured_piece(self)))],
127 },
128 file_path: None,
129 };
130
131 vtk_struct
133 .write_legacy(writer)
134 .expect("E: could not write data to writer");
135 }
136
137 pub fn to_vtk_ascii(&self, writer: impl std::fmt::Write) {
145 let vtk_struct = Vtk {
147 version: Version::Legacy { major: 2, minor: 0 },
148 title: "cmap".to_string(),
149 byte_order: ByteOrder::BigEndian,
150 data: DataSet::UnstructuredGrid {
151 meta: None,
152 pieces: vec![Piece::Inline(Box::new(build_unstructured_piece(self)))],
153 },
154 file_path: None,
155 };
156
157 vtk_struct
159 .write_legacy_ascii(writer)
160 .expect("E: could not write data to writer");
161 }
162}
163
164fn build_unstructured_piece<T>(map: &CMap2<T>) -> UnstructuredGridPiece
166where
167 T: CoordsFloat + 'static,
168{
169 let vertex_ids: Vec<VertexIdType> = map.iter_vertices().collect();
171 let mut id_map: BTreeMap<VertexIdType, usize> = BTreeMap::new();
172 vertex_ids.iter().enumerate().for_each(|(id, vid)| {
173 id_map.insert(*vid, id);
174 });
175 let vertices = vertex_ids
177 .iter()
178 .map(|vid| {
179 map.force_read_vertex(*vid)
180 .expect("E: found a topological vertex with no associated coordinates")
181 })
182 .flat_map(|v| [v.x(), v.y(), T::zero()].into_iter());
183 let mut n_cells = 0;
185 let face_ids: Vec<FaceIdType> = map.iter_faces().collect();
187 let face_data = face_ids.into_iter().map(|id| {
188 let mut count: u32 = 0;
189 let orbit: Vec<u32> = Orbit2::new(map, OrbitPolicy::Custom(&[1]), id as DartIdType)
191 .map(|dart_id| {
192 count += 1;
193 id_map[&map.vertex_id(dart_id)] as u32
194 })
195 .collect();
196 (count, orbit)
197 });
198
199 let edge_ids: Vec<EdgeIdType> = map.iter_edges().collect();
201 let edge_data = edge_ids
204 .into_iter()
205 .filter(|id| map.beta::<2>(*id as DartIdType) == NULL_DART_ID)
206 .map(|id| {
207 let dart_id = id as DartIdType;
208 let ndart_id = map.beta::<1>(dart_id);
209 (
210 id_map[&map.vertex_id(dart_id)] as u32,
211 id_map[&map.vertex_id(ndart_id)] as u32,
212 )
213 });
214
215 let mut cell_vertices: Vec<u32> = Vec::new();
219 let mut cell_types: Vec<CellType> = Vec::new();
220
221 edge_data.for_each(|(v1, v2)| {
222 cell_types.push(CellType::Line);
223 cell_vertices.extend([2_u32, v1, v2]);
224 n_cells += 1;
225 });
226
227 face_data.for_each(|(count, mut elements)| {
228 cell_types.push(match count {
229 0..=2 => return, 3 => CellType::Triangle,
231 4 => CellType::Quad,
232 5.. => CellType::Polygon,
233 });
234 cell_vertices.push(count);
235 cell_vertices.append(&mut elements);
236 n_cells += 1;
237 });
238
239 UnstructuredGridPiece {
240 points: if TypeId::of::<T>() == TypeId::of::<f32>() {
241 IOBuffer::F32(
242 vertices
243 .map(|t| t.to_f32().expect("E: unreachable"))
244 .collect(),
245 )
246 } else if TypeId::of::<T>() == TypeId::of::<f64>() {
247 IOBuffer::F64(
248 vertices
249 .map(|t| t.to_f64().expect("E: unreachable"))
250 .collect(),
251 )
252 } else {
253 println!("W: unrecognized coordinate type -- cast to f64 might fail");
254 IOBuffer::F64(
255 vertices
256 .map(|t| t.to_f64().expect("E: unreachable"))
257 .collect(),
258 )
259 },
260 cells: vtkio::model::Cells {
261 cell_verts: VertexNumbers::Legacy {
262 num_cells: n_cells,
263 vertices: cell_vertices,
264 },
265 types: cell_types,
266 },
267 data: vtkio::model::Attributes::default(),
268 }
269}