PolyFEM
Loading...
Searching...
No Matches
CMesh2D.cpp
Go to the documentation of this file.
3
9
10#include <geogram/basic/file_system.h>
11#include <geogram/mesh/mesh_io.h>
12#include <geogram/mesh/mesh_geometry.h>
13#include <geogram/mesh/mesh_repair.h>
14
15#include <cassert>
16#include <array>
17#include <unordered_map>
18#include <type_traits>
19
20namespace polyfem
21{
22 using namespace io;
23 using namespace utils;
24
25 namespace mesh
26 {
27 void CMesh2D::remove_elements(const std::vector<bool> &keep)
28 {
29 assert(keep.size() == n_faces());
30
31 std::unordered_map<std::pair<int, int>, int, utils::HashPair> old_edge_ids;
32 std::unordered_map<std::pair<int, int>, EdgeNodes, utils::HashPair> old_edge_nodes;
33 for (int e = 0; e < n_edges(); ++e)
34 {
35 const std::pair<int, int> key = std::minmax(edge_vertex(e, 0), edge_vertex(e, 1));
36 if (has_boundary_ids())
37 old_edge_ids[key] = boundary_ids_[e];
38 if (e < edge_nodes_.size())
39 old_edge_nodes[key] = edge_nodes_[e];
40 }
41
42 auto filter_nodes = [&keep](auto &nodes) {
43 if (nodes.size() != keep.size())
44 return;
45 std::decay_t<decltype(nodes)> filtered;
46 for (int i = 0; i < keep.size(); ++i)
47 if (keep[i])
48 filtered.push_back(nodes[i]);
49 nodes = std::move(filtered);
50 };
51 filter_nodes(face_nodes_);
52 filter_nodes(cell_nodes_);
54
55 GEO::vector<GEO::index_t> to_delete(mesh_.facets.nb(), 0);
56 for (int f = 0; f < keep.size(); ++f)
57 to_delete[f] = keep[f] ? 0 : 1;
58 mesh_.facets.delete_elements(to_delete);
59
60 c2e_.reset();
61 boundary_vertices_.reset();
62 boundary_edges_.reset();
64 c2e_ = std::make_unique<GEO::Attribute<GEO::index_t>>(mesh_.facet_corners.attributes(), "edge_id");
65 boundary_vertices_ = std::make_unique<GEO::Attribute<bool>>(mesh_.vertices.attributes(), "boundary_vertex");
66 boundary_edges_ = std::make_unique<GEO::Attribute<bool>>(mesh_.edges.attributes(), "boundary_edge");
67
68 if (!old_edge_ids.empty())
69 {
70 boundary_ids_.resize(n_edges());
71 for (int e = 0; e < n_edges(); ++e)
72 {
73 const std::pair<int, int> key = std::minmax(edge_vertex(e, 0), edge_vertex(e, 1));
74 const auto it = old_edge_ids.find(key);
75 boundary_ids_[e] = it == old_edge_ids.end() ? get_default_boundary_id(e) : it->second;
76 }
77 }
78 else
79 boundary_ids_.clear();
80
81 edge_nodes_.clear();
82 if (!old_edge_nodes.empty())
83 {
84 edge_nodes_.resize(n_edges());
85 for (int e = 0; e < n_edges(); ++e)
86 {
87 const std::pair<int, int> key = std::minmax(edge_vertex(e, 0), edge_vertex(e, 1));
88 const auto it = old_edge_nodes.find(key);
89 if (it != old_edge_nodes.end())
90 edge_nodes_[e] = it->second;
91 }
92 }
93
94 in_ordered_edges_.resize(n_edges(), 2);
95 for (int e = 0; e < n_edges(); ++e)
96 in_ordered_edges_.row(e) << edge_vertex(e, 0), edge_vertex(e, 1);
98 }
99
100 void CMesh2D::refine(const int n_refinement, const double t)
101 {
102 // return;
103 if (n_refinement <= 0)
104 {
105 return;
106 }
107
108 orders_.resize(0, 0);
109
110 bool all_simplicial = true;
111 for (int e = 0; e < n_elements(); ++e)
112 {
113 all_simplicial &= is_simplex(e);
114 }
115
116 for (int i = 0; i < n_refinement; ++i)
117 {
118 GEO::Mesh mesh;
119 mesh.copy(mesh_);
120
121 c2e_.reset();
122 boundary_vertices_.reset();
123 boundary_edges_.reset();
124
125 mesh_.clear(false, false);
126
127 // TODO add tags to the refinement
128 if (all_simplicial)
129 {
131 }
132 else if (t <= 0)
133 {
135 }
136 else
137 {
139 }
140
142 c2e_ = std::make_unique<GEO::Attribute<GEO::index_t>>(mesh_.facet_corners.attributes(), "edge_id");
143 boundary_vertices_ = std::make_unique<GEO::Attribute<bool>>(mesh_.vertices.attributes(), "boundary_vertex");
144 boundary_edges_ = std::make_unique<GEO::Attribute<bool>>(mesh_.edges.attributes(), "boundary_edge");
145 }
146
149
150 in_ordered_vertices_ = Eigen::VectorXi::LinSpaced(mesh_.vertices.nb(), 0, mesh_.vertices.nb() - 1);
151 assert(in_ordered_vertices_[0] == 0);
152 assert(in_ordered_vertices_[1] == 1);
153 assert(in_ordered_vertices_[2] == 2);
154 assert(in_ordered_vertices_[in_ordered_vertices_.size() - 1] == mesh_.vertices.nb() - 1);
155
156 in_ordered_edges_.resize(mesh_.edges.nb(), 2);
157
158 for (int e = 0; e < (int)mesh_.edges.nb(); ++e)
159 {
160 for (int lv = 0; lv < 2; ++lv)
161 {
162 in_ordered_edges_(e, lv) = mesh_.edges.vertex(e, lv);
163 }
164 assert(in_ordered_edges_(e, 0) != in_ordered_edges_(e, 1));
165 }
166 assert(in_ordered_edges_.size() > 0);
167
168 in_ordered_faces_.resize(0, 0);
169 }
170
171 bool CMesh2D::load(const std::string &path)
172 {
173 // This method should be used for special loading, like hybrid in 3d
174
175 // edge_nodes_.clear();
176 // face_nodes_.clear();
177 // cell_nodes_.clear();
178 // order_ = 1;
179
180 // c2e_.reset();
181 // boundary_vertices_.reset();
182 // boundary_edges_.reset();
183
184 // mesh_.clear(false,false);
185
186 // if (!StringUtils::endswith(path, "msh"))
187 // {
188 // Eigen::MatrixXd vertices;
189 // Eigen::MatrixXi cells;
190 // std::vector<std::vector<int>> elements;
191 // std::vector<std::vector<double>> weights;
192
193 // if(!MshReader::load(path, vertices, cells, elements, weights))
194 // return false;
195
196 // build_from_matrices(vertices, cells);
197 // attach_higher_order_nodes(vertices, elements);
198 // cell_weights_ = weights;
199 // }
200 // else
201 // {
202 // if(!mesh_load(path, mesh_))
203 // return false;
204 // }
205
206 // orient_normals_2d(mesh_);
207 // Navigation::prepare_mesh(mesh_);
208 // c2e_ = std::make_unique<GEO::Attribute<GEO::index_t>>(mesh_.facet_corners.attributes(), "edge_id");
209 // boundary_vertices_ = std::make_unique<GEO::Attribute<bool>>(mesh_.vertices.attributes(), "boundary_vertex");
210 // boundary_edges_ = std::make_unique<GEO::Attribute<bool>>(mesh_.edges.attributes(), "boundary_edge");
211
212 // compute_elements_tag();
213 assert(false);
214 return false;
215 }
216
217 bool CMesh2D::load(const GEO::Mesh &mesh)
218 {
219 edge_nodes_.clear();
220 face_nodes_.clear();
221 cell_nodes_.clear();
222
223 c2e_.reset();
224 boundary_vertices_.reset();
225 boundary_edges_.reset();
226
227 mesh_.clear(false, false);
228 mesh_.copy(mesh);
229
232 c2e_ = std::make_unique<GEO::Attribute<GEO::index_t>>(mesh_.facet_corners.attributes(), "edge_id");
233 boundary_vertices_ = std::make_unique<GEO::Attribute<bool>>(mesh_.vertices.attributes(), "boundary_vertex");
234 boundary_edges_ = std::make_unique<GEO::Attribute<bool>>(mesh_.edges.attributes(), "boundary_edge");
235
237 return true;
238 }
239
240 bool CMesh2D::save(const std::string &path) const
241 {
242 if (!mesh_save(mesh_, path))
243 return false;
244
245 return true;
246 }
247
248 bool CMesh2D::build_from_matrices(const Eigen::MatrixXd &V, const Eigen::MatrixXi &F)
249 {
250 edge_nodes_.clear();
251 face_nodes_.clear();
252 cell_nodes_.clear();
253
254 c2e_.reset();
255 boundary_vertices_.reset();
256 boundary_edges_.reset();
257
258 mesh_.clear(false, false);
260
263
264 c2e_ = std::make_unique<GEO::Attribute<GEO::index_t>>(mesh_.facet_corners.attributes(), "edge_id");
265 boundary_vertices_ = std::make_unique<GEO::Attribute<bool>>(mesh_.vertices.attributes(), "boundary_vertex");
266 boundary_edges_ = std::make_unique<GEO::Attribute<bool>>(mesh_.edges.attributes(), "boundary_edge");
267
269 return true;
270 }
271
272 void CMesh2D::attach_higher_order_nodes(const Eigen::MatrixXd &V, const std::vector<std::vector<int>> &nodes)
273 {
274 edge_nodes_.clear();
275 face_nodes_.clear();
276 cell_nodes_.clear();
277
278 edge_nodes_.resize(n_edges());
279 face_nodes_.resize(n_faces());
280
281 orders_.resize(n_faces(), 1);
282
283 assert(nodes.size() == n_faces());
284
285 for (int f = 0; f < n_faces(); ++f)
286 {
287 auto index = get_index_from_face(f);
288
289 const auto &nodes_ids = nodes[f];
290
291 if (nodes_ids.size() == 3)
292 {
293 orders_(f) = 1;
294 continue;
295 }
296 // P2
297 else if (nodes_ids.size() == 6)
298 {
299 orders_(f) = 2;
300
301 for (int le = 0; le < 3; ++le)
302 {
303 auto &n = edge_nodes_[index.edge];
304
305 // nodes not aleardy created
306 if (n.nodes.size() <= 0)
307 {
308 n.v1 = index.vertex;
309 n.v2 = switch_vertex(index).vertex;
310
311 int node_index = 0;
312 if ((n.v1 == nodes_ids[0] && n.v2 == nodes_ids[1]) || (n.v2 == nodes_ids[0] && n.v1 == nodes_ids[1]))
313 node_index = 3;
314 else if ((n.v1 == nodes_ids[1] && n.v2 == nodes_ids[2]) || (n.v2 == nodes_ids[1] && n.v1 == nodes_ids[2]))
315 node_index = 4;
316 else
317 node_index = 5;
318
319 n.nodes.resize(1, 2);
320 n.nodes << V(nodes_ids[node_index], 0), V(nodes_ids[node_index], 1);
321 n.nodes_ids.push_back(nodes_ids[node_index]);
322 }
323 index = next_around_face(index);
324 }
325 }
326 // P3
327 else if (nodes_ids.size() == 10)
328 {
329 orders_(f) = 3;
330
331 for (int le = 0; le < 3; ++le)
332 {
333 auto &n = edge_nodes_[index.edge];
334
335 // nodes not aleardy created
336 if (n.nodes.size() <= 0)
337 {
338 n.v1 = index.vertex;
339 n.v2 = switch_vertex(index).vertex;
340
341 int node_index1 = 0;
342 int node_index2 = 0;
343 if (n.v1 == nodes_ids[0] && n.v2 == nodes_ids[1])
344 {
345 node_index1 = 3;
346 node_index2 = 4;
347 }
348 else if (n.v2 == nodes_ids[0] && n.v1 == nodes_ids[1])
349 {
350 node_index1 = 4;
351 node_index2 = 3;
352 }
353 else if (n.v1 == nodes_ids[1] && n.v2 == nodes_ids[2])
354 {
355 node_index1 = 5;
356 node_index2 = 6;
357 }
358 else if (n.v2 == nodes_ids[1] && n.v1 == nodes_ids[2])
359 {
360 node_index1 = 6;
361 node_index2 = 5;
362 }
363 else if (n.v1 == nodes_ids[2] && n.v2 == nodes_ids[0])
364 {
365 node_index1 = 7;
366 node_index2 = 8;
367 }
368 else
369 {
370 assert(n.v2 == nodes_ids[2] && n.v1 == nodes_ids[0]);
371 node_index1 = 8;
372 node_index2 = 7;
373 }
374
375 n.nodes.resize(2, 2);
376 n.nodes.row(0) << V(nodes_ids[node_index1], 0), V(nodes_ids[node_index1], 1);
377 n.nodes.row(1) << V(nodes_ids[node_index2], 0), V(nodes_ids[node_index2], 1);
378
379 n.nodes_ids.push_back(nodes_ids[node_index1]);
380 n.nodes_ids.push_back(nodes_ids[node_index2]);
381 }
382 index = next_around_face(index);
383 }
384
385 {
386 auto &n = face_nodes_[f];
387 n.v1 = mesh_.facets.vertex(f, 0);
388 n.v2 = mesh_.facets.vertex(f, 1);
389 n.v3 = mesh_.facets.vertex(f, 2);
390 n.nodes.resize(1, 2);
391 n.nodes << V(nodes_ids[9], 0), V(nodes_ids[9], 1);
392 n.nodes_ids.push_back(nodes_ids[9]);
393 }
394 }
395 // P4
396 else if (nodes_ids.size() == 15)
397 {
398 orders_(f) = 4;
399 assert(false);
400 // unsupported P4 for geometry, need meshes for testing
401 }
402 // unsupported
403 else
404 {
405 assert(false);
406 }
407 }
408
409 if (orders_.maxCoeff() == 1)
410 orders_.resize(0, 0);
411 }
412
413 std::pair<RowVectorNd, int> CMesh2D::edge_node(const Navigation::Index &index, const int n_new_nodes, const int i) const
414 {
415 if (orders_.size() <= 0 || orders_(index.face) == 1 || edge_nodes_.empty() || edge_nodes_[index.edge].nodes.rows() != n_new_nodes)
416 {
417 const auto v1 = point(index.vertex);
418 const auto v2 = point(switch_vertex(index).vertex);
419
420 const double t = i / (n_new_nodes + 1.0);
421
422 return std::make_pair((1 - t) * v1 + t * v2, -1);
423 }
424
425 const auto &n = edge_nodes_[index.edge];
426 if (n.v1 == index.vertex)
427 return std::make_pair(n.nodes.row(i - 1), n.nodes_ids[i - 1]);
428 else
429 {
430 assert(n.v2 == index.vertex);
431 return std::make_pair(n.nodes.row(n.nodes.rows() - i), n.nodes_ids[n.nodes_ids.size() - i]);
432 }
433 }
434
435 std::pair<RowVectorNd, int> CMesh2D::face_node(const Navigation::Index &index, const int n_new_nodes, const int i, const int j) const
436 {
437 if (is_simplex(index.face))
438 {
439 if (orders_.size() <= 0 || orders_(index.face) == 1 || orders_(index.face) == 2 || face_nodes_.empty() || face_nodes_[index.face].nodes.rows() != n_new_nodes)
440 {
441 const auto v1 = point(index.vertex);
442 const auto v2 = point(switch_vertex(index).vertex);
443 const auto v3 = point(switch_vertex(switch_edge(index)).vertex);
444
445 const double b2 = i / (n_new_nodes + 2.0);
446 const double b3 = j / (n_new_nodes + 2.0);
447 const double b1 = 1 - b3 - b2;
448 assert(b3 < 1);
449 assert(b3 > 0);
450
451 return std::make_pair(b1 * v1 + b2 * v2 + b3 * v3, -1);
452 }
453
454 assert(orders_(index.face) == 3);
455 // unsupported P4 for geometry
456 const auto &n = face_nodes_[index.face];
457 return std::make_pair(n.nodes.row(0), n.nodes_ids[0]);
458 }
459 else if (is_cube(index.face))
460 {
461 // supports only blilinear quads
462 assert(orders_.size() <= 0 || orders_(index.face) == 1);
463
464 const auto v1 = point(index.vertex);
465 const auto v2 = point(switch_vertex(index).vertex);
466 const auto v3 = point(switch_vertex(switch_edge(switch_vertex(index))).vertex);
467 const auto v4 = point(switch_vertex(switch_edge(index)).vertex);
468
469 const double b1 = i / (n_new_nodes + 1.0);
470 const double b2 = j / (n_new_nodes + 1.0);
471
472 return std::make_pair(v1 * (1 - b1) * (1 - b2) + v2 * b1 * (1 - b2) + v3 * b1 * b2 + v4 * (1 - b1) * b2, -1);
473 }
474
475 assert(false);
476 return std::make_pair(RowVectorNd(2, 1), -1);
477 }
478
480 {
481 GEO::vec3 min_corner, max_corner;
482 GEO::get_bbox(mesh_, &min_corner[0], &max_corner[0]);
483 min.resize(2);
484 max.resize(2);
485
486 min(0) = min_corner.x;
487 min(1) = min_corner.y;
488
489 max(0) = max_corner.x;
490 max(1) = max_corner.y;
491 }
492
494 {
495
496 GEO::vec3 min_corner, max_corner;
497 GEO::get_bbox(mesh_, &min_corner[0], &max_corner[0]);
498 GEO::vec3 extent = max_corner - min_corner;
499 double scaling = std::max(extent[0], std::max(extent[1], extent[2]));
500 // const GEO::vec3 origin = 0.5 * (min_corner + max_corner);
501 const GEO::vec3 origin = min_corner;
502 for (GEO::index_t v = 0; v < mesh_.vertices.nb(); ++v)
503 {
504 mesh_.vertices.point(v) = (mesh_.vertices.point(v) - origin) / scaling;
505 }
506 Eigen::RowVector2d shift;
507 shift << origin[0], origin[1];
508 for (auto &n : edge_nodes_)
509 {
510 if (n.nodes.size() > 0)
511 n.nodes = (n.nodes.rowwise() - shift) / scaling;
512 }
513 for (auto &n : face_nodes_)
514 {
515 if (n.nodes.size() > 0)
516 n.nodes = (n.nodes.rowwise() - shift) / scaling;
517 }
518
519 logger().debug("-- bbox before normalization:");
520 logger().debug(" min : {} {}", min_corner[0], min_corner[1]);
521 logger().debug(" max : {} {}", max_corner[0], max_corner[1]);
522 logger().debug(" extent: {} {}", max_corner[0] - min_corner[0], max_corner[1] - min_corner[1]);
523 GEO::get_bbox(mesh_, &min_corner[0], &max_corner[0]);
524 logger().debug("-- bbox after normalization:");
525 logger().debug(" min : {} {}", min_corner[0], min_corner[1]);
526 logger().debug(" max : {} {}", max_corner[0], max_corner[1]);
527 logger().debug(" extent: {} {}", max_corner[0] - min_corner[0], max_corner[1] - min_corner[1]);
528
529 Eigen::MatrixXd p0, p1, p;
530 get_edges(p0, p1);
531 p = p0 - p1;
532 logger().debug("-- edge length after normalization:");
533 logger().debug(" min: {}", p.rowwise().norm().minCoeff());
534 logger().debug(" max: {}", p.rowwise().norm().maxCoeff());
535 logger().debug(" avg: {}", p.rowwise().norm().mean());
536 }
537
538 double CMesh2D::edge_length(const int gid) const
539 {
540 const int v0 = mesh_.edges.vertex(gid, 0);
541 const int v1 = mesh_.edges.vertex(gid, 1);
542
543 return (point(v0) - point(v1)).norm();
544 }
545
546 void CMesh2D::set_point(const int global_index, const RowVectorNd &p)
547 {
548 mesh_.vertices.point(global_index).x = p(0);
549 mesh_.vertices.point(global_index).y = p(1);
550 }
551
552 RowVectorNd CMesh2D::point(const int global_index) const
553 {
554 const double *ptr = mesh_.vertices.point_ptr(global_index);
555 RowVectorNd p(2);
556 p(0) = ptr[0];
557 p(1) = ptr[1];
558 return p;
559 }
560
561 bool CMesh2D::is_boundary_element(const int element_global_id) const
562 {
563 auto index = get_index_from_face(element_global_id);
564
565 for (int i = 0; i < n_face_vertices(element_global_id); ++i)
566 {
567 if (is_boundary_edge(index.edge))
568 return true;
569
570 index = next_around_face(index);
571 }
572
573 return false;
574 }
575
576 // void CMesh2D::triangulate_faces(Eigen::MatrixXi &tris, Eigen::MatrixXd &pts, std::vector<int> &ranges) const
577 // {
578 // ranges.clear();
579
580 // std::vector<Eigen::MatrixXi> local_tris(mesh_.facets.nb());
581 // std::vector<Eigen::MatrixXd> local_pts(mesh_.facets.nb());
582
583 // int total_tris = 0;
584 // int total_pts = 0;
585
586 // ranges.push_back(0);
587
588 // for (GEO::index_t f = 0; f < mesh_.facets.nb(); ++f)
589 // {
590 // const int n_vertices = mesh_.facets.nb_vertices(f);
591
592 // Eigen::MatrixXd face_pts(n_vertices, 2);
593 // // Eigen::MatrixXi edges(n_vertices,2);
594 // local_tris[f].resize(n_vertices - 2, 3);
595
596 // for (int i = 0; i < n_vertices; ++i)
597 // {
598 // const int vertex = mesh_.facets.vertex(f, i);
599 // const double *pt = mesh_.vertices.point_ptr(vertex);
600 // face_pts(i, 0) = pt[0];
601 // face_pts(i, 1) = pt[1];
602
603 // // edges(i, 0) = i;
604 // // edges(i, 1) = (i+1) % n_vertices;
605 // }
606
607 // for (int i = 1; i < n_vertices - 1; ++i)
608 // {
609 // local_tris[f].row(i - 1) << 0, i, i + 1;
610 // }
611
612 // local_pts[f] = face_pts;
613
614 // total_tris += local_tris[f].rows();
615 // total_pts += local_pts[f].rows();
616
617 // ranges.push_back(total_tris);
618
619 // assert(local_pts[f].rows() == face_pts.rows());
620 // }
621
622 // tris.resize(total_tris, 3);
623 // pts.resize(total_pts, 2);
624
625 // int tri_index = 0;
626 // int pts_index = 0;
627 // for (std::size_t i = 0; i < local_tris.size(); ++i)
628 // {
629 // tris.block(tri_index, 0, local_tris[i].rows(), local_tris[i].cols()) = local_tris[i].array() + pts_index;
630 // tri_index += local_tris[i].rows();
631
632 // pts.block(pts_index, 0, local_pts[i].rows(), local_pts[i].cols()) = local_pts[i];
633 // pts_index += local_pts[i].rows();
634 // }
635 // }
636
642
647
649 {
650 const int v0 = mesh_.edges.vertex(index, 0);
651 const int v1 = mesh_.edges.vertex(index, 1);
652
653 return 0.5 * (point(v0) + point(v1));
654 }
655
656 void CMesh2D::compute_body_ids(const std::function<int(const size_t, const std::vector<int> &, const RowVectorNd &)> &marker)
657 {
658 body_ids_.resize(n_elements());
659 std::fill(body_ids_.begin(), body_ids_.end(), -1);
660
661 for (int e = 0; e < n_elements(); ++e)
662 {
663 const auto bary = face_barycenter(e);
664 body_ids_[e] = marker(e, element_vertices(e), bary);
665 }
666 }
667
668 void CMesh2D::compute_boundary_ids(const std::function<int(const size_t, const std::vector<int> &, const RowVectorNd &, bool)> &marker)
669 {
670 boundary_ids_.resize(n_edges());
671
672 for (int e = 0; e < n_edges(); ++e)
673 {
674 bool is_boundary = is_boundary_edge(e);
675 const auto p = edge_barycenter(e);
676 std::vector<int> vs = {edge_vertex(e, 0), edge_vertex(e, 1)};
677 std::sort(vs.begin(), vs.end());
678 boundary_ids_[e] = marker(e, vs, p, is_boundary);
679 }
680 }
681
682 void CMesh2D::append(const Mesh &mesh)
683 {
684 assert(typeid(mesh) == typeid(CMesh2D));
685 Mesh::append(mesh);
686
687 const CMesh2D &mesh2d = dynamic_cast<const CMesh2D &>(mesh);
688
689 const int n_v = n_vertices();
690 const int n_f = n_faces();
691
692 mesh_.vertices.create_vertices(mesh2d.n_vertices());
693 for (int i = n_v; i < (int)mesh_.vertices.nb(); ++i)
694 {
695 GEO::vec3 &p = mesh_.vertices.point(i);
696 set_point(i, mesh2d.point(i - n_v));
697 }
698
699 std::vector<GEO::index_t> indices;
700 for (int i = 0; i < mesh2d.n_faces(); ++i)
701 {
702 indices.clear();
703 for (int j = 0; j < mesh2d.mesh_.facets.nb_vertices(i); ++j)
704 indices.push_back(mesh2d.mesh_.facets.vertex(i, j) + n_v);
705
706 mesh_.facets.create_polygon(indices.size(), &indices[0]);
707 }
708
709 assert(n_vertices() == n_v + mesh2d.n_vertices());
710 assert(n_faces() == n_f + mesh2d.n_faces());
711
712 c2e_.reset();
713 boundary_vertices_.reset();
714 boundary_edges_.reset();
716 c2e_ = std::make_unique<GEO::Attribute<GEO::index_t>>(mesh_.facet_corners.attributes(), "edge_id");
717 boundary_vertices_ = std::make_unique<GEO::Attribute<bool>>(mesh_.vertices.attributes(), "boundary_vertex");
718 boundary_edges_ = std::make_unique<GEO::Attribute<bool>>(mesh_.edges.attributes(), "boundary_edge");
719 }
720
721 std::unique_ptr<Mesh> CMesh2D::copy() const
722 {
723 std::unique_ptr<CMesh2D> copy_mesh = std::make_unique<CMesh2D>();
724 copy_mesh->load(this->mesh_);
725
726 // Manually copy parent's data
727 copy_mesh->elements_tag_ = this->elements_tag_;
728 copy_mesh->node_ids_ = this->node_ids_;
729 copy_mesh->boundary_ids_ = this->boundary_ids_;
730 copy_mesh->body_ids_ = this->body_ids_;
731 copy_mesh->geometry_ids_ = this->geometry_ids_;
732 copy_mesh->orders_ = this->orders_;
733 copy_mesh->is_rational_ = this->is_rational_;
734 copy_mesh->edge_nodes_ = this->edge_nodes_;
735 copy_mesh->face_nodes_ = this->face_nodes_;
736 copy_mesh->cell_nodes_ = this->cell_nodes_;
737 copy_mesh->cell_weights_ = this->cell_weights_;
738 copy_mesh->in_ordered_vertices_ = this->in_ordered_vertices_;
739 copy_mesh->in_ordered_edges_ = this->in_ordered_edges_;
740 copy_mesh->in_ordered_faces_ = this->in_ordered_faces_;
741
742 return copy_mesh;
743 }
744 } // namespace mesh
745} // namespace polyfem
int V
Eigen::RowVectorXd point
virtual RowVectorNd edge_barycenter(const int index) const override
edge barycenter
Definition CMesh2D.cpp:648
Navigation::Index switch_edge(Navigation::Index idx) const override
Definition CMesh2D.hpp:87
bool load(const std::string &path) override
loads a mesh from the path
Definition CMesh2D.cpp:171
void normalize() override
normalize the mesh
Definition CMesh2D.cpp:493
void compute_elements_tag() override
compute element types, see ElementType
Definition CMesh2D.cpp:637
int n_faces() const override
number of faces
Definition CMesh2D.hpp:33
int n_face_vertices(const int f_id) const override
number of vertices of a face
Definition CMesh2D.hpp:37
int n_vertices() const override
number of vertices
Definition CMesh2D.hpp:35
int n_edges() const override
number of edges
Definition CMesh2D.hpp:34
bool is_boundary_element(const int element_global_id) const override
is cell boundary
Definition CMesh2D.cpp:561
double edge_length(const int gid) const override
edge length
Definition CMesh2D.cpp:538
std::unique_ptr< GEO::Attribute< bool > > boundary_edges_
Definition CMesh2D.hpp:105
std::pair< RowVectorNd, int > edge_node(const Navigation::Index &index, const int n_new_nodes, const int i) const override
Definition CMesh2D.cpp:413
std::unique_ptr< Mesh > copy() const override
Create a copy of the mesh.
Definition CMesh2D.cpp:721
Navigation::Index switch_vertex(Navigation::Index idx) const override
Definition CMesh2D.hpp:86
void compute_boundary_ids(const std::function< int(const size_t, const std::vector< int > &, const RowVectorNd &, bool)> &marker) override
computes boundary selections based on a function
Definition CMesh2D.cpp:668
void set_point(const int global_index, const RowVectorNd &p) override
Set the point.
Definition CMesh2D.cpp:546
bool is_boundary_edge(const int edge_global_id) const override
is edge boundary
Definition CMesh2D.hpp:48
std::unique_ptr< GEO::Attribute< GEO::index_t > > c2e_
Definition CMesh2D.hpp:103
std::unique_ptr< GEO::Attribute< bool > > boundary_vertices_
Definition CMesh2D.hpp:104
std::pair< RowVectorNd, int > face_node(const Navigation::Index &index, const int n_new_nodes, const int i, const int j) const override
Definition CMesh2D.cpp:435
void append(const Mesh &mesh) override
appends a new mesh to the end of this
Definition CMesh2D.cpp:682
int edge_vertex(const int e_id, const int lv_id) const override
id of the edge vertex
Definition CMesh2D.hpp:40
Navigation::Index get_index_from_face(int f, int lv=0) const override
Definition CMesh2D.hpp:83
virtual void bounding_box(RowVectorNd &min, RowVectorNd &max) const override
computes the bbox of the mesh
Definition CMesh2D.cpp:479
void remove_elements(const std::vector< bool > &keep) override
Remove all top-dimensional elements whose mask entry is false.
Definition CMesh2D.cpp:27
void attach_higher_order_nodes(const Eigen::MatrixXd &V, const std::vector< std::vector< int > > &nodes) override
attach high order nodes
Definition CMesh2D.cpp:272
bool build_from_matrices(const Eigen::MatrixXd &V, const Eigen::MatrixXi &F) override
build a mesh from matrices
Definition CMesh2D.cpp:248
void refine(const int n_refinement, const double t) override
refine the mesh
Definition CMesh2D.cpp:100
bool save(const std::string &path) const override
Definition CMesh2D.cpp:240
void compute_body_ids(const std::function< int(const size_t, const std::vector< int > &, const RowVectorNd &)> &marker) override
computes boundary selections based on a function
Definition CMesh2D.cpp:656
virtual RowVectorNd point(const int global_index) const override
point coordinates
Definition CMesh2D.cpp:552
virtual void update_elements_tag() override
Update elements types.
Definition CMesh2D.cpp:643
RowVectorNd face_barycenter(const int index) const override
face barycenter
Definition Mesh2D.cpp:69
Navigation::Index next_around_face(Navigation::Index idx) const
Definition Mesh2D.hpp:61
void get_edges(Eigen::MatrixXd &p0, Eigen::MatrixXd &p1) const override
Get all the edges.
Definition Mesh2D.cpp:21
Class to store the high-order edge nodes.
Definition Mesh.hpp:53
Abstract mesh class to capture 2d/3d conforming and non-conforming meshes.
Definition Mesh.hpp:49
int n_elements() const
utitlity to return the number of elements, cells or faces in 3d and 2d
Definition Mesh.hpp:174
Eigen::MatrixXi orders_
list of geometry orders, one per cell
Definition Mesh.hpp:738
std::vector< ElementType > elements_tag_
list of element types
Definition Mesh.hpp:728
bool is_rational_
stores if the mesh is rational
Definition Mesh.hpp:740
bool has_boundary_ids() const
checks if surface selections are available
Definition Mesh.hpp:561
bool is_cube(const int el_id) const
checks if element is cube compatible
Definition Mesh.cpp:437
Eigen::MatrixXi in_ordered_faces_
Order of the input faces, TODO: change to std::vector of Eigen::Vector.
Definition Mesh.hpp:756
bool is_simplex(const int el_id) const
checks if element is simplex
Definition Mesh.cpp:507
std::vector< int > geometry_ids_
list of geometry labels, one per top-dimensional element
Definition Mesh.hpp:736
std::vector< int > boundary_ids_
list of surface labels
Definition Mesh.hpp:732
std::vector< int > node_ids_
list of node labels
Definition Mesh.hpp:730
std::vector< CellNodes > cell_nodes_
high-order nodes associates to cells
Definition Mesh.hpp:747
std::vector< std::vector< double > > cell_weights_
weights associates to cells for rational polynomail meshes
Definition Mesh.hpp:749
std::vector< int > element_vertices(const int el_id) const
list of vids of an element
Definition Mesh.hpp:242
std::vector< int > body_ids_
list of volume labels
Definition Mesh.hpp:734
virtual int get_default_boundary_id(const int primitive) const
Get the default boundary selection of an element (face in 3d, edge in 2d)
Definition Mesh.hpp:487
std::vector< FaceNodes > face_nodes_
high-order nodes associates to faces
Definition Mesh.hpp:745
std::vector< EdgeNodes > edge_nodes_
high-order nodes associates to edges
Definition Mesh.hpp:743
void filter_element_data(const std::vector< bool > &keep)
Definition Mesh.cpp:55
Eigen::MatrixXi in_ordered_edges_
Order of the input edges.
Definition Mesh.hpp:754
virtual void append(const Mesh &mesh)
appends a new mesh to the end of this
Definition Mesh.cpp:589
Eigen::VectorXi in_ordered_vertices_
Order of the input vertices.
Definition Mesh.hpp:752
void prepare_mesh(GEO::Mesh &M)
SplitFunction catmul_clark_split_func()
SplitFunction polar_split_func(double t)
Helper function.
void refine_triangle_mesh(const GEO::Mesh &M_in, GEO::Mesh &M_out)
Refine a triangle mesh.
void orient_normals_2d(GEO::Mesh &M)
Orient facets of a 2D mesh so that each connected component has positive volume.
void to_geogram_mesh(const Eigen::MatrixXd &V, const Eigen::MatrixXi &F, GEO::Mesh &M)
Converts a triangle mesh to a Geogram mesh.
void generate_edges(GEO::Mesh &M)
assing edges to M
void refine_polygonal_mesh(const GEO::Mesh &M_in, GEO::Mesh &M_out, Polygons::SplitFunction split_func)
Refine a polygonal mesh.
void compute_element_tags(const GEO::Mesh &M, std::vector< ElementType > &element_tags)
Compute the type of each facet in a surface mesh.
spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:44
Eigen::Matrix< double, 1, Eigen::Dynamic, Eigen::RowMajor, 1, 3 > RowVectorNd
Definition Types.hpp:13