Tatooine
mesh.h
Go to the documentation of this file.
1#ifndef TATOOINE_MESH_H
2#define TATOOINE_MESH_H
3
4#include <tatooine/edgeset.h>
5#include <boost/range/algorithm.hpp>
6#include <list>
7#include <set>
8#include "utility.h"
9#include "vtk_legacy.h"
10
11//==============================================================================
12namespace tatooine {
13//==============================================================================
14
15template <typename Real, size_t N>
16class mesh : public edgeset<Real, N> {
17 public:
20
21 using typename parent_type::edge;
22 using typename parent_type::handle;
23 using typename parent_type::order_independent_edge_compare;
24 using typename parent_type::pos_type;
25 using typename parent_type::vertex;
26
27 using parent_type::at;
28 using parent_type::operator[];
36
37 //============================================================================
38 public:
39 struct face : handle {
40 face() = default;
41 face(size_t i) : handle{i} {}
42 face(const face&) = default;
43 face(face&&) = default;
44 face& operator=(const face&) = default;
45 face& operator=(face&&) = default;
46 bool operator==(const face& other) const { return this->i == other.i; }
47 bool operator!=(const face& other) const { return this->i != other.i; }
48 bool operator<(const face& other) const { return this->i < other.i; }
49 static constexpr auto invalid() { return face{handle::invalid_idx}; }
50 };
51
52 //============================================================================
54 : public boost::iterator_facade<
55 face_iterator, face, boost::bidirectional_traversal_tag, face> {
56 face_iterator(face _f, const mesh* _m) : f{_f}, m{_m} {}
57 face_iterator(const face_iterator& other) : f{other.f}, m{other.m} {}
58
59 private:
61 const mesh* m;
63
64 void increment() {
65 do
66 ++f.i;
67 while (!m->is_valid(f));
68 }
69 void decrement() {
70 do
71 --f.i;
72 while (!m->is_valid(f));
73 }
74
75 bool equal(const face_iterator& other) const { return f.i == other.f.i; }
76 auto dereference() const { return f; }
77 };
78
79 //============================================================================
83 const mesh* m_mesh;
84
85 auto begin() const {
87 if (!m_mesh->is_valid(*fi)) ++fi;
88 return fi;
89 }
90 auto end() const { return face_iterator{face{m_mesh->m_faces.size()}, m_mesh}; }
91 };
92
93 //============================================================================
94 template <typename T>
95 using vertex_prop = typename parent_type::template vertex_prop<T>;
96
97 //----------------------------------------------------------------------------
98 template <typename T>
99 using edge_prop = typename parent_type::template edge_prop<T>;
100
101 //----------------------------------------------------------------------------
102 template <typename T>
103 struct face_prop : public property_type<T> {
104 using property_type<T>::property_type;
105 auto& at(face f) { return property_type<T>::at(f.i); }
106 const auto& at(face f) const { return property_type<T>::at(f.i); }
107 auto& operator[](face f) { return property_type<T>::operator[](f.i); }
108 const auto& operator[](face f) const {
109 return property_type<T>::operator[](f.i);
110 }
111 std::unique_ptr<property> clone() const override {
112 return std::unique_ptr<face_prop<T>>(new face_prop<T>{*this});
113 }
114 };
115
116 //============================================================================
117 protected:
118 std::vector<std::vector<vertex>> m_faces;
119 std::vector<face> m_invalid_faces;
120 std::map<std::string, std::unique_ptr<property>> m_face_properties;
121
124
126
127 public:
128 //============================================================================
129 constexpr mesh() { add_link_properties(); }
130
131 //----------------------------------------------------------------------------
132 constexpr mesh(std::initializer_list<pos_type>&& vertices)
133 : parent_type(std::move(vertices)) {
135 }
136
137 //----------------------------------------------------------------------------
138#ifdef USE_TRIANGLE
139 mesh(const triangle::io& io) : parent_type{io} {
141 for (int i = 0; i < io.numberoftriangles; ++i)
142 insert_face(io.trianglelist[i * 3], io.trianglelist[i * 3 + 1],
143 io.trianglelist[i * 3 + 2]);
144 }
145#endif
146
147 // mesh(const tetgenio& io) : parent_type{io} { add_link_properties(); }
148
149 //============================================================================
150 public:
151 mesh(const mesh& other)
152 : parent_type(other),
153 m_faces(other.m_faces),
155 m_face_properties.clear();
156 for (const auto& [name, prop] : other.m_face_properties)
157 m_face_properties[name] = prop->clone();
159 }
160
161 //----------------------------------------------------------------------------
162 mesh(mesh&& other)
163 : parent_type(std::move(other)),
164 m_faces(std::move(other.m_faces)),
165 m_invalid_faces(std::move(other.m_invalid_faces)),
166 m_face_properties(std::move(other.m_face_properties)) {
168 }
169
170 //----------------------------------------------------------------------------
171 auto& operator=(const mesh& other) {
173 m_faces = other.m_faces;
175 for (const auto& [name, prop] : other.m_face_properties)
176 m_face_properties[name] = prop->clone();
178 return *this;
179 }
180
181 //----------------------------------------------------------------------------
182 auto& operator=(mesh&& other) {
183 parent_type::operator=(std::move(other));
184 m_faces = std::move(other.m_faces);
185 m_invalid_faces = std::move(other.m_invalid_faces);
186 m_face_properties = std::move(other.m_face_properties);
188 return *this;
189 }
190
191 //============================================================================
192 private:
195 &this->template add_vertex_property<std::vector<face>>("v:faces"));
197 &this->template add_edge_property<std::vector<face>>("e:faces"));
198
200 &this->template add_face_property<std::vector<edge>>("f:edges"));
201 }
202
203 //----------------------------------------------------------------------------
206 &this->template vertex_property<std::vector<face>>("v:faces"));
208 &this->template edge_property<std::vector<face>>("e:faces"));
210 &face_property<std::vector<edge>>("f:edges"));
211 }
212
213 public:
214 //============================================================================
215 constexpr auto& at(face f) { return m_faces[f.i]; }
216 constexpr const auto& at(face f) const { return m_faces[f.i]; }
217
218 //----------------------------------------------------------------------------
219 constexpr auto& operator[](face f) { return at(f); }
220 constexpr const auto& operator[](face f) const { return at(f); }
221
222 //----------------------------------------------------------------------------
223 constexpr auto insert_face(same_as<vertex> auto const... vs) {
224 return insert_face(std::vector<vertex>{vs...});
225 }
226
227 //----------------------------------------------------------------------------
228 constexpr auto insert_face(std::vector<vertex> new_face) {
229 // rotate vertex indices so that first vertex has smallest index
230 boost::rotate(new_face, boost::min_element(new_face));
232 for (auto f : faces())
233 if (eq(at(f), new_face)) return f;
234
235 face f{m_faces.size()};
236 m_faces.push_back(new_face);
237 for (auto& [key, prop] : m_face_properties) prop->push_back();
238
239 auto inserted_edges = insert_edges(f);
240
241 for (auto v : new_face) { faces(v).push_back(f); }
242
243 for (auto e : inserted_edges) {
244 faces(e).push_back(f);
245 edges(f).push_back(e);
246 }
247
248 return f;
249 }
250
251 //----------------------------------------------------------------------------
252 void remove(vertex v) {
253 using namespace boost;
255 for (auto f : faces(v))
256 if (find(m_invalid_faces, f) == m_invalid_faces.end()) remove(f);
257 }
258
259 //----------------------------------------------------------------------------
260 void remove(edge e, bool remove_orphaned_vertices = true) {
261 using namespace boost;
262 parent_type::remove(e, remove_orphaned_vertices);
263 for (auto f : faces(e))
264 if (find(m_invalid_faces, f) == m_invalid_faces.end()) remove(f);
265 }
266
267 //----------------------------------------------------------------------------
268 constexpr void remove(face f, bool remove_orphaned_vertices = true,
269 bool remove_orphaned_edges = true) {
270 using namespace boost;
271 if (is_valid(f)) {
272 if (find(m_invalid_faces, f) == m_invalid_faces.end())
273 m_invalid_faces.push_back(f);
274 if (remove_orphaned_vertices)
275 for (auto v : vertices(f))
276 if (num_faces(v) <= 1) remove(v);
277
278 if (remove_orphaned_edges)
279 for (auto e : edges(f))
280 if (num_faces(e) <= 1) remove(e, remove_orphaned_vertices);
281
282 // remove face link from vertices
283 for (auto v : vertices(f)) faces(v).erase(find(faces(v), f));
284
285 // remove face link from edges
286 for (auto e : edges(f)) faces(e).erase(find(faces(e), f));
287 edges(f).clear();
288 }
289 }
290
291#ifdef USE_TRIANGLE
292 //----------------------------------------------------------------------------
293 void triangulate_face(const std::vector<vertex>& polygon) requires (N == 2){
294 if (polygon.size() == 3)
295 insert_face(polygon[0], polygon[1], polygon[2]);
296 else if (polygon.size() == 4) {
297 insert_face(polygon[0], polygon[1], polygon[2]);
298 insert_face(polygon[0], polygon[2], polygon[3]);
299 } else {
300 triangle::api api;
301 api.behaviour().firstnumber = 0;
302 api.behaviour().poly = true;
303 api.behaviour().usesegments = true;
304 auto contour = to_triangle_io(polygon);
305 contour.numberofsegments = polygon.size();
306 contour.segmentlist = new int[contour.numberofsegments * 2];
307 for (size_t i = 0; i < polygon.size(); ++i) {
308 contour.segmentlist[i * 2] = i;
309 contour.segmentlist[i * 2 + 1] = (i + 1) % polygon.size();
310 }
311
312 api.mesh_create(contour);
313 auto triangulated_contour = api.mesh_copy();
314 // assert(contour.numberofpoints == triangulated_contour.numberofpoints);
315 for (int i = 0; i < contour.numberofpoints * 2; ++i)
316 assert(contour.pointlist[i] == triangulated_contour.pointlist[i]);
317 for (int i = 0; i < triangulated_contour.numberoftriangles; ++i)
318 if (triangulated_contour.trianglelist[i * 3] < polygon.size() &&
319 triangulated_contour.trianglelist[i * 3 + 1] < polygon.size() &&
320 triangulated_contour.trianglelist[i * 3 + 2] < polygon.size())
321 insert_face(polygon[triangulated_contour.trianglelist[i * 3]],
322 polygon[triangulated_contour.trianglelist[i * 3 + 1]],
323 polygon[triangulated_contour.trianglelist[i * 3 + 2]]);
324 }
325 }
326
327 //----------------------------------------------------------------------------
328 inline auto triangulate_face(face f) requires(N == 2) {
329 std::vector<vertex> polygon;
330 polygon.reserve(num_vertices(f));
331 for (auto v : vertices(f)) polygon.push_back(v);
332 triangulate_face(polygon);
333 }
334#endif
335
336 //----------------------------------------------------------------------------
338 void tidy_up() {
339 using namespace boost;
340 for (auto invalid_f : m_invalid_faces) {
341 // decrease face-index of vertices whose indices are greater than an
342 // invalid face index
343 for (auto& faces : *m_faces_of_vertices)
344 for (auto& f : faces)
345 if (f.i > invalid_f.i) --f.i;
346
347 // decrease face-index of edges whose indices are greater than an invalid
348 // face-index
349 for (auto& faces : *m_faces_of_edges)
350 for (auto& f : faces)
351 if (f.i > invalid_f.i) --f.i;
352 }
353 // decrease edge-index of faces whose indices are greater than an invalid
354 // edge-index
355 for (auto invalid_e : this->m_invalid_edges)
356 for (auto& edges : *m_edges_of_faces)
357 for (auto& e : edges)
358 if (e.i >= invalid_e.i) --e.i;
359
360 // reindex face's vertex indices
361 for (const auto v : this->m_invalid_points)
362 for (auto f : faces())
363 for (auto& f_v : at(f))
364 if (f_v.i > v.i) --f_v.i;
365
366 // erase actual faces
367 for (const auto f : m_invalid_faces) {
368 // reindex deleted faces indices;
369 for (auto& f_to_reindex : m_invalid_faces)
370 if (f_to_reindex.i > f.i) --f_to_reindex.i;
371
372 m_faces.erase(m_faces.begin() + f.i);
373 for (const auto& [key, prop] : m_face_properties) { prop->erase(f.i); }
374 }
375 m_invalid_faces.clear();
376
377 // tidy up vertices
379 }
380
381 //----------------------------------------------------------------------------
382 constexpr bool is_valid(face f) const {
383 return boost::find(m_invalid_faces, f) == m_invalid_faces.end();
384 }
385
386 //----------------------------------------------------------------------------
387 constexpr auto insert_edges(face f) {
388 const auto& vertices = at(f);
389 std::vector<edge> edges;
390 edges.reserve(vertices.size());
391 for (size_t i = 0; i < vertices.size(); ++i)
392 edges.push_back(
393 insert_edge(vertices[i], vertices[(i + 1) % vertices.size()]));
394 return edges;
395 }
396
397 //----------------------------------------------------------------------------
398 constexpr void clear_faces() {
399 m_faces.clear();
400 m_faces.shrink_to_fit();
401 m_invalid_faces.clear();
402 m_invalid_faces.shrink_to_fit();
403 }
404
405 //----------------------------------------------------------------------------
406 void clear() {
408 clear_faces();
409 }
410
411 //----------------------------------------------------------------------------
412 constexpr auto num_faces(vertex v) const { return faces(v).size(); }
413 constexpr auto num_faces(edge e) const { return faces(e).size(); }
414 constexpr auto num_faces() const {
415 return m_faces.size() - m_invalid_faces.size();
416 }
417 constexpr auto num_edges(face f) const { return edges(f).size(); }
418
419 //----------------------------------------------------------------------------
420 constexpr auto faces() const { return face_container{this}; }
421 auto& faces(vertex v) { return m_faces_of_vertices->at(v); }
422 const auto& faces(vertex v) const { return m_faces_of_vertices->at(v); }
423 auto& faces(edge e) { return m_faces_of_edges->at(e); }
424 const auto& faces(edge e) const { return m_faces_of_edges->at(e); }
425 auto& edges(face f) { return m_edges_of_faces->at(f); }
426 const auto& edges(face f) const { return m_edges_of_faces->at(f); }
427 auto& vertices(face f) { return at(f); }
428 const auto& vertices(face f) const { return at(f); }
429 auto neighbor_faces(face f) const {
430 std::vector<face> neighbors;
431 for (auto e : edges(f)) {
432 for (auto nf : faces(e)) {
433 if (nf != f) { neighbors.push_back(nf); }
434 }
435 }
436 return neighbors;
437 }
438
439 //----------------------------------------------------------------------------
440 constexpr bool has_vertex(face f, vertex v) const {
441 return boost::find(at(f), v) != end(at(f));
442 }
443
444 //----------------------------------------------------------------------------
445 constexpr bool face_has_edge(face f, edge e) const {
446 return has_vertex(f, this->at(e)[0]) &&
447 has_vertex(f, this->at(e)[1]);
448 }
449
450 //----------------------------------------------------------------------------
451 constexpr auto num_vertices(face f) const { return at(f).size(); }
452
453#ifdef USE_TRIANGLE
454 //----------------------------------------------------------------------------
455 auto to_triangle_io() const {
456 auto io = parent_type::to_triangle_io();
457
458 // Define input points
459 io.numberoftriangles = num_faces();
460 io.numberofcorners = 3;
461
462 // copy faces
463 io.trianglelist = new int[io.numberoftriangles * io.numberofcorners];
464 size_t i = 0;
465 for (auto f : faces()) {
466 const auto& face = at(f);
467 for (unsigned int j = 0; j < 3; ++j) io.pointlist[i + j] = face[i].i;
468 i += 3;
469 }
470 return io;
471 }
472
473 //----------------------------------------------------------------------------
476 auto to_triangle_io(const std::vector<vertex>& vertices) const {
478
479 std::set<face> fs;
480 for (auto v : vertices)
481 for (auto f : faces(v)) fs.insert(f);
482
483 // Define input points
484 io.numberoftriangles = fs.size();
485 io.numberofcorners = 3;
486
487 // copy faces
488 io.trianglelist = new int[io.numberoftriangles * io.numberofcorners];
489 size_t i = 0;
490 for (auto f : fs) {
491 const auto& face = at(f);
492 // faces are not indexed by global pointlist
493 for (unsigned int j = 0; j < 3; ++j) io.trianglelist[i + j] = face[j].i;
494 i += 3;
495 }
496
497 // reindex points to local list of vertices
498 for (int i = 0; i < io.numberoftriangleattributes * 3; ++i)
499 for (size_t j = 0; j < vertices.size(); ++j)
500 if (io.trianglelist[i] == int(vertices[j].i)) {
501 io.trianglelist[i] = j;
502 break;
503 }
504 return io;
505 }
506#endif
507
508 //----------------------------------------------------------------------------
509 // void to_tetgen_io(tetgenio& in) const {
510 // parent_type::to_tetgen_io(in);
511 //
512 // // Define input points
513 // in.numberoffacets = num_faces();
514 //
515 // // copy faces
516 // in.facetlist = new tetgen::io::facet[in.numberoffacets];
517 // size_t i = 0;
518 // for (auto f : faces()) {
519 // auto& facet = in.facetlist[i++];
520 // facet.numberofholes = 0;
521 // facet.holelist = nullptr;
522 // facet.numberofpolygons = 1;
523 // facet.polygonlist = new tetgen::io::polygon[1];
524 // auto& poly = facet.polygonlist[0];
525 // poly.numberofvertices = num_vertices(f);
526 // poly.vertexlist = new int[poly.numberofvertices];
527 // size_t j = 0;
528 // for (auto v : at(f)) poly.vertexlist[j++] = v.i;
529 // }
530 // }
531
532 //----------------------------------------------------------------------------
533 // void to_tetgen_io(tetgenio& in, const std::vector<face>& fs) const {
534 // std::map<vertex, int> vertex_mapping;
535 // in.numberofpoints = 0;
536 // for (auto f : fs) {
537 // for (auto v : vertices(f)) {
538 // if (vertex_mapping.find(v) == end(vertex_mapping)) {
539 // vertex_mapping[v] = in.numberofpoints++;
540 // }
541 // }
542 // }
543 // in.pointlist = new tetgen::Real[in.numberofpoints * 3];
544 // in.pointmarkerlist = new int[in.numberofpoints];
545 // in.numberofpointattributes = 1;
546 // in.pointattributelist =
547 // new tetgen::real_type[in.numberofpoints * in.numberofpointattributes];
548 // for (const auto& [v, i] : vertex_mapping) {
549 // in.pointlist[i * 3] = at(v)(0);
550 // in.pointlist[i * 3 + 1] = at(v)(1);
551 // in.pointlist[i * 3 + 2] = at(v)(2);
552 // in.pointmarkerlist[i] = -1;
553 // in.pointattributelist[i] = v.i;
554 // }
555 //
556 // // Define input points
557 // in.numberoffacets = fs.size();
558 //
559 // // copy faces
560 // in.facetlist = new tetgen::io::facet[in.numberoffacets];
561 // size_t i = 0;
562 // for (auto f : fs) {
563 // auto& facet = in.facetlist[i++];
564 // facet.numberofholes = 0;
565 // facet.holelist = nullptr;
566 // facet.numberofpolygons = 1;
567 // facet.polygonlist = new tetgen::io::polygon[1];
568 // auto& poly = facet.polygonlist[0];
569 // poly.numberofvertices = num_vertices(f);
570 // poly.vertexlist = new int[poly.numberofvertices];
571 // size_t j = 0;
572 // for (auto v : at(f)) {
573 // assert(vertex_mapping.find(v) != end(vertex_mapping));
574 // poly.vertexlist[j++] = vertex_mapping[v];
575 // }
576 // }
577 // }
578
579 //----------------------------------------------------------------------------
580 template <typename T>
581 auto& face_property(const std::string& name) {
582 return *dynamic_cast<face_prop<T>*>(m_face_properties.at(name).get());
583 }
584
585 //----------------------------------------------------------------------------
586 template <typename T>
587 const auto& face_property(std::string const& name) const {
588 return *dynamic_cast<face_prop<T>*>(m_face_properties.at(name).get());
589 }
590
591 //----------------------------------------------------------------------------
592 template <typename T>
593 auto& add_face_property(const std::string& name, const T& value = T{}) {
594 auto [it, suc] = m_face_properties.insert(
595 std::pair{name, std::make_unique<face_prop<T>>(value)});
596 auto prop = dynamic_cast<face_prop<T>*>(it->second.get());
597 prop->resize(m_faces.size());
598 return *prop;
599 }
600
601 //----------------------------------------------------------------------------
602 void write(const std::string& path) {
603 auto ext = path.substr(path.find_last_of(".") + 1);
604 if constexpr (N == 2 || N == 3) {
605 if (ext == "vtk") {
606 write_vtk(path);
607 } else if (ext == "obj") {
608 write_obj(path);
609 }
610 }
611 }
612
613 //----------------------------------------------------------------------------
614 void write_obj(const std::string& path) requires(N == 2 || N == 3) {
615 std::ofstream fout(path);
616 if (fout) {
617 for (auto v : vertices())
618 if constexpr (N == 2)
619 fout << "v " << at(v)(0) << ' ' << at(v)(1) << " 0\n";
620 else if constexpr (N == 3)
621 fout << "v " << at(v)(0) << ' ' << at(v)(1) << " " << at(v)(2)
622 << '\n';
623 for (auto f : faces())
624 fout << "f " << at(f)[0].i + 1 << ' ' << at(f)[1].i + 1 << ' '
625 << at(f)[2].i + 1 << '\n';
626 fout.close();
627 }
628 }
629
630 //----------------------------------------------------------------------------
631 void write_vtk(const std::string& path,
632 const std::string& title = "tatooine mesh") const requires(N == 2 || N == 3){
633 vtk::legacy_file_writer writer(path, vtk::POLYDATA);
634 if (writer.is_open()) {
635 writer.set_title(title);
636 writer.write_header();
637
638 // write points
639 std::vector<std::array<Real, 3>> points;
640 points.reserve(this->m_points.size());
641 for (const auto& p : this->m_points) {
642 if constexpr (N == 3) {
643 points.push_back({p(0), p(1), p(2)});
644 } else {
645 points.push_back({p(0), p(1), 0});
646 }
647 }
648 writer.write_points(points);
649
650 // write faces
651 std::vector<std::vector<size_t>> polygons;
652 polygons.reserve(m_faces.size());
653 for (const auto& f : faces()) {
654 polygons.emplace_back();
655 for (const auto v : at(f)) polygons.back().push_back(v.i);
656 }
657 writer.write_polygons(polygons);
658
659 // write point data
660 // TODO uncomment if vertices have edge and face properties
661 if (this->m_vertex_properties.size() > 2) {
662 writer.write_point_data(this->m_points.size());
663 for (const auto& [name, prop] : this->m_vertex_properties) {
664 if (name != "v:edges" && name != "v:faces") {
665 std::vector<std::vector<Real>> data;
666 data.reserve(this->m_points.size());
667
668 if (prop->type() == typeid(vec<Real, 4>)) {
669 for (const auto& v4 :
670 *dynamic_cast<const vertex_prop<vec<Real, 4>>*>(
671 prop.get()))
672 data.push_back({v4(0), v4(1), v4(2), v4(3)});
673
674 } else if (prop->type() == typeid(vec<Real, 3>)) {
675 for (const auto& v3 :
676 *dynamic_cast<const vertex_prop<vec<Real, 3>>*>(
677 prop.get()))
678 data.push_back({v3(0), v3(1), v3(2)});
679
680 } else if (prop->type() == typeid(vec<Real, 2>)) {
681 const auto& casted_prop =
682 *dynamic_cast<const vertex_prop<vec<Real, 2>>*>(prop.get());
683 for (const auto& v2 : casted_prop) data.push_back({v2(0), v2(1)});
684
685 } else if (prop->type() == typeid(Real)) {
686 for (const auto& scalar :
687 *dynamic_cast<const vertex_prop<Real>*>(prop.get()))
688 data.push_back({scalar});
689 }
690 if (!data.empty()) writer.write_scalars(name, data);
691 }
692 }
693 }
694
695 // write cell data
696 if (m_face_properties.size() > 1) {
697 writer.write_cell_data(m_faces.size());
698 for (const auto& [name, prop] : m_face_properties) {
699 if (name != "f:edges") {
700 if (prop->type() == typeid(vec<Real, 4>)) {
701 std::vector<std::vector<Real>> data;
702 data.reserve(m_faces.size());
703 for (const auto& v4 :
704 *dynamic_cast<const face_prop<vec<Real, 4>>*>(prop.get()))
705 data.push_back({v4(0), v4(1), v4(2), v4(3)});
706 writer.write_scalars(name, data);
707
708 } else if (prop->type() == typeid(vec<Real, 3>)) {
709 std::vector<std::vector<Real>> data;
710 data.reserve(m_faces.size());
711 for (const auto& v3 :
712 *dynamic_cast<const face_prop<vec<Real, 3>>*>(prop.get()))
713 data.push_back({v3(0), v3(1), v3(2)});
714 writer.write_scalars(name, data);
715
716 } else if (prop->type() == typeid(vec<Real, 2>)) {
717 std::vector<std::vector<Real>> data;
718 data.reserve(m_faces.size());
719 for (const auto& v2 :
720 *dynamic_cast<const face_prop<vec<Real, 2>>*>(prop.get()))
721 data.push_back({v2(0), v2(1)});
722 writer.write_scalars(name, data);
723
724 } else if (prop->type() == typeid(double)) {
725 std::vector<std::vector<double>> data;
726 data.reserve(m_faces.size());
727 for (const auto& scalar :
728 *dynamic_cast<const face_prop<double>*>(prop.get()))
729 data.push_back({scalar});
730 writer.write_scalars(name, data);
731
732 } else if (prop->type() == typeid(float)) {
733 std::vector<std::vector<float>> data;
734 data.reserve(m_faces.size());
735 for (const auto& scalar :
736 *dynamic_cast<const face_prop<float>*>(prop.get()))
737 data.push_back({scalar});
738 writer.write_scalars(name, data);
739 }
740 }
741 }
742 }
743 writer.close();
744 }
745 }
746
748 bool are_neighbors(face f0, face f1) {
749 for (auto v0 : vertices(f0)) {
750 for (auto v1 : vertices(f1)) {
751 if (v0 == v1) { return true; }
752 }
753 }
754 return false;
755 }
756
757 //----------------------------------------------------------------------------
758 template <typename face_cont_t>
759 auto adjacent_faces(const face_cont_t& faces) {
760 using groups_t = std::list<std::vector<face>>;
761 using groups_it_t = typename groups_t::iterator;
762 groups_t groups;
763 for (auto f : faces) {
764 std::vector<groups_it_t> insertions;
765 for (auto groups_it = groups.begin(); groups_it != groups.end();
766 ++groups_it)
767 for (auto gf : *groups_it)
768 if (are_neighbors(f, gf)) {
769 insertions.push_back(groups_it);
770 break;
771 }
772
773 // no group was found -> create new group
774 if (insertions.empty()) groups.emplace_back().push_back(f);
775 // exactly one match -> just insert face
776 else if (insertions.size() == 1)
777 insertions.front()->push_back(f);
778
779 // multiple matches -> merge groups and insert face in first match
780 else {
781 insertions.front()->push_back(f);
782 for (size_t i = 1; i < insertions.size(); ++i) {
783 boost::copy(*insertions[i], std::back_inserter(*insertions.front()));
784 groups.erase(insertions[i]);
785 }
786 }
787 }
788
789 return groups;
790 }
791
792 //----------------------------------------------------------------------------
796 template <typename face_cont_t>
797 auto border_edges(const face_cont_t& faces) const {
798 std::map<edge, size_t> edge_counts;
799 for (auto f : faces)
800 for (auto e : edges(f)) ++edge_counts[e];
801
802 std::set<edge> es;
803 for (const auto& [e, cnt] : edge_counts)
804 if (cnt == 1) es.insert(e);
805
806 return es;
807 }
808
809 //----------------------------------------------------------------------------
811 template <typename edge_cont_t>
812 auto split_border_edges(const edge_cont_t& edges) {
813 std::vector<std::set<edge>> splitted_edges;
814 bool inserted = false;
815 for (auto e : edges) {
816 inserted = false;
817 for (auto& cont : splitted_edges)
818 for (auto inserted_edge : cont) {
819 if (at(inserted_edge)[0] == at(e)[0] ||
820 at(inserted_edge)[0] == at(e)[1] ||
821 at(inserted_edge)[1] == at(e)[0] ||
822 at(inserted_edge)[1] == at(e)[1]) {
823 cont.insert(e);
824 inserted = true;
825 break;
826 }
827 if (inserted) break;
828 }
829 if (!inserted) splitted_edges.emplace_back().insert(e);
830 }
831 return splitted_edges;
832 }
833
834 //----------------------------------------------------------------------------
838 template <typename edge_cont_t>
839 auto border_edges_to_vertices(const edge_cont_t& edges) {
840 std::vector<vertex> polygon;
841 // insert first edge
842 polygon.push_back(at(*edges.begin())[0]);
843 polygon.push_back(at(*edges.begin())[1]);
844
845 bool searching = true;
846 size_t i = 0;
847 while (searching) {
848 for (auto e_it = next(begin(edges)); e_it != end(edges); ++e_it) {
849 auto e = *e_it;
850 i = 2;
851 if (at(e)[0] == polygon.back() && at(e)[1] != *prev(end(polygon), 2))
852 i = 1;
853
854 else if (at(e)[1] == polygon.back() &&
855 at(e)[0] != *prev(end(polygon), 2))
856 i = 0;
857
858 // next edge found
859 if (i < 2) {
860 // insert vertex and check if other vertex of edge is beginning of
861 // polygon
862 if (polygon.front() == at(e)[i])
863 searching = false;
864 else {
865 polygon.push_back(at(e)[i]);
866 }
867 break;
868 }
869 }
870 }
871 return polygon;
872 }
873
874 //----------------------------------------------------------------------------
875 static bool is_left(const pos_type& a, const pos_type& b, const pos_type& c) {
876 return ((b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0])) >= 0;
877 }
878
879 //----------------------------------------------------------------------------
881 const std::vector<vertex>& polygon) requires(N == 2) {
882 size_t left_turns = 0;
883 size_t right_turns = 0;
884 for (size_t i_0 = 0; i_0 < polygon.size(); ++i_0) {
885 auto i_1 = (i_0 + 1) % polygon.size();
886 auto i_2 = (i_0 + 2) % polygon.size();
887 if (is_left(at(polygon[i_0]), at(polygon[i_1]), at(polygon[i_2])))
888 ++left_turns;
889 else
890 ++right_turns;
891 }
892 return left_turns > right_turns;
893 }
894
895 //----------------------------------------------------------------------------
896 template <typename face_cont_t>
897 auto border_polygons(const face_cont_t& faces,
898 bool check_counterclockwise = true) {
899 auto border_loops = split_border_edges(border_edges(faces));
900 std::vector<std::vector<vertex>> polygons;
901 for (const auto& loop : border_loops) {
902 polygons.push_back(border_edges_to_vertices(loop));
903 if (check_counterclockwise &&
904 !polygon_is_counter_clockwise(polygons.back()))
905 reverse(begin(polygons.back()), end(polygons.back()));
906 }
907 return polygons;
908 }
909
910 //============================================================================
912 static bool same_rotation(const std::vector<vertex>& lhs,
913 const std::vector<vertex>& rhs) {
914 auto lit = begin(lhs);
915 auto rit = begin(rhs);
916 bool equal = true;
917 for (; lit != end(lhs); ++lit, ++rit) {
918 if (*lit != *rit) {
919 equal = false;
920 break;
921 }
922 }
923 return equal;
924 }
925
926 //--------------------------------------------------------------------------
927 static bool different_rotation(const std::vector<vertex>& lhs,
928 const std::vector<vertex>& rhs) {
929 auto lit = begin(lhs);
930 auto rit = begin(rhs);
931 bool equal = true;
932 for (; lit != end(lhs); ++lit, --rit) {
933 if (*lit != *rit) {
934 equal = false;
935 break;
936 }
937 if (rit == begin(rhs)) rit = end(rhs);
938 }
939 return equal;
940 }
941
942 //--------------------------------------------------------------------------
943 bool operator()(const std::vector<vertex>& lhs,
944 const std::vector<vertex>& rhs) const {
945 if (lhs.size() != rhs.size()) return false;
946 if (same_rotation(lhs, rhs)) return true;
947 return different_rotation(lhs, rhs);
948 }
949 };
950};
951
952#ifdef USE_TRIANGLE
953//------------------------------------------------------------------------------
954template <typename Real>
955inline auto delaunay(const pointset<2, Real>& ps) {
956 triangle::api api;
957 api.behaviour().firstnumber = 0;
958 api.mesh_create(ps.to_triangle_io());
959 return mesh<2, Real>{api.mesh_copy()};
960}
961
962//------------------------------------------------------------------------------
963template <typename Real>
964inline auto delaunay(
965 const pointset<2, Real>& ps,
966 const std::vector<typename pointset<2, Real>::vertex>& vertices) {
967 triangle::api api;
968 api.behaviour().firstnumber = 0;
969 api.mesh_create(ps.to_triangle_io(vertices));
970 return mesh<2, Real>{api.mesh_copy()};
971}
972
973//------------------------------------------------------------------------------
974template <typename Real>
976 triangle::api api;
977 api.behaviour().firstnumber = 0;
978 api.behaviour().poly = true;
979 api.behaviour().usesegments = true;
980 auto contour = es.to_triangle_io();
981 contour.numberofsegments = es.num_edges();
982 size_t i;
983
984 i = 0;
985 contour.segmentlist = new int[contour.numberofsegments * 2];
986 for (auto e : es.edges()) {
987 contour.segmentlist[i] = es[e][0].i;
988 contour.segmentlist[i + 1] = es[e][1].i;
989 i += 2;
990 }
991
992 api.mesh_create(contour);
993 return mesh<2, Real>{api.mesh_copy()};
994}
995
996//------------------------------------------------------------------------------
997template <typename Real>
999 const pointset<2, Real>& ps,
1000 const std::vector<typename pointset<2, Real>::vertex>& polygon) {
1001 triangle::api api;
1002 api.behaviour().firstnumber = 0;
1003 api.behaviour().poly = true;
1004 api.behaviour().usesegments = true;
1005 auto contour = ps.to_triangle_io(polygon);
1006 contour.numberofsegments = polygon.size();
1007 size_t i = 0;
1008 contour.segmentlist = new int[contour.numberofsegments * 2];
1009 for (size_t j = 0; j < polygon.size(); ++j, i += 2) {
1010 contour.segmentlist[i] = j;
1011 contour.segmentlist[i + 1] = (j + 1) % polygon.size();
1012 }
1013
1014 api.mesh_create(contour);
1015 return mesh<2, Real>{api.mesh_copy()};
1016}
1017
1018//------------------------------------------------------------------------------
1019template <typename Real>
1021 triangle::real_type minangle = 0,
1022 triangle::real_type maxarea = 0) {
1023 triangle::api api;
1024 api.options("zpq" + std::to_string(minangle));
1025 if (maxarea > 0)
1026 api.options("zpq" + std::to_string(minangle) + "a" +
1027 std::to_string(maxarea));
1028 else
1029 api.options("zpq" + std::to_string(minangle));
1030
1031 auto contour = es.to_triangle_io();
1032 contour.numberofsegments = es.num_edges();
1033 size_t i = 0;
1034 contour.segmentlist = new int[contour.numberofsegments * 2];
1035 for (auto e : es.edges()) {
1036 contour.segmentlist[i++] = es[e][0].i;
1037 contour.segmentlist[i++] = es[e][1].i;
1038 }
1039
1040 api.mesh_create(contour);
1041 return mesh<2, Real>{api.mesh_copy()};
1042}
1043#endif
1044
1045//==============================================================================
1046} // namespace tatooine
1047//==============================================================================
1048
1049#endif
1050
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: mesh.h:16
constexpr const auto & at(face f) const
Definition: mesh.h:216
face_prop< std::vector< edge > > * m_edges_of_faces
Definition: mesh.h:125
auto & faces(edge e)
Definition: mesh.h:423
void remove(vertex v)
Definition: mesh.h:252
const auto & face_property(std::string const &name) const
Definition: mesh.h:587
typename parent_type::template vertex_prop< T > vertex_prop
Definition: mesh.h:95
auto border_polygons(const face_cont_t &faces, bool check_counterclockwise=true)
Definition: mesh.h:897
constexpr bool is_valid(face f) const
Definition: mesh.h:382
constexpr auto insert_face(same_as< vertex > auto const ... vs)
Definition: mesh.h:223
constexpr void clear_faces()
Definition: mesh.h:398
bool are_neighbors(face f0, face f1)
checks if two faces are neighbors
Definition: mesh.h:748
std::vector< std::vector< vertex > > m_faces
Definition: mesh.h:118
auto to_triangle_io(const std::vector< vertex > &vertices) const
Definition: mesh.h:476
auto & add_face_property(const std::string &name, const T &value=T{})
Definition: mesh.h:593
mesh(mesh &&other)
Definition: mesh.h:162
void find_link_properties()
Definition: mesh.h:204
auto to_triangle_io() const
Definition: mesh.h:455
constexpr mesh()
Definition: mesh.h:129
static bool is_left(const pos_type &a, const pos_type &b, const pos_type &c)
Definition: mesh.h:875
constexpr auto num_edges(face f) const
Definition: mesh.h:417
constexpr auto num_vertices(face f) const
Definition: mesh.h:451
mesh(const triangle::io &io)
Definition: mesh.h:139
constexpr auto num_faces(vertex v) const
Definition: mesh.h:412
auto & operator=(const mesh &other)
Definition: mesh.h:171
void triangulate_face(const std::vector< vertex > &polygon)
Definition: mesh.h:293
edge_prop< std::vector< face > > * m_faces_of_edges
Definition: mesh.h:123
auto neighbor_faces(face f) const
Definition: mesh.h:429
void tidy_up()
tidies up invalid vertices, edges and faces
Definition: mesh.h:338
constexpr auto faces() const
Definition: mesh.h:420
void remove(edge e, bool remove_orphaned_vertices=true)
Definition: mesh.h:260
auto & vertices(face f)
Definition: mesh.h:427
void write(const std::string &path)
Definition: mesh.h:602
constexpr auto num_faces() const
Definition: mesh.h:414
auto border_edges_to_vertices(const edge_cont_t &edges)
Definition: mesh.h:839
constexpr mesh(std::initializer_list< pos_type > &&vertices)
Definition: mesh.h:132
auto adjacent_faces(const face_cont_t &faces)
Definition: mesh.h:759
auto & faces(vertex v)
Definition: mesh.h:421
constexpr auto & at(face f)
Definition: mesh.h:215
const auto & faces(vertex v) const
Definition: mesh.h:422
constexpr const auto & operator[](face f) const
Definition: mesh.h:220
const auto & faces(edge e) const
Definition: mesh.h:424
constexpr auto & operator[](face f)
Definition: mesh.h:219
auto & edges(face f)
Definition: mesh.h:425
vertex_prop< std::vector< face > > * m_faces_of_vertices
Definition: mesh.h:122
typename parent_type::template edge_prop< T > edge_prop
Definition: mesh.h:99
constexpr bool has_vertex(face f, vertex v) const
Definition: mesh.h:440
constexpr auto insert_edges(face f)
Definition: mesh.h:387
std::vector< face > m_invalid_faces
Definition: mesh.h:119
auto border_edges(const face_cont_t &faces) const
Definition: mesh.h:797
constexpr bool face_has_edge(face f, edge e) const
Definition: mesh.h:445
void clear()
Definition: mesh.h:406
constexpr auto num_faces(edge e) const
Definition: mesh.h:413
constexpr auto insert_face(std::vector< vertex > new_face)
Definition: mesh.h:228
std::map< std::string, std::unique_ptr< property > > m_face_properties
Definition: mesh.h:120
const auto & edges(face f) const
Definition: mesh.h:426
void add_link_properties()
Definition: mesh.h:193
const auto & vertices(face f) const
Definition: mesh.h:428
auto triangulate_face(face f)
Definition: mesh.h:328
void write_vtk(const std::string &path, const std::string &title="tatooine mesh") const
Definition: mesh.h:631
void write_obj(const std::string &path)
Definition: mesh.h:614
mesh(const mesh &other)
Definition: mesh.h:151
bool polygon_is_counter_clockwise(const std::vector< vertex > &polygon)
Definition: mesh.h:880
auto & operator=(mesh &&other)
Definition: mesh.h:182
auto & face_property(const std::string &name)
Definition: mesh.h:581
auto split_border_edges(const edge_cont_t &edges)
searches coherent border edge loops
Definition: mesh.h:812
constexpr void remove(face f, bool remove_orphaned_vertices=true, bool remove_orphaned_edges=true)
Definition: mesh.h:268
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_cell_data(std::size_t i) -> void
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_polygons(std::vector< std::vector< std::size_t > > const &polygons) -> void
Definition: concepts.h:15
Definition: solver.h:9
typename tatooine::edgeset< Real, NumDimensions >::vertex_handle vertex
Definition: post_triangulation.h:13
Definition: algorithm.h:6
auto begin(Range &&range)
Definition: iterator_facade.h:318
auto end(Range &&range)
Definition: iterator_facade.h:322
auto constrained_delaunay(const edgeset< 2, Real > &es)
Definition: mesh.h:975
auto vertices(pointset< Real, NumDimensions > const &ps)
Definition: vertex_container.h:278
auto conforming_delaunay(const edgeset< 2, Real > &es, triangle::real_type minangle=0, triangle::real_type maxarea=0)
Definition: mesh.h:1020
auto next(Iter iter)
Definition: iterator_facade.h:325
auto delaunay(const pointset< 2, Real > &ps)
Definition: mesh.h:955
auto prev(Iter iter)
Definition: iterator_facade.h:343
vec_type pos_type
Definition: axis_aligned_bounding_box.h:109
Definition: edgeset.h:9
auto insert_edge(vertex_handle const v0, vertex_handle const v1)
Definition: edgeset.h:16
auto edges() const
Definition: edgeset.h:21
Definition: handle.h:14
static constexpr auto invalid_idx
Definition: handle.h:16
Int i
Definition: handle.h:21
Definition: mesh.h:80
auto begin() const
Definition: mesh.h:85
auto end() const
Definition: mesh.h:90
const mesh * m_mesh
Definition: mesh.h:83
Definition: mesh.h:55
face f
Definition: mesh.h:60
void decrement()
Definition: mesh.h:69
bool equal(const face_iterator &other) const
Definition: mesh.h:75
face_iterator(face _f, const mesh *_m)
Definition: mesh.h:56
void increment()
Definition: mesh.h:64
friend class boost::iterator_core_access
Definition: mesh.h:62
const mesh * m
Definition: mesh.h:61
auto dereference() const
Definition: mesh.h:76
face_iterator(const face_iterator &other)
Definition: mesh.h:57
Definition: mesh.h:103
const auto & at(face f) const
Definition: mesh.h:106
auto & at(face f)
Definition: mesh.h:105
std::unique_ptr< property > clone() const override
Definition: mesh.h:111
const auto & operator[](face f) const
Definition: mesh.h:108
auto & operator[](face f)
Definition: mesh.h:107
Definition: mesh.h:39
bool operator==(const face &other) const
Definition: mesh.h:46
face & operator=(face &&)=default
static constexpr auto invalid()
Definition: mesh.h:49
bool operator<(const face &other) const
Definition: mesh.h:48
face(face &&)=default
face & operator=(const face &)=default
face(const face &)=default
bool operator!=(const face &other) const
Definition: mesh.h:47
face(size_t i)
Definition: mesh.h:41
bool operator()(const std::vector< vertex > &lhs, const std::vector< vertex > &rhs) const
Definition: mesh.h:943
static bool different_rotation(const std::vector< vertex > &lhs, const std::vector< vertex > &rhs)
Definition: mesh.h:927
static bool same_rotation(const std::vector< vertex > &lhs, const std::vector< vertex > &rhs)
Definition: mesh.h:912
Definition: pointset.h:69
auto num_vertices() const
Definition: pointset.h:229
vertex_property_container_type m_vertex_properties
Definition: pointset.h:119
auto vertices() const
Definition: pointset.h:226
type_list_at< this_type, I > at
Definition: type_list.h:269
Definition: vec.h:12
std::map< std::string, data_array > vertices
Definition: piece.h:26
std::size_t num_vertices
Definition: piece.h:16