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