Tatooine
vtp_writer.h
Go to the documentation of this file.
1#include <tatooine/edgeset.h>
2//==============================================================================
3namespace detail::edgeset {
4//==============================================================================
5template <typename MeshCont>
6auto write_container_to_vtk(MeshCont const& edgesets,
7 std::filesystem::path const& path,
8 std::string const& title = "tatooine edgeset") {
9 vtk::legacy_file_writer writer(path, vtk::dataset_type::polydata);
10 if (!writer.is_open()) {
11 return;
12 }
13 auto num_pts = std::size_t{};
14 auto cur_first = std::size_t{};
15 for (auto const& m : edgesets) {
16 num_pts += m.vertices().size();
17 }
18 auto points =
19 std::vector<std::array<typename MeshCont::value_type::real_type, 3>>{};
20 auto edges = std::vector<std::vector<std::size_t>>{};
21 points.reserve(num_pts);
22 edges.reserve(edgesets.size());
23
24 for (auto const& m : edgesets) {
25 // add points
26 for (auto const& v : m.vertices()) {
27 points.push_back(std::array{m[v](0), m[v](1), m[v](2)});
28 }
29
30 // add edges
31 for (auto s : m.simplices()) {
32 edges.emplace_back();
33 auto [v0, v1] = m[s];
34 edges.back().push_back(cur_first + v0.index());
35 edges.back().push_back(cur_first + v1.index());
36 }
37 cur_first += m.vertices().size();
38 }
39
40 // write
41 writer.set_title(title);
42 writer.write_header();
43 writer.write_points(points);
44 writer.write_polygons(edges);
45 writer.close();
46}
47//==============================================================================
48template <typename Real, std::size_t NumDimensions>
49auto write_to_vtp(edgeset<Real, NumDimensions> const& es,
50 std::filesystem::path const& path) {
51 auto file = std::ofstream{path, std::ios::binary};
52 if (!file.is_open()) {
53 throw std::runtime_error{"Could not write " + path.string()};
54 }
55 auto offset = std::size_t{};
56 using header_type = std::uint64_t;
57 using lines_connectivity_int_t = std::int32_t;
58 using lines_offset_int_t = lines_connectivity_int_t;
59 file << "<VTKFile"
60 << " type=\"PolyData\""
61 << " version=\"1.0\" "
62 "byte_order=\"LittleEndian\""
63 << " header_type=\""
64 << vtk::xml::data_array::to_string(
65 vtk::xml::data_array::to_type<header_type>())
66 << "\">";
67 file << "<PolyData>\n";
68 using real_type = typename std::decay_t<decltype(es)>::real_type;
69 file << "<Piece"
70 << " NumberOfPoints=\"" << es.vertices().size() << "\""
71 << " NumberOfPolys=\"0\""
72 << " NumberOfVerts=\"0\""
73 << " NumberOfLines=\"" << es.simplices().size() << "\""
74 << " NumberOfStrips=\"0\""
75 << ">\n";
76
77 // Points
78 file << "<Points>";
79 file << "<DataArray"
80 << " format=\"appended\""
81 << " offset=\"" << offset << "\""
82 << " type=\""
83 << vtk::xml::data_array::to_string(
84 vtk::xml::data_array::to_type<real_type>())
85 << "\" NumberOfComponents=\"3\"/>";
86 auto const num_bytes_points =
87 header_type(sizeof(real_type) * es.num_dimensions() *
88 es.vertices().data_container().size());
89 offset += num_bytes_points + sizeof(header_type);
90 file << "</Points>\n";
91
92 // Lines
93 file << "<Lines>\n";
94 // Lines - connectivity
95 file << "<DataArray format=\"appended\" offset=\"" << offset << "\" type=\""
96 << vtk::xml::data_array::to_string(
97 vtk::xml::data_array::to_type<lines_connectivity_int_t>())
98 << "\" Name=\"connectivity\"/>\n";
99 auto const num_bytes_lines_connectivity = es.simplices().size() *
100 es.num_vertices_per_simplex() *
101 sizeof(lines_connectivity_int_t);
102 offset += num_bytes_lines_connectivity + sizeof(header_type);
103
104 // Lines - offsets
105 file << "<DataArray format=\"appended\" offset=\"" << offset << "\" type=\""
106 << vtk::xml::data_array::to_string(
107 vtk::xml::data_array::to_type<lines_offset_int_t>())
108 << "\" Name=\"offsets\"/>\n";
109 auto const num_bytes_lines_offsets =
110 sizeof(lines_offset_int_t) * es.simplices().size();
111 offset += num_bytes_lines_offsets + sizeof(header_type);
112 file << "</Lines>\n";
113 file << "</Piece>\n\n";
114 file << "</PolyData>\n";
115
116 file << "<AppendedData encoding=\"raw\">_";
117 using namespace std::ranges;
118 // Writing vertex data to appended data section
119 auto const num_bytes =
120 header_type(sizeof(real_type) * 3 * es.vertices().size());
121 file.write(reinterpret_cast<char const*>(&num_bytes), sizeof(header_type));
122 if constexpr (NumDimensions == 2) {
123 auto point_data = std::vector<vec<real_type, 3>>{};
124 point_data.reserve(es.vertices().size());
125 auto position = [this](auto const v) -> auto& { return at(v); };
126 constexpr auto to_3d = [](auto const& p) {
127 return vec{p.x(), p.y(), real_type(0)};
128 };
129 for (auto const v : es.vertices()) {
130 point_data.push_back(to_3d(es[v]));
131 }
132
133 file.write(reinterpret_cast<char const*>(point_data.data()), num_bytes);
134 } else if constexpr (NumDimensions == 3) {
135 file.write(reinterpret_cast<char const*>(es.vertices().data()), num_bytes);
136 }
137 // Writing lines connectivity data to appended data section
138 {
139 auto connectivity_data = std::vector<lines_connectivity_int_t>(
140 es.simplices().size() * es.num_vertices_per_simplex());
141 copy(
142 es.simplices().data_container() |
143 std::views::transform([](auto const x) -> lines_connectivity_int_t {
144 return x.index();
145 }),
146 begin(connectivity_data));
147 arr_size = es.simplices().size() * es.num_vertices_per_simplex() *
148 sizeof(lines_connectivity_int_t);
149 file.write(reinterpret_cast<char const*>(&arr_size), sizeof(header_type));
150 file.write(reinterpret_cast<char const*>(connectivity_data.data()),
151 arr_size);
152 }
153
154 // Writing lines offsets to appended data section
155 {
156 auto offsets = std::vector<lines_offset_int_t>(
157 es.simplices().size(), es.num_vertices_per_simplex());
158 for (std::size_t i = 1; i < size(offsets); ++i) {
159 offsets[i] += offsets[i - 1];
160 }
161 arr_size = sizeof(lines_offset_int_t) * es.simplices().size();
162 file.write(reinterpret_cast<char const*>(&arr_size), sizeof(header_type));
163 file.write(reinterpret_cast<char const*>(offsets.data()), arr_size);
164 }
165 file << "</AppendedData>";
166 file << "</VTKFile>";
167}
168//==============================================================================
169auto write_container_to_vtp(range auto const& edgesets,
170 std::filesystem::path const& path) {
171 auto file = std::ofstream{path, std::ios::binary};
172 if (!file.is_open()) {
173 throw std::runtime_error{"Could not write " + path.string()};
174 }
175 auto offset = std::size_t{};
176 using header_type = std::uint64_t;
177 using lines_connectivity_int_t = std::int32_t;
178 using lines_offset_int_t = lines_connectivity_int_t;
179 file << "<VTKFile"
180 << " type=\"PolyData\""
181 << " version=\"1.0\" "
182 "byte_order=\"LittleEndian\""
183 << " header_type=\""
184 << vtk::xml::data_array::to_string(
185 vtk::xml::data_array::to_type<header_type>())
186 << "\">";
187 file << "<PolyData>\n";
188 for (auto const& g : edgesets) {
189 using real_type = typename std::decay_t<decltype(g)>::real_type;
190 file << "<Piece"
191 << " NumberOfPoints=\"" << g.vertices().size() << "\""
192 << " NumberOfPolys=\"0\""
193 << " NumberOfVerts=\"0\""
194 << " NumberOfLines=\"" << es.simplices().size() << "\""
195 << " NumberOfStrips=\"0\""
196 << ">\n";
197
198 // Points
199 file << "<Points>";
200 file << "<DataArray"
201 << " format=\"appended\""
202 << " offset=\"" << offset << "\""
203 << " type=\""
204 << vtk::xml::data_array::to_string(
205 vtk::xml::data_array::to_type<real_type>())
206 << "\" NumberOfComponents=\"" << g.num_dimensions() << "\"/>";
207 auto const num_bytes_points =
208 header_type(sizeof(real_type) * g.num_dimensions() *
209 g.vertices().data_container().size());
210 offset += num_bytes_points + sizeof(header_type);
211 file << "</Points>\n";
212
213 // Lines
214 file << "<Lines>\n";
215 // Lines - connectivity
216 file << "<DataArray format=\"appended\" offset=\"" << offset << "\" type=\""
217 << vtk::xml::data_array::to_string(
218 vtk::xml::data_array::to_type<lines_connectivity_int_t>())
219 << "\" Name=\"connectivity\"/>\n";
220 auto const num_bytes_lines_connectivity = g.simplices().size() *
221 g.num_vertices_per_simplex() *
222 sizeof(lines_connectivity_int_t);
223 offset += num_bytes_lines_connectivity + sizeof(header_type);
224
225 // Lines - offsets
226 file << "<DataArray format=\"appended\" offset=\"" << offset << "\" type=\""
227 << vtk::xml::data_array::to_string(
228 vtk::xml::data_array::to_type<lines_offset_int_t>())
229 << "\" Name=\"offsets\"/>\n";
230 auto const num_bytes_lines_offsets =
231 sizeof(lines_offset_int_t) * g.simplices().size();
232 offset += num_bytes_lines_offsets + sizeof(header_type);
233 file << "</Lines>\n";
234 file << "</Piece>\n\n";
235 }
236 file << "</PolyData>\n";
237
238 file << "<AppendedData encoding=\"raw\">_";
239 // Writing vertex data to appended data section
240 auto arr_size = header_type{};
241
242 for (auto const& g : edgesets) {
243 using real_type = typename std::decay_t<decltype(g)>::real_type;
244 arr_size = header_type(sizeof(real_type) * g.num_dimensions() *
245 g.vertices().data_container().size());
246 file.write(reinterpret_cast<char const*>(&arr_size), sizeof(header_type));
247 file.write(reinterpret_cast<char const*>(g.vertices().data()), arr_size);
248
249 // Writing lines connectivity data to appended data section
250 {
251 auto connectivity_data = std::vector<lines_connectivity_int_t>(
252 g.simplices().size() * g.num_vertices_per_simplex());
253 std::ranges::copy(g.simplices().data_container() |
254 std::views::transform(
255 [](auto const x) -> lines_connectivity_int_t {
256 return x.index();
257 }),
258 begin(connectivity_data));
259 arr_size = g.simplices().size() * g.num_vertices_per_simplex() *
260 sizeof(lines_connectivity_int_t);
261 file.write(reinterpret_cast<char const*>(&arr_size), sizeof(header_type));
262 file.write(reinterpret_cast<char const*>(connectivity_data.data()),
263 arr_size);
264 }
265
266 // Writing lines offsets to appended data section
267 {
268 auto offsets = std::vector<lines_offset_int_t>(
269 g.simplices().size(), g.num_vertices_per_simplex());
270 for (std::size_t i = 1; i < size(offsets); ++i) {
271 offsets[i] += offsets[i - 1];
272 }
273 arr_size = sizeof(lines_offset_int_t) * g.simplices().size();
274 file.write(reinterpret_cast<char const*>(&arr_size), sizeof(header_type));
275 file.write(reinterpret_cast<char const*>(offsets.data()), arr_size);
276 }
277 }
278 file << "</AppendedData>";
279 file << "</VTKFile>";
280}
281//==============================================================================
282} // namespace detail::edgeset
283//==============================================================================
Definition: vtp_writer.h:3
auto write_container_to_vtp(range auto const &edgesets, std::filesystem::path const &path)
Definition: vtp_writer.h:169
auto write_to_vtp(edgeset< Real, NumDimensions > const &es, std::filesystem::path const &path)
Definition: vtp_writer.h:49
auto write_container_to_vtk(MeshCont const &edgesets, std::filesystem::path const &path, std::string const &title="tatooine edgeset")
Definition: vtp_writer.h:6