Tatooine
unstructured_simplicial_grid.h
Go to the documentation of this file.
1#ifndef TATOOINE_UNSTRUCTURED_SIMPLICIAL_GRID_H
2#define TATOOINE_UNSTRUCTURED_SIMPLICIAL_GRID_H
3//==============================================================================
4#if TATOOINE_CDT_AVAILABLE
5#include <CDT.h>
6#endif
7#if TATOOINE_CGAL_AVAILABLE
8#include <tatooine/cgal.h>
9#endif
10
11#include <tatooine/available_libraries.h>
18#include <tatooine/pointset.h>
19#include <tatooine/property.h>
22#include <tatooine/vtk_legacy.h>
23
24#include <boost/range/adaptor/transformed.hpp>
25#include <boost/range/algorithm/copy.hpp>
26#include <filesystem>
27#include <vector>
28//==============================================================================
30//==============================================================================
31template <floating_point Real, std::size_t NumDimensions,
32 std::size_t SimplexDim>
33struct simplex_container;
34//==============================================================================
35template <floating_point Real, std::size_t NumDimensions,
36 std::size_t SimplexDim, typename T>
37struct vertex_property_sampler;
38//==============================================================================
39template <typename Mesh, floating_point Real, std::size_t NumDimensions,
40 std::size_t SimplexDim>
41struct parent;
42//==============================================================================
43} // namespace tatooine::detail::unstructured_simplicial_grid
44//==============================================================================
45namespace tatooine {
46//==============================================================================
47template <floating_point Real, std::size_t NumDimensions,
48 std::size_t SimplexDim = NumDimensions>
51 unstructured_simplicial_grid<Real, NumDimensions, SimplexDim>, Real,
52 NumDimensions, SimplexDim> {
53 using this_type =
55 using real_type = Real;
58 NumDimensions, SimplexDim>;
59 template <typename T>
62 Real, NumDimensions, SimplexDim, T>;
64 this_type, Real, NumDimensions, SimplexDim>;
65 using parent_type::at;
67 using typename parent_type::pos_type;
68 using typename parent_type::vertex_handle;
69 using parent_type::operator[];
76
79
80 template <typename T>
82 typename parent_type::template typed_vertex_property_type<T>;
84 static constexpr auto num_vertices_per_simplex() { return SimplexDim + 1; }
85 static constexpr auto simplex_dimension() { return SimplexDim; }
86 //----------------------------------------------------------------------------
87 struct simplex_handle : handle<simplex_handle> {
89 };
90 //----------------------------------------------------------------------------
93 Real, NumDimensions, SimplexDim>;
95 Real, NumDimensions, SimplexDim>;
96 //----------------------------------------------------------------------------
97 template <typename T>
100 std::map<std::string, std::unique_ptr<vector_property<simplex_handle>>>;
101 //============================================================================
102 private:
103 std::vector<vertex_handle> m_simplex_index_data;
104 std::set<simplex_handle> m_invalid_simplices;
106 mutable std::unique_ptr<hierarchy_type> m_hierarchy;
107
108 public:
109 //============================================================================
110 // GETTER
111 //============================================================================
112 auto simplex_index_data() const -> auto const& {
114 }
115 auto invalid_simplices() const -> auto const& { return m_invalid_simplices; }
116 auto simplex_properties() const -> auto const& {
118 }
119
120 //============================================================================
121 constexpr unstructured_simplicial_grid() = default;
122 //============================================================================
125 for (auto const& [key, prop] : other.simplex_properties()) {
126 m_simplex_properties.insert(std::pair{key, prop->clone()});
127 }
128 }
129 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
131 default;
132 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
136 m_simplex_properties.clear();
137 m_simplex_index_data = other.m_simplex_index_data;
138 for (auto const& [key, prop] : other.simplex_properties()) {
139 m_simplex_properties.insert(std::pair{key, prop->clone()});
140 }
141 return *this;
142 }
143 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
145 -> unstructured_simplicial_grid& = default;
146 //----------------------------------------------------------------------------
147 explicit unstructured_simplicial_grid(std::filesystem::path const& path) {
148 read(path);
149 }
150 //----------------------------------------------------------------------------
151 unstructured_simplicial_grid(std::initializer_list<pos_type>&& vertices)
152 : parent_type{std::move(vertices)} {}
153 //----------------------------------------------------------------------------
155 std::vector<vec<Real, NumDimensions>> const& positions)
156 : parent_type{positions} {}
157 //----------------------------------------------------------------------------
159 std::vector<vec<Real, NumDimensions>>&& positions)
160 : parent_type{std::move(positions)} {}
161 //----------------------------------------------------------------------------
162 private:
163 template <typename... TypesToCheck>
164 auto copy_prop(auto const& other_grid, std::string const& name,
165 auto const& other_prop) {
166 (([&]() {
167 if (other_prop->type() == typeid(TypesToCheck)) {
168 auto& this_prop = this->template vertex_property<TypesToCheck>(name);
169 auto const& other_typed_prop =
170 other_grid.template vertex_property<TypesToCheck>(name);
171 auto vi = vertex_handle{0};
172 other_grid.vertices().iterate_indices([&](auto const... is) {
173 this_prop[vi++] = other_typed_prop.at(is...);
174 });
175 }
176 }()),
177 ...);
178 }
179
180 public:
181 template <floating_point_range DimX, floating_point_range DimY>
182 requires(NumDimensions == 2) && (SimplexDim == 2)
183 explicit unstructured_simplicial_grid(rectilinear_grid<DimX, DimY> const& g) {
184 auto const s0 = g.size(0);
185 auto const s1 = g.size(1);
186 g.vertices().iterate_indices(
187 [&](auto const i, auto const j) { insert_vertex(g.vertex_at(i, j)); });
188
189 for (auto const& [name, prop] : g.vertex_properties()) {
191 vec4f, vec3f, vec2f, double, float, std::int8_t, std::uint8_t,
192 std::int16_t, std::uint16_t, std::int32_t, std::uint32_t,
193 std::int64_t, std::uint64_t>(g, name, prop);
194 }
195
196 constexpr auto turned = [](std::size_t const ix,
197 std::size_t const iy) -> bool {
198 bool const xodd = ix % 2 == 0;
199 bool const yodd = iy % 2 == 0;
200
201 bool turned = xodd;
202 if (yodd) {
203 turned = !turned;
204 }
205 return turned;
206 };
207 for_loop(
208 [&](auto const ix, auto const iy) {
209 auto const le_bo = vertex_handle{ix + iy * s0};
210 auto const ri_bo = vertex_handle{(ix + 1) + iy * s0};
211 auto const le_to = vertex_handle{ix + (iy + 1) * s0};
212 auto const ri_to = vertex_handle{(ix + 1) + (iy + 1) * s0};
213 if (turned(ix, iy)) {
214 insert_simplex(le_bo, ri_bo, ri_to);
215 insert_simplex(le_bo, ri_to, le_to);
216 } else {
217 insert_simplex(le_bo, ri_bo, le_to);
218 insert_simplex(ri_bo, ri_to, le_to);
219 }
220 },
221 s0 - 1, s1 - 1);
222 }
223 //----------------------------------------------------------------------------
224 template <floating_point_range DimX, floating_point_range DimY,
226 requires(NumDimensions == 3) && (SimplexDim == 3)
228 rectilinear_grid<DimX, DimY, DimZ> const& g) {
229 constexpr auto turned = [](std::size_t const ix, std::size_t const iy,
230 std::size_t const iz) -> bool {
231 bool const xodd = ix % 2 == 0;
232 bool const yodd = iy % 2 == 0;
233 bool const zodd = iz % 2 == 0;
234
235 bool turned = xodd;
236 if (yodd) {
237 turned = !turned;
238 }
239 if (zodd) {
240 turned = !turned;
241 }
242 return turned;
243 };
244
245 auto const gv = g.vertices();
246 for (auto v : gv) {
247 insert_vertex(gv[v]);
248 }
249 auto const s0 = g.size(0);
250 auto const s1 = g.size(1);
251 auto const s0s1 = s0 * s1;
252 auto it = [&](auto const ix, auto const iy, auto const iz) {
253 auto const le_bo_fr = vertex_handle{ix + iy * s0 + iz * s0s1};
254 auto const ri_bo_fr = vertex_handle{(ix + 1) + iy * s0 + iz * s0s1};
255 auto const le_to_fr = vertex_handle{ix + (iy + 1) * s0 + iz * s0s1};
256 auto const ri_to_fr = vertex_handle{(ix + 1) + (iy + 1) * s0 + iz * s0s1};
257 auto const le_bo_ba = vertex_handle{ix + iy * s0 + (iz + 1) * s0s1};
258 auto const ri_bo_ba = vertex_handle{(ix + 1) + iy * s0 + (iz + 1) * s0s1};
259 auto const le_to_ba = vertex_handle{ix + (iy + 1) * s0 + (iz + 1) * s0s1};
260 auto const ri_to_ba =
261 vertex_handle{(ix + 1) + (iy + 1) * s0 + (iz + 1) * s0s1};
262 if (turned(ix, iy, iz)) {
263 insert_simplex(le_bo_fr, ri_bo_ba, ri_to_fr,
264 le_to_ba); // inner
265 insert_simplex(le_bo_fr, ri_bo_fr, ri_to_fr,
266 ri_bo_ba); // right front
267 insert_simplex(le_bo_fr, ri_to_fr, le_to_fr,
268 le_to_ba); // left front
269 insert_simplex(ri_to_fr, ri_bo_ba, ri_to_ba,
270 le_to_ba); // right back
271 insert_simplex(le_bo_fr, le_bo_ba, ri_bo_ba,
272 le_to_ba); // left back
273 } else {
274 insert_simplex(le_to_fr, ri_bo_fr, le_bo_ba,
275 ri_to_ba); // inner
276 insert_simplex(le_bo_fr, ri_bo_fr, le_to_fr,
277 le_bo_ba); // left front
278 insert_simplex(ri_bo_fr, ri_to_fr, le_to_fr,
279 ri_to_ba); // right front
280 insert_simplex(le_to_fr, le_to_ba, ri_to_ba,
281 le_bo_ba); // left back
282 insert_simplex(ri_bo_fr, ri_bo_ba, ri_to_ba,
283 le_bo_ba); // right back
284 }
285 };
286 for_loop_unpacked(it, g.size());
287 for (auto const& [name, prop] : g.vertex_properties()) {
289 vec4f, vec3f, vec2f, double, float, std::int8_t, std::uint8_t,
290 std::int16_t, std::uint16_t, std::int32_t, std::uint32_t,
291 std::int64_t, std::uint64_t>(g, name, prop);
292 }
293 }
294 //============================================================================
295 auto operator[](simplex_handle t) const -> auto{
296 return simplex_at(t.index());
297 }
298 auto operator[](simplex_handle t) -> auto{ return simplex_at(t.index()); }
299 //----------------------------------------------------------------------------
300 auto at(simplex_handle t) const -> auto{ return simplex_at(t.index()); }
301 auto at(simplex_handle t) -> auto{ return simplex_at(t.index()); }
302 //----------------------------------------------------------------------------
303 auto simplex_at(simplex_handle t) const -> auto{
304 return simplex_at(t.index());
305 }
306 auto simplex_at(simplex_handle t) -> auto{ return simplex_at(t.index()); }
307 //----------------------------------------------------------------------------
308 template <std::size_t... Seq>
309 auto simplex_at(std::size_t const i) const {
310 return simplex_at(i,
311 std::make_index_sequence<num_vertices_per_simplex()>{});
312 }
313 template <std::size_t... Seq>
314 auto simplex_at(std::size_t const i) {
315 return simplex_at(i,
316 std::make_index_sequence<num_vertices_per_simplex()>{});
317 }
318 //----------------------------------------------------------------------------
319 private:
320 template <std::size_t... Seq>
321 auto simplex_at(std::size_t const i,
322 std::index_sequence<Seq...> /*seq*/) const
324 return {m_simplex_index_data[i * num_vertices_per_simplex() + Seq]...};
325 }
326 template <std::size_t... Seq>
327 auto simplex_at(std::size_t const i, std::index_sequence<Seq...> /*seq*/)
329 return {m_simplex_index_data[i * num_vertices_per_simplex() + Seq]...};
330 }
331 //----------------------------------------------------------------------------
332 public:
333 auto insert_vertex(arithmetic auto const... comps)
334 requires(sizeof...(comps) == NumDimensions)
335 {
336 auto const vi = parent_type::insert_vertex(comps...);
337 // if (m_hierarchy != nullptr) {
338 // if (!m_hierarchy->insert_vertex(vi.index())) {
339 // build_hierarchy();
340 // }
341 //}
342 return vi;
343 }
344 //----------------------------------------------------------------------------
345 auto insert_vertex(pos_type const& v) {
346 auto const vi = parent_type::insert_vertex(v);
347 // if (m_hierarchy != nullptr) {
348 // if (!m_hierarchy->insert_vertex(vi.index())) {
349 // build_hierarchy();
350 // }
351 //}
352 return vi;
353 }
354 //----------------------------------------------------------------------------
356 auto const vi = parent_type::insert_vertex(std::move(v));
357 // if (m_hierarchy != nullptr) {
358 // if (!m_hierarchy->insert_vertex(vi.index())) {
359 // build_hierarchy();
360 // }
361 //}
362 return vi;
363 }
364 //----------------------------------------------------------------------------
365 auto remove(vertex_handle const vh) {
366 using namespace std::ranges;
368 auto simplex_contains_vertex = [this, vh](auto const ch) {
369 return contains(ch, vh);
370 };
371 copy_if(simplices(),
373 simplex_contains_vertex);
374 }
375 //----------------------------------------------------------------------------
376 auto remove_duplicate_vertices(Real const eps = Real{}) {
378 }
379 //----------------------------------------------------------------------------
381 Real const eps = Real{}) {
382 auto m = std::mutex{};
383 for (auto v0 = vertices().cbegin(); v0 != vertices().cend(); ++v0) {
384#pragma omp parallel for
385 for (auto v1 = next(v0); v1 != vertices().cend(); ++v1) {
386 auto const d = squared_euclidean_distance(at(*v0), at(*v1));
387 if (d <= eps) {
388 for (std::size_t is = 0; is < m_simplex_index_data.size();
389 is += num_vertices_per_simplex()) {
390 for (std::size_t ivs = 0; ivs < num_vertices_per_simplex(); ++ivs) {
391 if (m_simplex_index_data[is + ivs] == *v1) {
392 m_simplex_index_data[is + ivs] = *v0;
393 }
394 }
395 }
396 auto l = std::lock_guard{m};
398 }
399 }
400 }
401 }
402 //----------------------------------------------------------------------------
404 Real const eps = Real{}) {
405 // auto const& data = this->m_vertex_position_data;
406 for (auto v0 = vertices().cbegin(); v0 != vertices().cend(); ++v0) {
407 for (auto v1 = next(v0); v1 != vertices().cend(); ++v1) {
408 auto const d = squared_euclidean_distance(at(*v0), at(*v1));
409 if (d <= eps) {
410 for (std::size_t is = 0; is < m_simplex_index_data.size();
411 is += num_vertices_per_simplex()) {
412 for (std::size_t ivs = 0; ivs < num_vertices_per_simplex(); ++ivs) {
413 if (m_simplex_index_data[is + ivs] == *v1) {
414 m_simplex_index_data[is + ivs] = *v0;
415 }
416 }
417 }
419 }
420 }
421 }
422 }
423 //----------------------------------------------------------------------------
424 auto remove(simplex_handle const ch) { m_invalid_simplices.insert(ch); }
425 //----------------------------------------------------------------------------
426 template <typename... Handles>
427 auto insert_simplex(Handles const... handles)
428 requires(is_same<Handles, vertex_handle> && ...)
429 {
430 static_assert(sizeof...(Handles) == num_vertices_per_simplex(),
431 "wrong number of vertices for simplex");
432 (m_simplex_index_data.push_back(handles), ...);
433 for (auto& [key, prop] : m_simplex_properties) {
434 prop->push_back();
435 }
436 return simplex_handle{simplices().size() - 1};
437 }
438 //----------------------------------------------------------------------------
439 private:
440 template <std::size_t... Seq>
441 auto barycentric_coordinate(simplex_handle const& s, pos_type const& /*q*/,
442 std::index_sequence<Seq...> /*seq*/) const {
445 b(NumDimensions) = 1;
446
447 (
448 [&](auto const v) {
449 for (std::size_t i = 0; i < NumDimensions; ++i) {
450 A(i, v.index()) = v(i);
451 }
452 }(std::get<Seq>(at(s))),
453 ...);
454
455 return *solve(A, b);
456 }
457 //----------------------------------------------------------------------------
458 public:
459 auto barycentric_coordinate(simplex_handle const& s, pos_type const& q) const
460 requires(NumDimensions == SimplexDim)
461 {
462 if constexpr (NumDimensions == 2) {
463 auto const [v0, v1, v2] = at(s);
464 auto const p0 = at(v0) - q;
465 auto const p1 = at(v1) - q;
466 auto const p2 = at(v2) - q;
467 return vec{p1.x() * p2.y() - p2.x() * p1.y(),
468 p2.x() * p0.y() - p0.x() * p2.y(),
469 p0.x() * p1.y() - p1.x() * p0.y()} /
470 ((p1.x() - p0.x()) * p2.y() + (p0.x() - p2.x()) * p1.y() +
471 (p2.x() - p1.x()) * p0.y());
472 } else {
474 s, q, std::make_index_sequence<NumDimensions + 1>{});
475 }
476 }
477 //----------------------------------------------------------------------------
479 private:
481 auto inc = [](auto i) { return ++i; };
482 auto offsets = std::vector<std::size_t>(size(vertex_position_data()), 0);
483 for (auto const v : invalid_vertices()) {
484 auto i = begin(offsets) + v.index();
485 std::ranges::transform(i, end(offsets), i, inc);
486 }
487 for (auto& i : m_simplex_index_data) {
488 i -= offsets[i.index()];
489 }
490 }
491 //----------------------------------------------------------------------------
492 public:
493 auto tidy_up() {
496 auto correction = std::size_t{};
497 for (auto const c : m_invalid_simplices) {
498 auto simplex_begin = begin(m_simplex_index_data) +
499 c.index() * num_vertices_per_simplex() - correction;
500 m_simplex_index_data.erase(simplex_begin,
501 simplex_begin + num_vertices_per_simplex());
502 for (auto const& [key, prop] : m_simplex_properties) {
503 prop->erase(c.index());
504 }
505 correction += num_vertices_per_simplex();
506 }
507 m_invalid_simplices.clear();
508 }
509 //----------------------------------------------------------------------------
510 auto clear() {
512 m_simplex_index_data.clear();
513 }
514 //----------------------------------------------------------------------------
515 auto simplices() const { return simplex_container{this}; }
516 //----------------------------------------------------------------------------
518 if (m_invalid_simplices.empty()) {
520 }
521 auto indices = std::vector<vertex_handle>{};
522 indices.reserve(simplices().size() * num_vertices_per_simplex());
523 auto invalid_it = begin(m_invalid_simplices);
524
525 for (std::size_t i = 0; i < size(m_simplex_index_data()); ++i) {
526 if (*invalid_it == i) {
527 ++invalid_it;
528 } else {
529 for (std::size_t j = 0; j < num_vertices_per_simplex(); ++j) {
530 indices.push_back(m_simplex_index_data[i + j]);
531 }
532 }
533 }
534
535 auto constexpr inc = [](auto i) { return ++i; };
536 auto offsets = std::vector<std::size_t>(size(vertex_position_data()), 0);
537 for (auto const v : invalid_vertices()) {
538 auto i = begin(offsets) + v.index();
539 std::ranges::transform(i, end(offsets), i, inc);
540 }
541 for (auto& i : indices) {
542 i -= offsets[i.index()];
543 }
544
545 return indices;
546 }
547 //----------------------------------------------------------------------------
548 private:
549 template <std::size_t... Is>
550 auto contains(simplex_handle const ch, vertex_handle const vh,
551 std::index_sequence<Is...> /*seq*/) const {
552 auto simplices_vertices = at(ch);
553 return ((std::get<Is>(simplices_vertices) == vh) || ...);
554 }
555 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
556 public:
557 auto contains(simplex_handle const ch, vertex_handle const vh) const {
558 return contains(ch, vh,
559 std::make_index_sequence<num_vertices_per_simplex()>{});
560 }
561 //----------------------------------------------------------------------------
562#if TATOOINE_CGAL_AVAILABLE
564 requires(NumDimensions == 2) || (NumDimensions == 3)
565 {
566 build_delaunay_mesh(std::make_index_sequence<NumDimensions>{});
567 }
568
569 private:
570 template <std::size_t... Seq>
571 auto build_delaunay_mesh(std::index_sequence<Seq...> /*seq*/) -> void
572 requires(NumDimensions == 2) || (NumDimensions == 3)
573 {
574 m_simplex_index_data.clear();
575 using kernel_type = CGAL::Exact_predicates_inexact_constructions_kernel;
576 using triangulation_type =
578 kernel_type>;
579 using point_type = typename triangulation_type::Point;
580 auto points = std::vector<std::pair<point_type, vertex_handle>>{};
581 points.reserve(vertices().size());
582 for (auto v : vertices()) {
583 points.emplace_back(point_type{at(v)(Seq)...}, v);
584 }
585
586 auto triangulation = triangulation_type{begin(points), end(points)};
587 if constexpr (NumDimensions == 2) {
588 for (auto it = triangulation.finite_faces_begin();
589 it != triangulation.finite_faces_end(); ++it) {
590 insert_simplex(vertex_handle{it->vertex(0)->info()},
591 vertex_handle{it->vertex(Seq + 1)->info()}...);
592 }
593 } else if constexpr (NumDimensions == 3) {
594 for (auto it = triangulation.finite_cells_begin();
595 it != triangulation.finite_cells_end(); ++it) {
596 insert_simplex(vertex_handle{it->vertex(0)->info()},
597 vertex_handle{it->vertex(Seq + 1)->info()}...);
598 }
599 }
600 }
601
602 public:
603 auto build_sub_delaunay_mesh(std::vector<vertex_handle> const& vertices)
604 requires(NumDimensions == 2) || (NumDimensions == 3)
605 {
607 std::make_index_sequence<NumDimensions>{});
608 }
609
610 private:
611 template <std::size_t... Seq>
612 auto build_sub_delaunay_mesh(std::vector<vertex_handle> const& vertices,
613 std::index_sequence<Seq...> /*seq*/) -> void
614 requires(NumDimensions == 2) || (NumDimensions == 3)
615 {
616 m_simplex_index_data.clear();
617 using kernel_type = CGAL::Exact_predicates_inexact_constructions_kernel;
618 using triangulation_type =
620 kernel_type>;
621 using point_type = typename triangulation_type::Point;
622 auto points = std::vector<std::pair<point_type, vertex_handle>>{};
623 points.reserve(vertices.size());
624 for (auto v : vertices) {
625 points.emplace_back(point_type{at(v)(Seq)...}, v);
626 }
627
628 auto triangulation = triangulation_type{begin(points), end(points)};
629 if constexpr (NumDimensions == 2) {
630 for (auto it = triangulation.finite_faces_begin();
631 it != triangulation.finite_faces_end(); ++it) {
632 insert_simplex(vertex_handle{it->vertex(0)->info()},
633 vertex_handle{it->vertex(Seq + 1)->info()}...);
634 }
635 } else if constexpr (NumDimensions == 3) {
636 for (auto it = triangulation.finite_cells_begin();
637 it != triangulation.finite_cells_end(); ++it) {
638 insert_simplex(vertex_handle{it->vertex(0)->info()},
639 vertex_handle{it->vertex(Seq + 1)->info()}...);
640 }
641 }
642 }
643#endif
644
645#if TATOOINE_CDT_AVAILABLE
646 public:
648 std::vector<std::pair<vertex_handle, vertex_handle>> const& constraints)
649 -> void
650 requires(NumDimensions == 2) || (NumDimensions == 3)
651 {
652 build_delaunay_mesh(constraints, std::make_index_sequence<NumDimensions>{});
653 }
654
655 private:
656 template <std::size_t... Seq>
657 requires(NumDimensions == 2) /*|| (NumDimensions == 3)*/
659 std::vector<std::pair<vertex_handle, vertex_handle>> const& constraints,
660 std::index_sequence<Seq...> /*seq*/) -> void {
661 m_simplex_index_data.clear();
662 std::vector<CDT::Edge> edges;
663 edges.reserve(size(constraints));
664 boost::transform(constraints, std::back_inserter(edges),
665 [](auto const& c) -> CDT::Edge {
666 return {c.first.index(), c.second.index()};
667 });
668 auto triangulation =
669 CDT::Triangulation<Real>{CDT::FindingClosestPoint::BoostRTree};
670
671 triangulation.insertVertices(
672 vertices().begin(), vertices().end(),
673 [this](auto const& v) { return this->vertex_at(v)(0); },
674 [this](auto const& v) { return this->vertex_at(v)(1); });
675 auto const duplicates_info = CDT::RemoveDuplicatesAndRemapEdges<Real>(
676 triangulation.vertices, edges,
677 [this](auto const& v) { return v.pos.x; },
678 [this](auto const& v) { return v.pos.y; });
679
680 triangulation.insertEdges(edges);
681 triangulation.eraseSuperTriangle();
682 // triangulation.eraseOuterTrianglesAndHoles();
683 for (auto const& tri : triangulation.triangles) {
684 insert_simplex(vertex_handle{tri.vertices[0]},
685 vertex_handle{tri.vertices[1]},
686 vertex_handle{tri.vertices[2]});
687 }
688 }
689#endif
690 //----------------------------------------------------------------------------
691 public:
692 template <typename T>
693 auto simplex_property(std::string const& name) -> auto& {
694 auto it = m_simplex_properties.find(name);
695 if (it == end(m_simplex_properties)) {
696 return insert_simplex_property<T>(name);
697 }
698 if (typeid(T) != it->second->type()) {
699 throw std::runtime_error{
700 "type of property \"" + name + "\"(" +
701 boost::core::demangle(it->second->type().name()) +
702 ") does not match specified type " + type_name<T>() + "."};
703 }
704 return *dynamic_cast<simplex_property_type<T>*>(
705 m_simplex_properties.at(name).get());
706 }
707 //----------------------------------------------------------------------------
708 template <typename T>
709 auto simplex_property(std::string const& name) const -> const auto& {
710 auto it = m_simplex_properties.find(name);
711 if (it == end(m_simplex_properties)) {
712 throw std::runtime_error{"property \"" + name + "\" not found"};
713 }
714 if (typeid(T) != it->second->type()) {
715 throw std::runtime_error{
716 "type of property \"" + name + "\"(" +
717 boost::core::demangle(it->second->type().name()) +
718 ") does not match specified type " + type_name<T>() + "."};
719 }
720 return *dynamic_cast<simplex_property_type<T>*>(
721 m_simplex_properties.at(name).get());
722 }
723 //----------------------------------------------------------------------------
724 auto scalar_simplex_property(std::string const& name) const -> auto const& {
725 return simplex_property<tatooine::real_number>(name);
726 }
727 //----------------------------------------------------------------------------
728 auto scalar_simplex_property(std::string const& name) -> auto& {
729 return simplex_property<tatooine::real_number>(name);
730 }
731 //----------------------------------------------------------------------------
732 auto vec2_simplex_property(std::string const& name) const -> auto const& {
733 return simplex_property<vec2>(name);
734 }
735 //----------------------------------------------------------------------------
736 auto vec2_simplex_property(std::string const& name) -> auto& {
737 return simplex_property<vec2>(name);
738 }
739 //----------------------------------------------------------------------------
740 auto vec3_simplex_property(std::string const& name) const -> auto const& {
741 return simplex_property<vec3>(name);
742 }
743 //----------------------------------------------------------------------------
744 auto vec3_simplex_property(std::string const& name) -> auto& {
745 return simplex_property<vec3>(name);
746 }
747 //----------------------------------------------------------------------------
748 auto vec4_simplex_property(std::string const& name) const -> auto const& {
749 return simplex_property<vec4>(name);
750 }
751 //----------------------------------------------------------------------------
752 auto vec4_simplex_property(std::string const& name) -> auto& {
753 return simplex_property<vec4>(name);
754 }
755 //----------------------------------------------------------------------------
756 auto mat2_simplex_property(std::string const& name) const -> auto const& {
757 return simplex_property<mat2>(name);
758 }
759 //----------------------------------------------------------------------------
760 auto mat2_simplex_property(std::string const& name) -> auto& {
761 return simplex_property<mat2>(name);
762 }
763 //----------------------------------------------------------------------------
764 auto mat3_simplex_property(std::string const& name) const -> auto const& {
765 return simplex_property<mat3>(name);
766 }
767 //----------------------------------------------------------------------------
768 auto mat3_simplex_property(std::string const& name) -> auto& {
769 return simplex_property<mat3>(name);
770 }
771 //----------------------------------------------------------------------------
772 auto mat4_simplex_property(std::string const& name) const -> auto const& {
773 return simplex_property<mat4>(name);
774 }
775 //----------------------------------------------------------------------------
776 auto mat4_simplex_property(std::string const& name) -> auto& {
777 return simplex_property<mat4>(name);
778 }
779 //----------------------------------------------------------------------------
780 template <typename T>
781 auto insert_simplex_property(std::string const& name, T const& value = T{})
782 -> auto& {
783 auto [it, suc] = m_simplex_properties.insert(
784 std::pair{name, std::make_unique<simplex_property_type<T>>(value)});
785 auto prop = dynamic_cast<simplex_property_type<T>*>(it->second.get());
786 prop->resize(simplices().size());
787 return *prop;
788 }
789 //----------------------------------------------------------------------------
790 auto write(filesystem::path const& path) const {
791 auto const ext = path.extension();
792 if (ext == ".vtk") {
793 if constexpr ((NumDimensions == 2 || NumDimensions == 3) &&
794 SimplexDim == 2) {
795 write_vtk(path);
796 return;
797 } else {
798 throw std::runtime_error{
799 ".vtk is not supported with this simplicial grid."};
800 }
801 } else if (ext == ".vtp") {
802 if constexpr ((NumDimensions == 2 || NumDimensions == 3) &&
803 (SimplexDim == 1 || SimplexDim == 2)) {
804 write_vtp(path);
805 return;
806 } else {
807 throw std::runtime_error{
808 ".vtp is not supported with this simplicial grid."};
809 }
810 } else if (ext == ".vtu") {
811 if constexpr ((NumDimensions == 2 || NumDimensions == 3) &&
812 (SimplexDim == 2 || SimplexDim == 3)) {
813 write_vtu(path);
814 return;
815 } else {
816 throw std::runtime_error{
817 ".vtu is not supported with this simplicial grid."};
818 }
819 }
820 throw std::runtime_error(
821 "Could not write unstructured_simplicial_grid. Unknown file extension: "
822 "\"" +
823 ext.string() + "\".");
824 }
825 //----------------------------------------------------------------------------
826 auto write_vtk(std::filesystem::path const& path,
827 std::string const& title = "tatooine grid") const {
828 if constexpr (SimplexDim == 2) {
829 // tidy_up();
831 }
832 }
833 //----------------------------------------------------------------------------
834 auto write_vtp(filesystem::path const& path) const
835 requires((NumDimensions == 2 || NumDimensions == 3) &&
836 (SimplexDim == 1 || SimplexDim == 2))
837 {
838 if constexpr (SimplexDim == 1) {
839 write_vtp_edges(path);
840 } else if constexpr (SimplexDim == 2) {
842 }
843 }
844 //----------------------------------------------------------------------------
845 auto write_vtu(filesystem::path const& path) const
846 requires((NumDimensions == 2 || NumDimensions == 3) &&
847 (SimplexDim == 2 || SimplexDim == 3))
848 {
849 if constexpr (SimplexDim == 2) {
851 } else if constexpr (SimplexDim == 3) {
853 }
854 }
855 //----------------------------------------------------------------------------
856 template <unsigned_integral HeaderType = std::uint64_t,
857 integral ConnectivityInt = std::int64_t,
858 integral OffsetInt = std::int64_t>
859 auto write_vtp_edges(filesystem::path const& path) const
860 requires((NumDimensions == 2 || NumDimensions == 3) && SimplexDim == 1)
861 {
863 this_type, HeaderType, ConnectivityInt, OffsetInt>{*this}
864 .write(path);
865 }
866 //----------------------------------------------------------------------------
867 template <unsigned_integral HeaderType = std::uint64_t,
868 integral ConnectivityInt = std::int64_t,
869 integral OffsetInt = std::int64_t>
870 auto write_vtp_triangles(filesystem::path const& path) const
871 requires((NumDimensions == 2 || NumDimensions == 3) && SimplexDim == 2)
872 {
874 this_type, HeaderType, ConnectivityInt, OffsetInt>{*this}
875 .write(path);
876 }
877 //----------------------------------------------------------------------------
878 template <unsigned_integral HeaderType = std::uint64_t,
879 integral ConnectivityInt = std::int64_t,
880 integral OffsetInt = std::int64_t,
881 unsigned_integral CellTypesInt = std::uint8_t>
882 auto write_vtu_triangular(filesystem::path const& path) const
883 requires((NumDimensions == 2 || NumDimensions == 3) && SimplexDim == 2)
884 {
886 this_type, HeaderType, ConnectivityInt, OffsetInt, CellTypesInt>{*this}
887 .write(path);
888 }
889 //----------------------------------------------------------------------------
890 template <unsigned_integral HeaderType = std::uint64_t,
891 integral ConnectivityInt = std::int64_t,
892 integral OffsetInt = std::int64_t,
893 unsigned_integral CellTypesInt = std::uint8_t>
894 auto write_vtu_tetrahedral(filesystem::path const& path) const
895 requires((NumDimensions == 2 || NumDimensions == 3) && SimplexDim == 3)
896 {
898 this_type, HeaderType, ConnectivityInt, OffsetInt, CellTypesInt>{*this}
899 .write(path);
900 }
901 //----------------------------------------------------------------------------
902 auto write_unstructured_triangular_grid_vtk(std::filesystem::path const& path,
903 std::string const& title) const
904 -> bool
905 requires(SimplexDim == 2)
906 {
907 using namespace std::ranges;
908 auto writer =
910 if (writer.is_open()) {
911 writer.set_title(title);
912 writer.write_header();
913 if constexpr (NumDimensions == 2) {
914 auto three_dims = [](vec<Real, 2> const& v2) {
915 return vec<Real, 3>{v2(0), v2(1), 0};
916 };
917 auto v3s = std::vector<vec<Real, 3>>(vertices().size());
918 auto three_dimensional = views::transform(three_dims);
919 copy(vertex_position_data() | three_dimensional, begin(v3s));
920 writer.write_points(v3s);
921
922 } else if constexpr (NumDimensions == 3) {
923 writer.write_points(vertex_position_data());
924 }
925
926 auto vertices_per_simplex = std::vector<std::vector<std::size_t>>{};
927 vertices_per_simplex.reserve(simplices().size());
928 auto cell_types = std::vector<vtk::cell_type>(simplices().size(),
930 for (auto const c : simplices()) {
931 auto const [v0, v1, v2] = at(c);
932 vertices_per_simplex.push_back(
933 std::vector{v0.index(), v1.index(), v2.index()});
934 }
935 writer.write_cells(vertices_per_simplex);
936 writer.write_cell_types(cell_types);
937
938 // write vertex_handle data
939 writer.write_point_data(vertices().size());
940 for (auto const& [name, prop] : vertex_properties()) {
941 if (prop->type() == typeid(vec<Real, 4>)) {
942 auto const& casted_prop =
943 *dynamic_cast<typed_vertex_property_type<vec<Real, 4>> const*>(
944 prop.get());
945 writer.write_scalars(name, casted_prop.internal_container());
946 } else if (prop->type() == typeid(vec<Real, 3>)) {
947 auto const& casted_prop =
948 *dynamic_cast<typed_vertex_property_type<vec<Real, 3>> const*>(
949 prop.get());
950 writer.write_scalars(name, casted_prop.internal_container());
951 } else if (prop->type() == typeid(vec<Real, 2>)) {
952 auto const& casted_prop =
953 *dynamic_cast<typed_vertex_property_type<vec<Real, 2>> const*>(
954 prop.get());
955 writer.write_scalars(name, casted_prop.internal_container());
956 } else if (prop->type() == typeid(Real)) {
957 auto const& casted_prop =
958 *dynamic_cast<typed_vertex_property_type<Real> const*>(
959 prop.get());
960 writer.write_scalars(name, casted_prop.internal_container());
961 }
962 }
963
964 writer.close();
965 return true;
966 }
967 return false;
968 }
969 //----------------------------------------------------------------------------
971 std::filesystem::path const& path, std::string const& title) const -> bool
972 requires(SimplexDim == 2)
973 {
974 using boost::copy;
975 using boost::adaptors::transformed;
977 if (writer.is_open()) {
978 writer.set_title(title);
979 writer.write_header();
981
982 auto vertices_per_simplex = std::vector<std::vector<std::size_t>>{};
983 vertices_per_simplex.reserve(simplices().size());
984 auto cell_types = std::vector<vtk::cell_type>(simplices().size(),
986 for (auto const t : simplices()) {
987 auto const [v0, v1, v2, v3] = at(t);
988 vertices_per_simplex.push_back(
989 std::vector{v0.index(), v1.index(), v2.index(), v3.index()});
990 }
991 writer.write_cells(vertices_per_simplex);
992 writer.write_cell_types(cell_types);
993
994 // write vertex_handle data
995 writer.write_point_data(vertices().size());
996 for (auto const& [name, prop] : vertex_properties()) {
997 if (prop->type() == typeid(vec<Real, 4>)) {
998 } else if (prop->type() == typeid(vec<Real, 3>)) {
999 } else if (prop->type() == typeid(vec<Real, 2>)) {
1000 auto const& casted_prop =
1001 *dynamic_cast<typed_vertex_property_type<vec<Real, 2>> const*>(
1002 prop.get());
1003 writer.write_scalars(name, casted_prop.internal_container());
1004 } else if (prop->type() == typeid(Real)) {
1005 auto const& casted_prop =
1006 *dynamic_cast<typed_vertex_property_type<Real> const*>(
1007 prop.get());
1008 writer.write_scalars(name, casted_prop.internal_container());
1009 }
1010 }
1011
1012 writer.close();
1013 return true;
1014 }
1015 return false;
1016 }
1017 //----------------------------------------------------------------------------
1018 public:
1019 auto read(std::filesystem::path const& path) {
1020 auto ext = path.extension();
1021 if constexpr (NumDimensions == 2 || NumDimensions == 3) {
1022 if (ext == ".vtk") {
1023 read_vtk(path);
1024 }
1025 }
1026 }
1027 //----------------------------------------------------------------------------
1028 auto read_vtk(std::filesystem::path const& path)
1029 requires(NumDimensions == 2 || NumDimensions == 3)
1030 {
1031 struct listener_type : vtk::legacy_file_listener {
1033 std::vector<int> simplices;
1034
1035 explicit listener_type(unstructured_simplicial_grid& _grid)
1036 : grid{_grid} {}
1037 auto add_simplices(std::vector<int> const& simplices) -> void {
1038 std::size_t i = 0;
1039 while (i < size(simplices)) {
1040 auto const num_vertices = simplices[i++];
1041 if (num_vertices != num_vertices_per_simplex()) {
1042 throw std::runtime_error{
1043 "Number of vertices in file does not match number of vertices "
1044 "per simplex."};
1045 }
1046 for (std::size_t j = 0; j < static_cast<std::size_t>(num_vertices);
1047 ++j) {
1048 grid.simplex_index_data().push_back(vertex_handle{simplices[i++]});
1049 }
1050 for (auto& [key, prop] : grid.simplex_properties()) {
1051 prop->push_back();
1052 }
1053 }
1054 }
1055 void on_cells(std::vector<int> const& simplices) override {
1056 add_simplices(simplices);
1057 }
1058 void on_dataset_type(vtk::dataset_type t) override {
1059 if (t != vtk::dataset_type::unstructured_grid &&
1060 t != vtk::dataset_type::polydata) {
1061 throw std::runtime_error{
1062 "[unstructured_simplicial_grid] need polydata or "
1063 "unstructured_grid "
1064 "when reading vtk legacy"};
1065 }
1066 }
1067
1068 void on_points(std::vector<std::array<float, 3>> const& ps) override {
1069 for (const auto& p : ps) {
1070 if constexpr (NumDimensions == 2) {
1071 grid.insert_vertex(static_cast<Real>(p[0]),
1072 static_cast<Real>(p[1]));
1073 }
1074 if constexpr (NumDimensions == 3) {
1075 grid.insert_vertex(static_cast<Real>(p[0]), static_cast<Real>(p[1]),
1076 static_cast<Real>(p[2]));
1077 }
1078 }
1079 }
1080 void on_points(std::vector<std::array<double, 3>> const& ps) override {
1081 for (const auto& p : ps) {
1082 if constexpr (NumDimensions == 2) {
1083 grid.insert_vertex(static_cast<Real>(p[0]),
1084 static_cast<Real>(p[1]));
1085 }
1086 if constexpr (NumDimensions == 3) {
1087 grid.insert_vertex(static_cast<Real>(p[0]), static_cast<Real>(p[1]),
1088 static_cast<Real>(p[2]));
1089 }
1090 }
1091 }
1092 void on_polygons(std::vector<int> const& ps) override {
1093 add_simplices(ps);
1094 }
1095 void on_scalars(std::string const& data_name,
1096 std::string const& /*lookup_table_name*/,
1097 std::size_t num_comps, std::vector<double> const& scalars,
1098 vtk::reader_data data) override {
1099 if (data == vtk::reader_data::point_data) {
1100 if (num_comps == 1) {
1101 auto& prop =
1102 grid.template insert_vertex_property<double>(data_name);
1103 for (auto v = vertex_handle{0}; v < vertex_handle{prop.size()};
1104 ++v) {
1105 prop[v] = scalars[v.index()];
1106 }
1107 } else if (num_comps == 2) {
1108 auto& prop =
1109 grid.template insert_vertex_property<vec<double, 2>>(data_name);
1110
1111 for (auto v = vertex_handle{0}; v < vertex_handle{prop.size()};
1112 ++v) {
1113 for (std::size_t j = 0; j < num_comps; ++j) {
1114 prop[v][j] = scalars[v.index() * num_comps + j];
1115 }
1116 }
1117 } else if (num_comps == 3) {
1118 auto& prop =
1119 grid.template insert_vertex_property<vec<double, 3>>(data_name);
1120 for (auto v = vertex_handle{0}; v < vertex_handle{prop.size()};
1121 ++v) {
1122 for (std::size_t j = 0; j < num_comps; ++j) {
1123 prop[v][j] = scalars[v.index() * num_comps + j];
1124 }
1125 }
1126 } else if (num_comps == 4) {
1127 auto& prop =
1128 grid.template insert_vertex_property<vec<double, 4>>(data_name);
1129 for (auto v = vertex_handle{0}; v < vertex_handle{prop.size()};
1130 ++v) {
1131 for (std::size_t j = 0; j < num_comps; ++j) {
1132 prop[v][j] = scalars[v.index() * num_comps + j];
1133 }
1134 }
1135 }
1136 } else if (data == vtk::reader_data::cell_data) {
1137 if (num_comps == 1) {
1138 auto& prop =
1139 grid.template insert_simplex_property<double>(data_name);
1140 for (auto c = simplex_handle{0}; c < simplex_handle{prop.size()};
1141 ++c) {
1142 prop[c] = scalars[c.index()];
1143 }
1144 } else if (num_comps == 2) {
1145 auto& prop = grid.template insert_simplex_property<vec<double, 2>>(
1146 data_name);
1147
1148 for (auto c = simplex_handle{0}; c < simplex_handle{prop.size()};
1149 ++c) {
1150 for (std::size_t j = 0; j < num_comps; ++j) {
1151 prop[c][j] = scalars[c.index() * num_comps + j];
1152 }
1153 }
1154 } else if (num_comps == 3) {
1155 auto& prop = grid.template insert_simplex_property<vec<double, 3>>(
1156 data_name);
1157 for (auto c = simplex_handle{0}; c < simplex_handle{prop.size()};
1158 ++c) {
1159 for (std::size_t j = 0; j < num_comps; ++j) {
1160 prop[c][j] = scalars[c.index() * num_comps + j];
1161 }
1162 }
1163 } else if (num_comps == 4) {
1164 auto& prop = grid.template insert_simplex_property<vec<double, 4>>(
1165 data_name);
1166 for (auto c = simplex_handle{0}; c < simplex_handle{prop.size()};
1167 ++c) {
1168 for (std::size_t j = 0; j < num_comps; ++j) {
1169 prop[c][j] = scalars[c.index() * num_comps + j];
1170 }
1171 }
1172 }
1173 }
1174 }
1175 } listener{*this};
1176 auto f = vtk::legacy_file{path};
1177 f.add_listener(listener);
1178 f.read();
1179 }
1180 //----------------------------------------------------------------------------
1181 constexpr auto is_valid(simplex_handle t) const {
1182 return std::ranges::find(m_invalid_simplices, t) ==
1184 }
1185 //----------------------------------------------------------------------------
1186 auto build_hierarchy() const {
1188 auto& h = hierarchy();
1189 if constexpr (is_uniform_tree_hierarchy<hierarchy_type>()) {
1190 for (auto v : vertices()) {
1191 h.insert_vertex(v);
1192 }
1193 for (auto c : simplices()) {
1194 h.insert_simplex(c);
1195 }
1196 }
1197 }
1198 //----------------------------------------------------------------------------
1199 auto clear_hierarchy() const { m_hierarchy.reset(); }
1200 //----------------------------------------------------------------------------
1201 auto hierarchy() const -> auto& {
1202 if (m_hierarchy == nullptr) {
1203 auto const bb = bounding_box();
1204 m_hierarchy = std::make_unique<hierarchy_type>(bb.min(), bb.max(), *this);
1205 }
1206 return *m_hierarchy;
1207 }
1208 //----------------------------------------------------------------------------
1209 template <typename T>
1210 auto sampler(typed_vertex_property_type<T> const& prop) const {
1211 if (m_hierarchy == nullptr) {
1213 }
1214 return vertex_property_sampler_type<T>{*this, prop};
1215 }
1216 //--------------------------------------------------------------------------
1217 template <typename T>
1218 auto vertex_property_sampler(std::string const& name) const {
1219 return sampler<T>(this->template vertex_property<T>(name));
1220 }
1221 //============================================================================
1222 template <typename F>
1225 auto sample_to_vertex_property(F&& f, std::string const& name)
1226 -> auto& {
1227 return sample_to_vertex_property(std::forward<F>(f), name,
1229 }
1230 //----------------------------------------------------------------------------
1231 template <typename F>
1234 auto sample_to_vertex_property(F&& f, std::string const& name,
1235 execution_policy_tag auto tag)
1236 -> auto& {
1237 if constexpr (invocable<F, pos_type>) {
1238 return sample_to_vertex_property_pos(std::forward<F>(f), name, tag);
1239 } else {
1240 return sample_to_vertex_property_vertex_handle(std::forward<F>(f), name,
1241 tag);
1242 }
1243 }
1244 //----------------------------------------------------------------------------
1245 private:
1246 template <invocable<vertex_handle> F>
1248 F&& f, std::string const& name, execution_policy_tag auto /*tag*/)
1249 -> auto& {
1250 using T = std::invoke_result_t<F, vertex_handle>;
1251 auto& prop = this->template vertex_property<T>(name);
1252 for (auto const v : vertices()) {
1253 try {
1254 prop[v] = f(v);
1255 } catch (std::exception&) {
1256 if constexpr (tensor_num_components<T> == 1) {
1257 prop[v] = T{0.0 / 0.0};
1258 } else {
1259 prop[v] = T::fill(0.0 / 0.0);
1260 }
1261 }
1262 };
1263 return prop;
1264 }
1265 //----------------------------------------------------------------------------
1266 template <invocable<pos_type> F>
1267 auto sample_to_vertex_property_pos(F&& f, std::string const& name,
1268 execution_policy_tag auto /*tag*/)
1269 -> auto& {
1270 using T = std::invoke_result_t<F, pos_type>;
1271 auto& prop = this->template vertex_property<T>(name);
1272 for (auto const v : vertices()) {
1273 try {
1274 prop[v] = f(at(v));
1275 } catch (std::exception&) {
1276 if constexpr (tensor_num_components<T> == 1) {
1277 prop[v] = T{0.0 / 0.0};
1278 } else {
1279 prop[v] = T::fill(0.0 / 0.0);
1280 }
1281 }
1282 };
1283 return prop;
1284 }
1285 //--------------------------------------------------------------------------
1286 constexpr auto bounding_box() const {
1287 auto bb = axis_aligned_bounding_box<Real, num_dimensions()>{};
1288 for (auto const v : vertices()) {
1289 bb += at(v);
1290 }
1291 return bb;
1292 }
1293};
1294//==============================================================================
1295// unstructured_simplicial_grid()->unstructured_simplicial_grid<double, 3>;
1298template <typename... Dims>
1301 typename rectilinear_grid<Dims...>::real_type, sizeof...(Dims)>;
1302//==============================================================================
1303// namespace detail {
1304// template <typename MeshCont>
1305// auto write_grid_container_to_vtk(MeshContc onst& grids, std::string const&
1306// path,
1307// std::string const& title) {
1308// vtk::legacy_file_writer writer(path, vtk::POLYDATA);
1309// if (writer.is_open()) {
1310// std::size_t num_pts = 0;
1311// std::size_t cur_first = 0;
1312// for (auto const& m : grids) { num_pts += m.vertices().size(); }
1313// std::vector<std::array<typename MeshCont::value_type::real_type, 3>>
1314// points; std::vector<std::vector<std::size_t>> simplices;
1315// points.reserve(num_pts); simplices.reserve(grids.size());
1316//
1317// for (auto const& m : grids) {
1318// // add points
1319// for (auto const& v : m.vertices()) {
1320// points.push_back(std::array{m[v](0), m[v](1), m[v](2)});
1321// }
1322//
1323// // add simplices
1324// for (auto t : m.simplices()) {
1325// simplices.emplace_back();
1326// simplices.back().push_back(cur_first + m[t][0].index());
1327// simplices.back().push_back(cur_first + m[t][1].index());
1328// simplices.back().push_back(cur_first + m[t][2].index());
1329// }
1330// cur_first += m.num_vertices();
1331// }
1332//
1333// // write
1334// writer.set_title(title);
1335// writer.write_header();
1336// writer.write_points(points);
1337// writer.write_polygons(simplices);
1338// //writer.write_point_data(num_pts);
1339// writer.close();
1340// }
1341//}
1342//} // namespace detail
1344// template <floating_point Real>
1345// auto write_vtk(std::vector<unstructured_simplicial_grid<Real, 3>> const&
1346// grids, std::string const& path,
1347// std::string const& title = "tatooine grids") {
1348// detail::write_grid_container_to_vtk(grids, path, title);
1349//}
1350//------------------------------------------------------------------------------
1351static constexpr inline auto constrained_delaunay_available(
1352 std::size_t const NumDimensions) -> bool {
1353 if (NumDimensions == 2) {
1354 return cdt_available();
1355 }
1356 return false;
1357}
1358//==============================================================================
1359} // namespace tatooine
1360//==============================================================================
1364//==============================================================================
1365#endif
void clear()
Definition: cache.h:145
auto & operator=(const cache &other)
Definition: cache.h:48
auto is_valid() const -> bool
Definition: grid_edge.h:207
Definition: grid_edge.h:16
void remove(vertex v)
Definition: mesh.h:252
void tidy_up()
tidies up invalid vertices, edges and faces
Definition: mesh.h:338
Definition: rectilinear_grid.h:38
Definition: vtk_legacy.h:448
auto write_point_data(std::size_t i) -> void
auto set_title(std::string const &title) -> void
Definition: vtk_legacy.h:632
auto write_scalars(std::string const &name, std::vector< Data > const &data, std::string const &lookup_table_name="default") -> void
Definition: vtk_legacy.h:760
auto write_points(std::vector< std::array< Real, 2 > > const &points) -> void
Definition: vtk_legacy.h:637
auto write_cell_types(std::vector< cell_type > const &cell_types) -> void
auto write_cells(std::vector< std::vector< std::size_t > > const &cells) -> void
Definition: vtk_legacy.h:184
auto add_listener(legacy_file_listener &listener) -> void
Definition: concepts.h:33
Definition: tags.h:72
Definition: concepts.h:94
Definition: concepts.h:21
Definition: invocable_with_n_types.h:37
Definition: concepts.h:121
Definition: concepts.h:27
delaunay_triangulation< NumDimensions, Traits, triangulation_data_structure< NumDimensions, Traits, triangulation_vertex_base_with_info< NumDimensions, Info, Traits >, SimplexBase > > delaunay_triangulation_with_info
Definition: delaunay_triangulation.h:50
Definition: edge_vtp_writer.h:12
static constexpr sequential_t sequential
Definition: tags.h:63
static constexpr parallel_t parallel
Definition: tags.h:60
reader_data
Definition: vtk_legacy.h:42
dataset_type
Definition: vtk_legacy.h:44
Definition: algorithm.h:6
VecF< 3 > vec3f
Definition: vec_typedefs.h:40
auto begin(Range &&range)
Definition: iterator_facade.h:318
static constexpr auto constrained_delaunay_available(std::size_t const NumDimensions) -> bool
Definition: unstructured_simplicial_grid.h:1351
mat44f mat4f
Definition: mat_typedefs.h:299
auto end(Range &&range)
Definition: iterator_facade.h:322
VecD< 3 > vec3d
Definition: vec_typedefs.h:51
mat22d mat2d
Definition: mat_typedefs.h:370
mat33d mat3d
Definition: mat_typedefs.h:371
auto for_loop_unpacked(Iteration &&iteration, execution_policy_tag auto policy, std::array< Int, N > const &sizes)
Definition: for_loop.h:480
mat33f mat3f
Definition: mat_typedefs.h:298
auto solve(polynomial< Real, 1 > const &p) -> std::vector< Real >
solve a + b*x
Definition: polynomial.h:187
VecD< 2 > vec2d
Definition: vec_typedefs.h:50
VecF< 4 > vec4f
Definition: vec_typedefs.h:41
VecD< 4 > vec4d
Definition: vec_typedefs.h:52
auto size(vec< ValueType, N > const &v)
Definition: vec.h:148
auto next(Iter iter)
Definition: iterator_facade.h:325
constexpr auto squared_euclidean_distance(base_tensor< Tensor0, T0, N > const &lhs, base_tensor< Tensor1, T1, N > const &rhs)
Definition: distance.h:11
constexpr auto for_loop(Iteration &&iteration, execution_policy::sequential_t, Ranges(&&... ranges)[2]) -> void
Use this function for creating a sequential nested loop.
Definition: for_loop.h:336
mat22f mat2f
Definition: mat_typedefs.h:297
mat44d mat4d
Definition: mat_typedefs.h:372
VecF< 2 > vec2f
Definition: vec_typedefs.h:39
Definition: axis_aligned_bounding_box.h:103
vec_type pos_type
Definition: axis_aligned_bounding_box.h:109
detail::unstructured_simplicial_grid::simplex_at_return_type< vertex_handle const &, SimplexDim+1 > const_simplex_at_return_type
Definition: parent.h:19
detail::unstructured_simplicial_grid::simplex_at_return_type< vertex_handle &, SimplexDim+1 > simplex_at_return_type
Definition: parent.h:22
hierarchy< Mesh, Real, NumDimensions, SimplexDim > hierarchy_type
Definition: parent.h:16
Definition: handle.h:14
constexpr handle()
Definition: handle.h:24
auto num_dimensions() const -> std::size_t
Definition: hdf5.h:764
auto vertex_properties() const -> auto const &
Definition: line.h:450
static auto constexpr ones()
Definition: mat.h:38
Definition: pointset.h:83
auto insert_vertex(arithmetic auto const ... ts)
Definition: pointset.h:243
auto vertex_position_data() const -> auto const &
Definition: pointset.h:235
static constexpr auto num_dimensions() -> std::size_t
Definition: pointset.h:72
auto invalid_vertices() const -> auto const &
Definition: pointset.h:239
auto vertices() const
Definition: pointset.h:226
auto vertex_at(vertex_handle const v) -> auto &
Definition: pointset.h:205
auto vertex_properties() const -> auto const &
Definition: pointset.h:191
type_list_at< this_type, I > at
Definition: type_list.h:269
Definition: property.h:66
Definition: unstructured_simplicial_grid.h:87
Definition: unstructured_simplicial_grid.h:52
auto read_vtk(std::filesystem::path const &path)
Definition: unstructured_simplicial_grid.h:1028
auto simplices() const
Definition: unstructured_simplicial_grid.h:515
auto scalar_simplex_property(std::string const &name) const -> auto const &
Definition: unstructured_simplicial_grid.h:724
auto write_vtp_edges(filesystem::path const &path) const
Definition: unstructured_simplicial_grid.h:859
auto simplex_at(std::size_t const i)
Definition: unstructured_simplicial_grid.h:314
auto at(simplex_handle t) -> auto
Definition: unstructured_simplicial_grid.h:301
auto build_delaunay_mesh(std::vector< std::pair< vertex_handle, vertex_handle > > const &constraints) -> void requires(NumDimensions==2)||(NumDimensions==3)
Definition: unstructured_simplicial_grid.h:647
auto simplex_at(std::size_t const i, std::index_sequence< Seq... >) -> simplex_at_return_type
Definition: unstructured_simplicial_grid.h:327
auto write_vtu(filesystem::path const &path) const
Definition: unstructured_simplicial_grid.h:845
auto remove_duplicate_vertices(execution_policy::parallel_t, Real const eps=Real{})
Definition: unstructured_simplicial_grid.h:380
auto write_vtp(filesystem::path const &path) const
Definition: unstructured_simplicial_grid.h:834
static constexpr auto simplex_dimension()
Definition: unstructured_simplicial_grid.h:85
auto clean_simplex_index_list() const
Definition: unstructured_simplicial_grid.h:517
unstructured_simplicial_grid< Real, NumDimensions, SimplexDim > this_type
Definition: unstructured_simplicial_grid.h:54
auto simplex_properties() const -> auto const &
Definition: unstructured_simplicial_grid.h:116
auto write_vtu_triangular(filesystem::path const &path) const
Definition: unstructured_simplicial_grid.h:882
auto simplex_at(simplex_handle t) const -> auto
Definition: unstructured_simplicial_grid.h:303
auto vertex_property_sampler(std::string const &name) const
Definition: unstructured_simplicial_grid.h:1218
auto vec4_simplex_property(std::string const &name) const -> auto const &
Definition: unstructured_simplicial_grid.h:748
unstructured_simplicial_grid(std::filesystem::path const &path)
Definition: unstructured_simplicial_grid.h:147
auto sample_to_vertex_property_pos(F &&f, std::string const &name, execution_policy_tag auto) -> auto &
Definition: unstructured_simplicial_grid.h:1267
unstructured_simplicial_grid(unstructured_simplicial_grid &&other) noexcept=default
std::unique_ptr< hierarchy_type > m_hierarchy
Definition: unstructured_simplicial_grid.h:106
auto build_hierarchy() const
Definition: unstructured_simplicial_grid.h:1186
auto operator[](simplex_handle t) const -> auto
Definition: unstructured_simplicial_grid.h:295
std::map< std::string, std::unique_ptr< vector_property< simplex_handle > > > simplex_property_container_type
Definition: unstructured_simplicial_grid.h:100
auto mat4_simplex_property(std::string const &name) const -> auto const &
Definition: unstructured_simplicial_grid.h:772
auto scalar_simplex_property(std::string const &name) -> auto &
Definition: unstructured_simplicial_grid.h:728
auto sample_to_vertex_property_vertex_handle(F &&f, std::string const &name, execution_policy_tag auto) -> auto &
Definition: unstructured_simplicial_grid.h:1247
auto mat2_simplex_property(std::string const &name) -> auto &
Definition: unstructured_simplicial_grid.h:760
auto simplex_at(std::size_t const i) const
Definition: unstructured_simplicial_grid.h:309
auto barycentric_coordinate(simplex_handle const &s, pos_type const &, std::index_sequence< Seq... >) const
Definition: unstructured_simplicial_grid.h:441
detail::unstructured_simplicial_grid::simplex_at_return_type< vertex_handle const &, SimplexDim+1 > const_simplex_at_return_type
Definition: parent.h:19
simplex_property_container_type m_simplex_properties
Definition: unstructured_simplicial_grid.h:105
auto write_vtp_triangles(filesystem::path const &path) const
Definition: unstructured_simplicial_grid.h:870
auto write_unstructured_tetrahedral_grid_vtk(std::filesystem::path const &path, std::string const &title) const -> bool requires(SimplexDim==2)
Definition: unstructured_simplicial_grid.h:970
auto simplex_at(std::size_t const i, std::index_sequence< Seq... >) const -> const_simplex_at_return_type
Definition: unstructured_simplicial_grid.h:321
auto clear()
Definition: unstructured_simplicial_grid.h:510
auto simplex_property(std::string const &name) -> auto &
Definition: unstructured_simplicial_grid.h:693
constexpr auto is_valid(simplex_handle t) const
Definition: unstructured_simplicial_grid.h:1181
auto hierarchy() const -> auto &
Definition: unstructured_simplicial_grid.h:1201
auto mat3_simplex_property(std::string const &name) const -> auto const &
Definition: unstructured_simplicial_grid.h:764
unstructured_simplicial_grid(std::vector< vec< Real, NumDimensions > > const &positions)
Definition: unstructured_simplicial_grid.h:154
static constexpr auto num_vertices_per_simplex()
Definition: unstructured_simplicial_grid.h:84
detail::unstructured_simplicial_grid::simplex_at_return_type< vertex_handle &, SimplexDim+1 > simplex_at_return_type
Definition: parent.h:22
auto operator=(unstructured_simplicial_grid const &other) -> unstructured_simplicial_grid &
Definition: unstructured_simplicial_grid.h:133
auto contains(simplex_handle const ch, vertex_handle const vh) const
Definition: unstructured_simplicial_grid.h:557
auto build_delaunay_mesh()
Definition: unstructured_simplicial_grid.h:563
auto barycentric_coordinate(simplex_handle const &s, pos_type const &q) const
Definition: unstructured_simplicial_grid.h:459
auto write_vtk(std::filesystem::path const &path, std::string const &title="tatooine grid") const
Definition: unstructured_simplicial_grid.h:826
unstructured_simplicial_grid(std::initializer_list< pos_type > &&vertices)
Definition: unstructured_simplicial_grid.h:151
auto read(std::filesystem::path const &path)
Definition: unstructured_simplicial_grid.h:1019
typename parent_type::template typed_vertex_property_type< T > typed_vertex_property_type
Definition: unstructured_simplicial_grid.h:82
auto simplex_index_data() const -> auto const &
Definition: unstructured_simplicial_grid.h:112
auto reindex_simplices_vertex_handles()
tidies up invalid vertices
Definition: unstructured_simplicial_grid.h:480
auto build_delaunay_mesh(std::vector< std::pair< vertex_handle, vertex_handle > > const &constraints, std::index_sequence< Seq... >) -> void
Definition: unstructured_simplicial_grid.h:658
auto write_unstructured_triangular_grid_vtk(std::filesystem::path const &path, std::string const &title) const -> bool requires(SimplexDim==2)
Definition: unstructured_simplicial_grid.h:902
auto remove(simplex_handle const ch)
Definition: unstructured_simplicial_grid.h:424
auto insert_vertex(arithmetic auto const ... comps)
Definition: unstructured_simplicial_grid.h:333
auto remove(vertex_handle const vh)
Definition: unstructured_simplicial_grid.h:365
auto insert_vertex(pos_type &&v)
Definition: unstructured_simplicial_grid.h:355
auto vec3_simplex_property(std::string const &name) -> auto &
Definition: unstructured_simplicial_grid.h:744
auto insert_simplex(Handles const ... handles)
Definition: unstructured_simplicial_grid.h:427
auto simplex_at(simplex_handle t) -> auto
Definition: unstructured_simplicial_grid.h:306
auto copy_prop(auto const &other_grid, std::string const &name, auto const &other_prop)
Definition: unstructured_simplicial_grid.h:164
auto insert_simplex_property(std::string const &name, T const &value=T{}) -> auto &
Definition: unstructured_simplicial_grid.h:781
auto insert_vertex(pos_type const &v)
Definition: unstructured_simplicial_grid.h:345
auto build_sub_delaunay_mesh(std::vector< vertex_handle > const &vertices)
Definition: unstructured_simplicial_grid.h:603
auto contains(simplex_handle const ch, vertex_handle const vh, std::index_sequence< Is... >) const
Definition: unstructured_simplicial_grid.h:550
typename parent_type::hierarchy_type hierarchy_type
Definition: unstructured_simplicial_grid.h:83
auto operator=(unstructured_simplicial_grid &&other) noexcept -> unstructured_simplicial_grid &=default
auto sampler(typed_vertex_property_type< T > const &prop) const
Definition: unstructured_simplicial_grid.h:1210
auto sample_to_vertex_property(F &&f, std::string const &name) -> auto &
Definition: unstructured_simplicial_grid.h:1225
auto vec2_simplex_property(std::string const &name) -> auto &
Definition: unstructured_simplicial_grid.h:736
auto operator[](simplex_handle t) -> auto
Definition: unstructured_simplicial_grid.h:298
auto mat4_simplex_property(std::string const &name) -> auto &
Definition: unstructured_simplicial_grid.h:776
auto write_vtu_tetrahedral(filesystem::path const &path) const
Definition: unstructured_simplicial_grid.h:894
auto at(simplex_handle t) const -> auto
Definition: unstructured_simplicial_grid.h:300
auto tidy_up()
Definition: unstructured_simplicial_grid.h:493
auto vec2_simplex_property(std::string const &name) const -> auto const &
Definition: unstructured_simplicial_grid.h:732
constexpr unstructured_simplicial_grid()=default
std::set< simplex_handle > m_invalid_simplices
Definition: unstructured_simplicial_grid.h:104
auto remove_duplicate_vertices(Real const eps=Real{})
Definition: unstructured_simplicial_grid.h:376
auto invalid_simplices() const -> auto const &
Definition: unstructured_simplicial_grid.h:115
std::vector< vertex_handle > m_simplex_index_data
Definition: unstructured_simplicial_grid.h:103
auto build_delaunay_mesh(std::index_sequence< Seq... >) -> void requires(NumDimensions==2)||(NumDimensions==3)
Definition: unstructured_simplicial_grid.h:571
auto write(filesystem::path const &path) const
Definition: unstructured_simplicial_grid.h:790
auto mat3_simplex_property(std::string const &name) -> auto &
Definition: unstructured_simplicial_grid.h:768
auto remove_duplicate_vertices(execution_policy::sequential_t, Real const eps=Real{})
Definition: unstructured_simplicial_grid.h:403
auto build_sub_delaunay_mesh(std::vector< vertex_handle > const &vertices, std::index_sequence< Seq... >) -> void requires(NumDimensions==2)||(NumDimensions==3)
Definition: unstructured_simplicial_grid.h:612
auto simplex_property(std::string const &name) const -> const auto &
Definition: unstructured_simplicial_grid.h:709
unstructured_simplicial_grid(unstructured_simplicial_grid const &other)
Definition: unstructured_simplicial_grid.h:123
auto vec3_simplex_property(std::string const &name) const -> auto const &
Definition: unstructured_simplicial_grid.h:740
auto clear_hierarchy() const
Definition: unstructured_simplicial_grid.h:1199
auto mat2_simplex_property(std::string const &name) const -> auto const &
Definition: unstructured_simplicial_grid.h:756
auto vec4_simplex_property(std::string const &name) -> auto &
Definition: unstructured_simplicial_grid.h:752
Real real_type
Definition: unstructured_simplicial_grid.h:55
constexpr auto bounding_box() const
Definition: unstructured_simplicial_grid.h:1286
auto sample_to_vertex_property(F &&f, std::string const &name, execution_policy_tag auto tag) -> auto &
Definition: unstructured_simplicial_grid.h:1234
unstructured_simplicial_grid(std::vector< vec< Real, NumDimensions > > &&positions)
Definition: unstructured_simplicial_grid.h:158
Definition: vec.h:12
auto constexpr x() const -> auto const &requires(N >=1)
Definition: vec.h:102
static auto constexpr zeros()
Definition: vec.h:26
Definition: vtk_legacy.h:92
std::map< std::string, data_array > vertices
Definition: piece.h:26