PolyFEM
Loading...
Searching...
No Matches
NCMesh3D.cpp
Go to the documentation of this file.
4
6
7#include <igl/writeMESH.h>
8
9#include <geogram/mesh/mesh_io.h>
10#include <fstream>
11
12using namespace polyfem::utils;
13
14namespace polyfem
15{
16 namespace mesh
17 {
18 void NCMesh3D::remove_elements(const std::vector<bool> &keep)
19 {
20 assert(keep.size() == n_cells());
21
22 std::vector<int> old_node_ids(vertices.size(), -1);
23 if (has_node_ids())
24 for (int v = 0; v < n_vertices(); ++v)
25 old_node_ids[valid_to_all_vertex(v)] = node_ids_[v];
26 std::vector<int> old_boundary_ids(faces.size(), -1);
27 if (has_boundary_ids())
28 for (int f = 0; f < n_faces(); ++f)
29 old_boundary_ids[valid_to_all_face(f)] = boundary_ids_[f];
30
31 for (int e = 0; e < keep.size(); ++e)
32 {
33 if (keep[e])
34 continue;
35 const int full_id = valid_to_all_elem(e);
36 auto &element = elements[full_id];
37 element.is_ghost = true;
38 for (const int face : element.faces)
39 faces[face].remove_element(full_id);
40 for (const int edge : element.edges)
41 edges[edge].remove_element(full_id);
42 for (const int vertex : element.vertices)
43 vertices[vertex].remove_element(full_id);
44 --n_elements;
45 }
48
49 if (has_node_ids())
50 {
51 node_ids_.resize(n_vertices());
52 for (int v = 0; v < n_vertices(); ++v)
53 node_ids_[v] = old_node_ids[valid_to_all_vertex(v)];
54 }
55 if (has_boundary_ids())
56 {
57 boundary_ids_.resize(n_faces());
58 for (int f = 0; f < n_faces(); ++f)
59 {
60 const int old_id = old_boundary_ids[valid_to_all_face(f)];
61 boundary_ids_[f] = old_id < 0 ? get_default_boundary_id(f) : old_id;
62 faces[valid_to_all_face(f)].boundary_id = boundary_ids_[f];
63 }
64 }
65 }
66
67 int NCMesh3D::face_edge(const int f_id, const int le_id) const
68 {
69 const int v0 = faces[valid_to_all_face(f_id)].vertices(le_id);
70 const int v1 = faces[valid_to_all_face(f_id)].vertices((le_id + 1) % 3);
71 const int e_id = find_edge(v0, v1);
72 return all_to_valid_edge(e_id);
73 }
74
75 void NCMesh3D::refine(const int n_refinement, const double t)
76 {
77 if (n_refinement <= 0)
78 return;
79 std::vector<bool> refine_mask(elements.size(), false);
80 for (int i = 0; i < elements.size(); i++)
81 if (elements[i].is_valid())
82 refine_mask[i] = true;
83
84 for (int i = 0; i < refine_mask.size(); i++)
85 if (refine_mask[i])
87
88 refine(n_refinement - 1, t);
89 }
90
91 bool NCMesh3D::is_boundary_element(const int element_global_id) const
92 {
93 assert(index_prepared);
94 for (int lv = 0; lv < n_cell_edges(element_global_id); lv++)
95 if (is_boundary_vertex(cell_vertex(element_global_id, lv)))
96 return true;
97
98 return false;
99 }
100
101 bool NCMesh3D::build_from_matrices(const Eigen::MatrixXd &V, const Eigen::MatrixXi &F)
102 {
103 n_elements = 0;
104 elements.clear();
105 vertices.clear();
106 edges.clear();
107 midpointMap.clear();
108 edgeMap.clear();
109 faceMap.clear();
110 refineHistory.clear();
111 index_prepared = false;
112 adj_prepared = false;
113
114 vertices.reserve(V.rows());
115 for (int i = 0; i < V.rows(); i++)
116 {
117 vertices.emplace_back(V.row(i));
118 }
119 for (int i = 0; i < F.rows(); i++)
120 {
121 add_element(F.row(i), -1);
122 }
123
124 prepare_mesh();
125
126 return true;
127 }
128
129 void NCMesh3D::attach_higher_order_nodes(const Eigen::MatrixXd &V, const std::vector<std::vector<int>> &nodes)
130 {
131 for (int f = 0; f < n_cells(); ++f)
132 if (nodes[f].size() != 4)
133 throw std::runtime_error("NCMesh doesn't support high order mesh!");
134 }
135
137 {
138 polyfem::RowVectorNd min, max;
139 bounding_box(min, max);
140
141 auto extent = max - min;
142 double scale = extent.maxCoeff();
143
144 for (auto &v : vertices)
145 v.pos = (v.pos - min.transpose()) / scale;
146 }
147
156 double NCMesh3D::edge_length(const int gid) const
157 {
158 const int v1 = edge_vertex(gid, 0);
159 const int v2 = edge_vertex(gid, 1);
160
161 return (point(v1) - point(v2)).norm();
162 }
163
164 RowVectorNd NCMesh3D::point(const int global_index) const
165 {
166 return vertices[valid_to_all_vertex(global_index)].pos.transpose();
167 }
168
169 void NCMesh3D::set_point(const int global_index, const RowVectorNd &p)
170 {
171 vertices[valid_to_all_vertex(global_index)].pos = p;
172 }
173
175 {
176 const int v1 = edge_vertex(e, 0);
177 const int v2 = edge_vertex(e, 1);
178
179 return 0.5 * (point(v1) + point(v2));
180 }
182 {
183 const int v1 = face_vertex(f, 0);
184 const int v2 = face_vertex(f, 1);
185 const int v3 = face_vertex(f, 2);
186
187 return (point(v1) + point(v2) + point(v3)) / 3.;
188 }
190 {
191 const int v1 = face_vertex(c, 0);
192 const int v2 = face_vertex(c, 1);
193 const int v3 = face_vertex(c, 2);
194
195 return (point(v1) + point(v2) + point(v3)) / 3.;
196 }
197
199 {
200 min = vertices[0].pos;
201 max = vertices[0].pos;
202
203 for (const auto &v : vertices)
204 {
205 for (int d = 0; d < 3; d++)
206 {
207 if (v.pos[d] > max[d])
208 max[d] = v.pos[d];
209 if (v.pos[d] < min[d])
210 min[d] = v.pos[d];
211 }
212 }
213 }
214
215 void NCMesh3D::compute_boundary_ids(const std::function<int(const size_t, const std::vector<int> &, const RowVectorNd &, bool)> &marker)
216 {
217 boundary_ids_.resize(n_faces());
218 std::fill(boundary_ids_.begin(), boundary_ids_.end(), -1);
219
220 for (int f = 0; f < n_faces(); ++f)
221 {
222 const bool is_boundary = is_boundary_face(f);
223 std::vector<int> vs(n_face_vertices(f));
224 const auto p = face_barycenter(f);
225
226 for (int vid = 0; vid < vs.size(); ++vid)
227 vs[vid] = face_vertex(f, vid);
228
229 std::sort(vs.begin(), vs.end());
230 boundary_ids_[f] = marker(f, vs, p, is_boundary);
231
232 faces[valid_to_all_face(f)].boundary_id = boundary_ids_[f];
233 }
234 }
235
236 void NCMesh3D::compute_body_ids(const std::function<int(const size_t, const std::vector<int> &, const RowVectorNd &)> &marker)
237 {
238 body_ids_.resize(n_cells());
239 std::fill(body_ids_.begin(), body_ids_.end(), -1);
240
241 for (int e = 0; e < n_cells(); ++e)
242 {
243 const auto bary = cell_barycenter(e);
244 body_ids_[e] = marker(e, element_vertices(e), bary);
245 elements[valid_to_all_elem(e)].body_id = body_ids_[e];
246 }
247 }
248 void NCMesh3D::set_boundary_ids(const std::vector<int> &boundary_ids)
249 {
250 assert(boundary_ids.size() == n_faces());
251 for (int i = 0; i < boundary_ids.size(); i++)
252 {
253 faces[valid_to_all_face(i)].boundary_id = boundary_ids[i];
254 }
255 }
256 void NCMesh3D::set_body_ids(const std::vector<int> &body_ids)
257 {
258 assert(body_ids.size() == n_cells());
259 for (int i = 0; i < body_ids.size(); i++)
260 {
261 elements[valid_to_all_elem(i)].body_id = body_ids[i];
262 }
263 }
264
265 // void NCMesh3D::triangulate_faces(Eigen::MatrixXi &tris, Eigen::MatrixXd &pts, std::vector<int> &ranges) const
266 // {
267 // ranges.clear();
268
269 // std::vector<Eigen::MatrixXi> local_tris(n_cells());
270 // std::vector<Eigen::MatrixXd> local_pts(n_cells());
271 // Eigen::MatrixXi tets;
272
273 // int total_tris = 0;
274 // int total_pts = 0;
275
276 // ranges.push_back(0);
277
278 // Eigen::MatrixXd face_barys;
279 // face_barycenters(face_barys);
280
281 // Eigen::MatrixXd cell_barys;
282 // cell_barycenters(cell_barys);
283
284 // for (std::size_t e = 0; e < n_cells(); ++e)
285 // {
286 // const int n_vertices = n_cell_vertices(e);
287 // const int n_faces = n_cell_faces(e);
288
289 // Eigen::MatrixXd local_pt(n_vertices + n_faces, 3);
290
291 // std::map<int, int> global_to_local;
292
293 // for (int i = 0; i < n_vertices; ++i)
294 // {
295 // const int global_index = cell_vertex(e, i);
296 // local_pt.row(i) = point(global_index);
297 // global_to_local[global_index] = i;
298 // }
299
300 // int n_local_faces = 0;
301 // for (int i = 0; i < n_faces; ++i)
302 // {
303 // const int f_id = cell_face(e, i);
304 // n_local_faces += n_face_vertices(f_id);
305
306 // local_pt.row(n_vertices + i) = face_barys.row(f_id);
307 // }
308
309 // Eigen::MatrixXi local_faces(n_local_faces, 3);
310
311 // int face_index = 0;
312 // for (int i = 0; i < n_faces; ++i)
313 // {
314 // const int f_id = cell_face(e, i);
315
316 // const Eigen::RowVector3d e0 = (point(face_vertex(f_id, 0)) - local_pt.row(n_vertices + i));
317 // const Eigen::RowVector3d e1 = (point(face_vertex(f_id, 1)) - local_pt.row(n_vertices + i));
318 // const Eigen::RowVector3d normal = e0.cross(e1);
319 // // const Eigen::RowVector3d check_dir = (node_from_element(e)-p);
320 // const Eigen::RowVector3d check_dir = (cell_barys.row(e) - point(face_vertex(f_id, 1)));
321
322 // const bool reverse_order = normal.dot(check_dir) > 0;
323
324 // for (int j = 0; j < n_face_vertices(f_id); ++j)
325 // {
326 // const int jp = (j + 1) % n_face_vertices(f_id);
327 // if (reverse_order)
328 // {
329 // local_faces(face_index, 0) = global_to_local[face_vertex(f_id, jp)];
330 // local_faces(face_index, 1) = global_to_local[face_vertex(f_id, j)];
331 // }
332 // else
333 // {
334 // local_faces(face_index, 0) = global_to_local[face_vertex(f_id, j)];
335 // local_faces(face_index, 1) = global_to_local[face_vertex(f_id, jp)];
336 // }
337 // local_faces(face_index, 2) = n_vertices + i;
338
339 // ++face_index;
340 // }
341 // }
342
343 // local_pts[e] = local_pt;
344 // local_tris[e] = local_faces;
345
346 // total_tris += local_tris[e].rows();
347 // total_pts += local_pts[e].rows();
348
349 // ranges.push_back(total_tris);
350
351 // assert(local_pts[e].rows() == local_pt.rows());
352 // }
353
354 // tris.resize(total_tris, 3);
355 // pts.resize(total_pts, 3);
356
357 // int tri_index = 0;
358 // int pts_index = 0;
359 // for (std::size_t i = 0; i < local_tris.size(); ++i)
360 // {
361 // tris.block(tri_index, 0, local_tris[i].rows(), local_tris[i].cols()) = local_tris[i].array() + pts_index;
362 // tri_index += local_tris[i].rows();
363
364 // pts.block(pts_index, 0, local_pts[i].rows(), local_pts[i].cols()) = local_pts[i];
365 // pts_index += local_pts[i].rows();
366 // }
367 // }
368
369 RowVectorNd NCMesh3D::kernel(const int cell_id) const
370 {
371 assert(false);
372 return RowVectorNd();
373 }
375 {
377
378 idx.element = hi;
379
380 idx.element_patch = lf;
381 idx.face = cell_face(hi, lf);
382
383 if (lv >= 4)
384 lv = lv % 4;
385 idx.face_corner = lv;
386 idx.vertex = face_vertex(idx.face, idx.face_corner);
387
388 idx.edge = face_edge(idx.face, idx.face_corner);
389
390 return idx;
391 }
393 {
395
396 idx.element = hi;
397 idx.element_patch = 0;
398 idx.face = cell_face(hi, 0);
399 idx.face_corner = 0;
400 idx.vertex = face_vertex(idx.face, idx.face_corner);
401 idx.edge = face_edge(idx.face, 0);
402
403 return idx;
404 }
405
407 {
409
410 idx.element = hi;
411 idx.vertex = v0;
413
414 for (int i = 0; i < 4; i++)
415 {
416 const int f_id = cell_face(idx.element, i);
417 for (int j = 0; j < 3; j++)
418 {
419 const int e_id = face_edge(f_id, j);
420 if (idx.edge == e_id)
421 {
422 idx.element_patch = i;
423 idx.face = f_id;
424
425 for (int d = 0; d < n_face_vertices(f_id); d++)
426 if (face_vertex(f_id, d) == idx.vertex)
427 idx.face_corner = d;
428
429 assert(switch_vertex(idx).vertex == v1);
430
431 return idx;
432 }
433 }
434 }
435
436 assert(false);
437 return idx;
438 }
439 Navigation3D::Index NCMesh3D::get_index_from_element_face(int hi, int v0, int v1, int v2) const
440 {
442
443 idx.element = hi;
444 idx.vertex = v0;
446
447 for (int d = 0; d < n_face_vertices(idx.face); d++)
448 if (face_vertex(idx.face, d) == idx.vertex)
449 idx.face_corner = d;
450
451 int v0_ = v0, v1_ = v1;
452
453 // let v0_ < v1_
454 if (v0_ > v1_)
455 std::swap(v0_, v1_);
456
457 for (int i = 0; i < 4; i++)
458 {
459 const int fid = cell_face(idx.element, i);
460 if (fid != idx.face)
461 continue;
462
463 idx.element_patch = i;
464
465 for (int j = 0; j < 3; j++)
466 {
467 const int eid = face_edge(fid, j);
468 const int ev0 = edge_vertex(eid, 0);
469 const int ev1 = edge_vertex(eid, 1);
470
471 if ((ev0 == v0_ && ev1 == v1_) || (ev0 == v1_ && ev1 == v0_))
472 {
473 idx.edge = eid;
474
475 assert(switch_vertex(idx).vertex == v1);
476 assert(switch_vertex(switch_edge(idx)).vertex == v2);
477
478 return idx;
479 }
480 }
481 }
482
483 assert(false);
484 return idx;
485 }
486
487 std::vector<uint32_t> NCMesh3D::vertex_neighs(const int v_gid) const
488 {
489 std::vector<uint32_t> hs;
490 for (auto h : vertices[valid_to_all_vertex(v_gid)].elem_list)
491 hs.push_back(all_to_valid_elem(h));
492
493 return hs;
494 }
495 std::vector<uint32_t> NCMesh3D::edge_neighs(const int e_gid) const
496 {
497 std::vector<uint32_t> hs;
498 for (auto h : edges[valid_to_all_edge(e_gid)].elem_list)
499 hs.push_back(all_to_valid_elem(h));
500
501 return hs;
502 }
503
505 {
506 if (idx.vertex == edge_vertex(idx.edge, 0))
507 idx.vertex = edge_vertex(idx.edge, 1);
508 else
509 idx.vertex = edge_vertex(idx.edge, 0);
510
511 for (int d = 0; d < n_face_vertices(idx.face); d++)
512 if (face_vertex(idx.face, d) == idx.vertex)
513 idx.face_corner = d;
514
515 return idx;
516 }
518 {
519 if (idx.edge == face_edge(idx.face, idx.face_corner))
520 idx.edge = face_edge(idx.face, (idx.face_corner + 2) % 3);
521 else
522 idx.edge = face_edge(idx.face, idx.face_corner);
523 return idx;
524 }
526 {
527 for (int i = 0; i < 4; i++)
528 {
529 const int fid = cell_face(idx.element, i);
530 if (fid == idx.face)
531 continue;
532 if (idx.edge == face_edge(fid, 0) || idx.edge == face_edge(fid, 1) || idx.edge == face_edge(fid, 2))
533 {
534 idx.face = fid;
535 idx.element_patch = i;
536
537 for (int d = 0; d < n_face_vertices(fid); d++)
538 if (face_vertex(fid, d) == idx.vertex)
539 idx.face_corner = d;
540
541 break;
542 }
543 }
544 return idx;
545 }
547 {
548 const auto &face = faces[valid_to_all_face(idx.face)];
549 if (face.n_elem() != 2)
550 {
551 idx.element = -1;
552 return idx;
553 }
554 if (all_to_valid_elem(face.get_element()) == idx.element)
555 idx.element = all_to_valid_elem(face.find_opposite_element(face.get_element()));
556 else
557 idx.element = all_to_valid_elem(face.get_element());
558
559 for (int f = 0; f < n_cell_faces(idx.element); f++)
560 if (cell_face(idx.element, f) == idx.face)
561 idx.element_patch = f;
562 return idx;
563 }
564
573
574 void NCMesh3D::get_vertex_elements_neighs(const int v_id, std::vector<int> &ids) const
575 {
576 ids.clear();
577 for (auto h : vertices[valid_to_all_vertex(v_id)].elem_list)
578 ids.push_back(all_to_valid_elem(h));
579 }
580 void NCMesh3D::get_edge_elements_neighs(const int e_id, std::vector<int> &ids) const
581 {
582 ids.clear();
583 for (auto h : edges[valid_to_all_edge(e_id)].elem_list)
584 ids.push_back(all_to_valid_elem(h));
585 }
586 void NCMesh3D::get_face_elements_neighs(const int f_id, std::vector<int> &ids) const
587 {
588 ids.clear();
589 for (auto h : faces[valid_to_all_face(f_id)].elem_list)
590 ids.push_back(all_to_valid_elem(h));
591 }
592
593 void NCMesh3D::refine_element(int id_full)
594 {
595 assert(elements[id_full].is_valid());
596 if (elements[id_full].is_not_valid())
597 throw std::runtime_error("Cannot refine an invalid element!");
598
599 const auto v = elements[id_full].vertices;
600 elements[id_full].is_refined = true;
601 n_elements--;
602
603 for (int f = 0; f < elements[id_full].faces.size(); f++)
604 faces[elements[id_full].faces(f)].remove_element(id_full);
605
606 for (int e = 0; e < elements[id_full].edges.size(); e++)
607 edges[elements[id_full].edges(e)].remove_element(id_full);
608
609 for (int i = 0; i < v.size(); i++)
610 vertices[v(i)].remove_element(id_full);
611
612 if (elements[id_full].children(0) >= 0)
613 {
614 for (int c = 0; c < elements[id_full].children.size(); c++)
615 {
616 const int child_id = elements[id_full].children(c);
617 auto &elem = elements[child_id];
618 elem.is_ghost = false;
619 n_elements++;
620
621 for (int f = 0; f < elem.faces.size(); f++)
622 faces[elem.faces(f)].add_element(child_id);
623
624 for (int e = 0; e < elem.edges.size(); e++)
625 edges[elem.edges(e)].add_element(child_id);
626
627 for (int v = 0; v < elem.vertices.size(); v++)
628 vertices[elem.vertices(v)].add_element(child_id);
629 }
630 }
631 else
632 {
633 // create mid-points if not exist
634 const int v1 = v[0];
635 const int v2 = v[1];
636 const int v3 = v[2];
637 const int v4 = v[3];
638 const int v5 = get_vertex(Eigen::Vector2i(v1, v2));
639 const int v8 = get_vertex(Eigen::Vector2i(v3, v2));
640 const int v6 = get_vertex(Eigen::Vector2i(v1, v3));
641 const int v7 = get_vertex(Eigen::Vector2i(v1, v4));
642 const int v9 = get_vertex(Eigen::Vector2i(v4, v2));
643 const int v10 = get_vertex(Eigen::Vector2i(v3, v4));
644
645 // inherite line singularity flag from parent edge
646 for (int i = 0; i < v.size(); i++)
647 for (int j = 0; j < i; j++)
648 {
649 int mid_id = find_vertex(v[i], v[j]);
650 int edge_id = find_edge(v[i], v[j]);
651 int edge1 = get_edge(v[i], mid_id);
652 int edge2 = get_edge(v[j], mid_id);
653 edges[edge1].boundary_id = edges[edge_id].boundary_id;
654 edges[edge2].boundary_id = edges[edge_id].boundary_id;
655 }
656
657 for (int i = 0; i < v.size(); i++)
658 for (int j = 0; j < i; j++)
659 for (int k = 0; k < j; k++)
660 {
661 int fid = find_face(v[i], v[j], v[k]);
662 int vij = find_vertex(v[i], v[j]);
663 int vjk = find_vertex(v[j], v[k]);
664 int vik = find_vertex(v[i], v[k]);
665 int facei = get_face(v[i], vij, vik);
666 int facej = get_face(v[j], vjk, vij);
667 int facek = get_face(v[k], vjk, vik);
668 int facem = get_face(vij, vjk, vik);
669 faces[facei].boundary_id = faces[fid].boundary_id;
670 faces[facej].boundary_id = faces[fid].boundary_id;
671 faces[facek].boundary_id = faces[fid].boundary_id;
672 faces[facem].boundary_id = faces[fid].boundary_id;
673 }
674
675 // create children
676 elements[id_full].children(0) = elements.size();
677 add_element(Eigen::Vector4i(v1, v5, v6, v7), id_full);
678 elements[id_full].children(1) = elements.size();
679 add_element(Eigen::Vector4i(v5, v2, v8, v9), id_full);
680 elements[id_full].children(2) = elements.size();
681 add_element(Eigen::Vector4i(v6, v8, v3, v10), id_full);
682 elements[id_full].children(3) = elements.size();
683 add_element(Eigen::Vector4i(v7, v9, v10, v4), id_full);
684 elements[id_full].children(4) = elements.size();
685 add_element(Eigen::Vector4i(v5, v6, v7, v9), id_full);
686 elements[id_full].children(5) = elements.size();
687 add_element(Eigen::Vector4i(v5, v9, v8, v6), id_full);
688 elements[id_full].children(6) = elements.size();
689 add_element(Eigen::Vector4i(v6, v7, v9, v10), id_full);
690 elements[id_full].children(7) = elements.size();
691 add_element(Eigen::Vector4i(v6, v10, v9, v8), id_full);
692 }
693
694 refineHistory.push_back(id_full);
695 }
696 void NCMesh3D::refine_elements(const std::vector<int> &ids)
697 {
698 std::vector<int> full_ids(ids.size());
699 for (int i = 0; i < ids.size(); i++)
700 full_ids[i] = valid_to_all_elem(ids[i]);
701
702 for (int i : full_ids)
704 }
705
707 {
708 const int parent_id = elements[id_full].parent;
709 auto &parent = elements[parent_id];
710
711 for (int i = 0; i < parent.children.size(); i++)
712 if (elements[parent.children(i)].is_not_valid())
713 throw std::runtime_error("Invalid siblings in coarsening!");
714
715 // remove elements
716 for (int c = 0; c < parent.children.size(); c++)
717 {
718 auto &elem = elements[parent.children(c)];
719 elem.is_ghost = true;
720 n_elements--;
721
722 for (int f = 0; f < elem.faces.size(); f++)
723 faces[elem.faces(f)].remove_element(parent.children(c));
724
725 for (int e = 0; e < elem.edges.size(); e++)
726 edges[elem.edges(e)].remove_element(parent.children(c));
727
728 for (int v = 0; v < elem.vertices.size(); v++)
729 vertices[elem.vertices(v)].remove_element(parent.children(c));
730 }
731
732 // add element
733 parent.is_refined = false;
734 n_elements++;
735
736 for (int f = 0; f < parent.faces.size(); f++)
737 faces[parent.faces(f)].add_element(parent_id);
738
739 for (int e = 0; e < parent.edges.size(); e++)
740 edges[parent.edges(e)].add_element(parent_id);
741
742 for (int v = 0; v < parent.vertices.size(); v++)
743 vertices[parent.vertices(v)].add_element(parent_id);
744
745 refineHistory.push_back(parent_id);
746 }
747
749 {
750 for (auto &face : faces)
751 {
752 if (face.n_elem() == 1)
753 face.isboundary = true;
754 else
755 face.isboundary = false;
756 }
757
758 for (auto &face : faces)
759 {
760 if (face.leader >= 0 && face.n_elem() > 0 && faces[face.leader].n_elem() > 0)
761 {
762 face.isboundary = false;
763 faces[face.leader].isboundary = false;
764 }
765 }
766
767 for (auto &vert : vertices)
768 vert.isboundary = false;
769
770 for (auto &edge : edges)
771 edge.isboundary = false;
772
773 for (auto &face : faces)
774 {
775 if (face.isboundary && face.n_elem())
776 {
777 for (int j = 0; j < 3; j++)
778 vertices[face.vertices(j)].isboundary = true;
779
780 for (int j = 0; j < 3; j++)
781 for (int i = 0; i < j; i++)
782 edges[find_edge(face.vertices(i), face.vertices(j))].isboundary = true;
783 }
784 }
785 }
786
788 {
789 all_to_valid_elemMap.assign(elements.size(), -1);
791
792 for (int i = 0, e = 0; i < elements.size(); i++)
793 {
794 if (elements[i].is_not_valid())
795 continue;
798 e++;
799 }
800
801 const int n_verts = n_vertices();
802
803 all_to_valid_vertexMap.assign(vertices.size(), -1);
804 valid_to_all_vertexMap.resize(n_verts);
805
806 for (int i = 0, j = 0; i < vertices.size(); i++)
807 {
808 if (vertices[i].n_elem() == 0)
809 continue;
812 j++;
813 }
814
815 all_to_valid_edgeMap.assign(edges.size(), -1);
817
818 for (int i = 0, j = 0; i < edges.size(); i++)
819 {
820 if (edges[i].n_elem() == 0)
821 continue;
824 j++;
825 }
826
827 all_to_valid_faceMap.assign(faces.size(), -1);
829
830 for (int i = 0, j = 0; i < faces.size(); i++)
831 {
832 if (faces[i].n_elem() == 0)
833 continue;
836 j++;
837 }
838 index_prepared = true;
839 }
840
841 void NCMesh3D::append(const Mesh &mesh)
842 {
843 assert(typeid(mesh) == typeid(NCMesh3D));
844 Mesh::append(mesh);
845
846 const NCMesh3D &mesh3d = dynamic_cast<const NCMesh3D &>(mesh);
847
848 const int n_v = n_vertices();
849 const int n_f = n_cells();
850
851 vertices.reserve(n_v + mesh3d.n_vertices());
852 for (int i = 0; i < mesh3d.n_vertices(); i++)
853 {
854 vertices.emplace_back(mesh3d.vertices[i].pos);
855 }
856 for (int i = 0; i < mesh3d.n_cells(); i++)
857 {
858 Eigen::Vector4i cell = mesh3d.elements[i].vertices;
859 cell = cell.array() + n_v;
860 add_element(cell, -1);
861 }
862
863 prepare_mesh();
864 }
865
866 std::unique_ptr<Mesh> NCMesh3D::copy() const
867 {
868 return std::make_unique<NCMesh3D>(*this);
869 }
870
871 bool NCMesh3D::load(const std::string &path)
872 {
873 if (!StringUtils::endswith(path, ".HYBRID"))
874 {
875 GEO::Mesh M;
876 GEO::mesh_load(path, M);
877 return load(M);
878 }
879 return false;
880 }
881 bool NCMesh3D::load(const GEO::Mesh &M)
882 {
883 assert(M.vertices.dimension() == 3);
884
885 Eigen::MatrixXd V(M.vertices.nb(), 2);
886 Eigen::MatrixXi C(M.cells.nb(), 4);
887
888 for (int v = 0; v < V.rows(); v++)
889 V.row(v) << M.vertices.point(v)[0], M.vertices.point(v)[1], M.vertices.point(v)[2];
890
891 for (int c = 0; c < C.rows(); c++)
892 {
893 if (M.cells.type(c) != GEO::MESH_TET)
894 throw std::runtime_error("NCMesh3D only supports tet mesh!");
895 for (int i = 0; i < C.cols(); i++)
896 C(c, i) = M.cells.vertex(c, i);
897 }
898
899 n_elements = 0;
900 vertices.reserve(V.rows());
901 for (int i = 0; i < V.rows(); i++)
902 {
903 vertices.emplace_back(V.row(i));
904 }
905 for (int i = 0; i < C.rows(); i++)
906 {
907 add_element(C.row(i), -1);
908 }
909
910 prepare_mesh();
911
912 return true;
913 }
914
915 int NCMesh3D::find_vertex(Eigen::Vector2i v) const
916 {
917 std::sort(v.data(), v.data() + v.size());
918 auto search = midpointMap.find(v);
919 if (search != midpointMap.end())
920 return search->second;
921 else
922 return -1;
923 }
924 int NCMesh3D::get_vertex(Eigen::Vector2i v)
925 {
926 std::sort(v.data(), v.data() + v.size());
927 int id = find_vertex(v);
928 if (id < 0)
929 {
930 Eigen::VectorXd v_mid = (vertices[v[0]].pos + vertices[v[1]].pos) / 2.;
931 id = vertices.size();
932 vertices.emplace_back(v_mid);
933 midpointMap.emplace(v, id);
934 }
935 return id;
936 }
937 int NCMesh3D::find_edge(Eigen::Vector2i v) const
938 {
939 std::sort(v.data(), v.data() + v.size());
940 auto search = edgeMap.find(v);
941 if (search != edgeMap.end())
942 return search->second;
943 else
944 return -1;
945 }
946 int NCMesh3D::get_edge(Eigen::Vector2i v)
947 {
948 std::sort(v.data(), v.data() + v.size());
949 int id = find_edge(v);
950 if (id < 0)
951 {
952 edges.emplace_back(v);
953 id = edges.size() - 1;
954 edgeMap.emplace(v, id);
955 }
956 return id;
957 }
958 int NCMesh3D::find_face(Eigen::Vector3i v) const
959 {
960 std::sort(v.data(), v.data() + v.size());
961 auto search = faceMap.find(v);
962 if (search != faceMap.end())
963 return search->second;
964 else
965 return -1;
966 }
967 int NCMesh3D::get_face(Eigen::Vector3i v)
968 {
969 std::sort(v.data(), v.data() + v.size());
970 int id = find_face(v);
971 if (id < 0)
972 {
973 faces.emplace_back(v);
974 id = faces.size() - 1;
975 faceMap.emplace(v, id);
976 }
977 return id;
978 }
979 void NCMesh3D::traverse_edge(Eigen::Vector2i v, double p1, double p2, int depth, std::vector<follower_edge> &list) const
980 {
981 int v_mid = find_vertex(v);
982 std::vector<follower_edge> list1, list2;
983 if (v_mid >= 0)
984 {
985 double p_mid = (p1 + p2) / 2;
986 traverse_edge(Eigen::Vector2i(v[0], v_mid), p1, p_mid, depth + 1, list1);
987 list.insert(
988 list.end(),
989 std::make_move_iterator(list1.begin()),
990 std::make_move_iterator(list1.end()));
991 traverse_edge(Eigen::Vector2i(v_mid, v[1]), p_mid, p2, depth + 1, list2);
992 list.insert(
993 list.end(),
994 std::make_move_iterator(list2.begin()),
995 std::make_move_iterator(list2.end()));
996 }
997 if (depth > 0)
998 {
999 int follower_id = find_edge(v);
1000 if (follower_id >= 0 && edges[follower_id].n_elem() > 0)
1001 list.emplace_back(follower_id, p1, p2);
1002 }
1003 }
1005 {
1006 for (auto &edge : edges)
1007 {
1008 edge.leader = -1;
1009 edge.followers.clear();
1010 edge.weights.setConstant(-1);
1011 }
1012
1013 for (int e_id = 0; e_id < edges.size(); e_id++)
1014 {
1015 auto &edge = edges[e_id];
1016 if (edge.n_elem() == 0)
1017 continue;
1018 std::vector<follower_edge> followers;
1019 traverse_edge(edge.vertices, 0, 1, 0, followers);
1020 for (auto &s : followers)
1021 {
1022 if (edges[s.id].leader >= 0 && std::abs(edges[s.id].weights(1) - edges[s.id].weights(0)) < std::abs(s.p2 - s.p1))
1023 continue;
1024 edge.followers.push_back(s.id);
1025 edges[s.id].leader = e_id;
1026 edges[s.id].weights << s.p1, s.p2;
1027 }
1028 }
1029
1030 // In 3d, it's possible for one edge to have both leader and follower edges, but we don't care this case.
1031 for (auto &edge : edges)
1032 if (edge.leader >= 0 && edge.followers.size())
1033 edge.followers.clear();
1034 }
1035 void NCMesh3D::traverse_face(int v1, int v2, int v3, Eigen::Vector2d p1, Eigen::Vector2d p2, Eigen::Vector2d p3, int depth, std::vector<follower_face> &face_list, std::vector<int> &edge_list) const
1036 {
1037 int v12 = find_vertex(Eigen::Vector2i(v1, v2));
1038 int v23 = find_vertex(Eigen::Vector2i(v3, v2));
1039 int v31 = find_vertex(Eigen::Vector2i(v1, v3));
1040 std::vector<follower_face> list1, list2, list3, list4;
1041 std::vector<int> list1_, list2_, list3_, list4_;
1042 if (depth > 0)
1043 {
1044 edge_list.push_back(find_edge(v1, v2));
1045 edge_list.push_back(find_edge(v3, v2));
1046 edge_list.push_back(find_edge(v1, v3));
1047 }
1048 if (v12 >= 0 && v23 >= 0 && v31 >= 0)
1049 {
1050 auto p12 = (p1 + p2) / 2, p23 = (p2 + p3) / 2, p31 = (p1 + p3) / 2;
1051 traverse_face(v1, v12, v31, p1, p12, p31, depth + 1, list1, list1_);
1052 traverse_face(v12, v2, v23, p12, p2, p23, depth + 1, list2, list2_);
1053 traverse_face(v31, v23, v3, p31, p23, p3, depth + 1, list3, list3_);
1054 traverse_face(v12, v23, v31, p12, p23, p31, depth + 1, list4, list4_);
1055
1056 face_list.insert(face_list.end(), std::make_move_iterator(list1.begin()), std::make_move_iterator(list1.end()));
1057 face_list.insert(face_list.end(), std::make_move_iterator(list2.begin()), std::make_move_iterator(list2.end()));
1058 face_list.insert(face_list.end(), std::make_move_iterator(list3.begin()), std::make_move_iterator(list3.end()));
1059 face_list.insert(face_list.end(), std::make_move_iterator(list4.begin()), std::make_move_iterator(list4.end()));
1060
1061 edge_list.insert(edge_list.end(), std::make_move_iterator(list1_.begin()), std::make_move_iterator(list1_.end()));
1062 edge_list.insert(edge_list.end(), std::make_move_iterator(list2_.begin()), std::make_move_iterator(list2_.end()));
1063 edge_list.insert(edge_list.end(), std::make_move_iterator(list3_.begin()), std::make_move_iterator(list3_.end()));
1064 edge_list.insert(edge_list.end(), std::make_move_iterator(list4_.begin()), std::make_move_iterator(list4_.end()));
1065 }
1066 if (depth > 0)
1067 {
1068 int follower_id = find_face(Eigen::Vector3i(v1, v2, v3));
1069 if (follower_id >= 0 && faces[follower_id].n_elem() > 0)
1070 face_list.emplace_back(follower_id, p1, p2, p3);
1071 }
1072 }
1074 {
1075 Eigen::Matrix<int, 4, 3> fv;
1076 fv.row(0) << 0, 1, 2;
1077 fv.row(1) << 0, 1, 3;
1078 fv.row(2) << 1, 2, 3;
1079 fv.row(3) << 2, 0, 3;
1080
1081 for (auto &face : faces)
1082 {
1083 face.leader = -1;
1084 face.followers.clear();
1085 }
1086
1087 for (auto &edge : edges)
1088 {
1089 edge.leader_face = -1;
1090 }
1091
1092 for (int f_id = 0; f_id < faces.size(); f_id++)
1093 {
1094 auto &face = faces[f_id];
1095 if (face.n_elem() == 0)
1096 continue;
1097 std::vector<follower_face> followers;
1098 std::vector<int> interior_edges;
1099 traverse_face(face.vertices(0), face.vertices(1), face.vertices(2), Eigen::Vector2d(0, 0), Eigen::Vector2d(1, 0), Eigen::Vector2d(0, 1), 0, followers, interior_edges); // order is important
1100 for (auto &s : followers)
1101 {
1102 faces[s.id].leader = f_id;
1103 face.followers.push_back(s.id);
1104 }
1105 for (int s : interior_edges)
1106 if (s >= 0 && edges[s].leader < 0 && edges[s].n_elem() > 0)
1107 edges[s].leader_face = f_id;
1108 }
1109 }
1111 {
1112 for (auto &vert : vertices)
1113 {
1114 vert.edge = -1;
1115 vert.face = -1;
1116 }
1117
1118 for (auto &small_edge : edges)
1119 {
1120 // invalid edges
1121 if (small_edge.n_elem() == 0)
1122 continue;
1123
1124 // not follower edges
1125 int large_edge = small_edge.leader;
1126 if (large_edge < 0)
1127 continue;
1128 assert(edges[large_edge].leader < 0);
1129
1130 // follower edges
1131 for (int j = 0; j < 2; j++)
1132 {
1133 const int v_id = small_edge.vertices(j);
1134 // hanging nodes
1135 if (v_id != edges[large_edge].vertices(0) && v_id != edges[large_edge].vertices(1))
1136 vertices[v_id].edge = large_edge;
1137 }
1138 }
1139
1140 for (auto &small_face : faces)
1141 {
1142 // invalid faces
1143 if (small_face.n_elem() == 0)
1144 continue;
1145
1146 // not follower faces
1147 int large_face = small_face.leader;
1148 if (large_face < 0)
1149 continue;
1150
1151 // follower faces
1152 for (int j = 0; j < 3; j++)
1153 {
1154 const int v_id = small_face.vertices(j);
1155 // hanging nodes
1156 if (v_id != faces[large_face].vertices(0) && v_id != faces[large_face].vertices(1) && v_id != faces[large_face].vertices(2))
1157 vertices[v_id].face = large_face;
1158 }
1159 }
1160 }
1161 std::array<int, 4> NCMesh3D::get_ordered_vertices_from_tet(const int element_index) const
1162 {
1163 return std::array<int, 4>({{cell_vertex(element_index, 0), cell_vertex(element_index, 1), cell_vertex(element_index, 2), cell_vertex(element_index, 3)}});
1164 }
1165 int NCMesh3D::add_element(Eigen::Vector4i v, int parent)
1166 {
1167 const int id = elements.size();
1168 const int level = (parent < 0) ? 0 : elements[parent].level + 1;
1169
1170 Eigen::Vector3d e1 = vertices[v[1]].pos - vertices[v[0]].pos;
1171 Eigen::Vector3d e2 = vertices[v[2]].pos - vertices[v[0]].pos;
1172 Eigen::Vector3d e3 = vertices[v[3]].pos - vertices[v[0]].pos;
1173 if ((e1.cross(e2)).dot(e3) < 0)
1174 std::swap(v[2], v[3]);
1175
1176 e2 = vertices[v[2]].pos - vertices[v[0]].pos;
1177 e3 = vertices[v[3]].pos - vertices[v[0]].pos;
1178 assert((e1.cross(e2)).dot(e3) > 0);
1179
1180 elements.emplace_back(3, v, level, parent);
1181
1182 if (parent >= 0)
1183 elements[id].body_id = elements[parent].body_id;
1184
1185 // add faces if not exist
1186 const int face012 = get_face(v[0], v[1], v[2]);
1187 const int face013 = get_face(v[0], v[1], v[3]);
1188 const int face123 = get_face(v[1], v[2], v[3]);
1189 const int face203 = get_face(v[2], v[0], v[3]);
1190
1191 faces[face012].add_element(id);
1192 faces[face013].add_element(id);
1193 faces[face123].add_element(id);
1194 faces[face203].add_element(id);
1195
1196 elements[id].faces << face012, face013, face123, face203;
1197
1198 // add edges if not exist
1199 const int edge01 = get_edge(v[0], v[1]);
1200 const int edge12 = get_edge(v[1], v[2]);
1201 const int edge20 = get_edge(v[2], v[0]);
1202 const int edge03 = get_edge(v[0], v[3]);
1203 const int edge13 = get_edge(v[1], v[3]);
1204 const int edge23 = get_edge(v[2], v[3]);
1205
1206 edges[edge01].add_element(id);
1207 edges[edge12].add_element(id);
1208 edges[edge20].add_element(id);
1209 edges[edge03].add_element(id);
1210 edges[edge13].add_element(id);
1211 edges[edge23].add_element(id);
1212
1213 elements[id].edges << edge01, edge12, edge20, edge03, edge13, edge23;
1214
1215 n_elements++;
1216
1217 for (int i = 0; i < v.size(); i++)
1218 vertices[v[i]].add_element(id);
1219
1220 return id;
1221 }
1222 } // namespace mesh
1223} // namespace polyfem
int V
Eigen::RowVectorXd point
int edge_id
Abstract mesh class to capture 2d/3d conforming and non-conforming meshes.
Definition Mesh.hpp:49
std::vector< ElementType > elements_tag_
list of element types
Definition Mesh.hpp:728
bool has_boundary_ids() const
checks if surface selections are available
Definition Mesh.hpp:561
bool has_node_ids() const
checks if points selections are available
Definition Mesh.hpp:557
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< 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
void filter_element_data(const std::vector< bool > &keep)
Definition Mesh.cpp:55
virtual void append(const Mesh &mesh)
appends a new mesh to the end of this
Definition Mesh.cpp:589
void remove_elements(const std::vector< bool > &keep) override
Remove all top-dimensional elements whose mask entry is false.
Definition NCMesh3D.cpp:18
int find_vertex(Eigen::Vector2i v) const
Definition NCMesh3D.cpp:915
bool is_boundary_element(const int element_global_id) const override
is cell boundary
Definition NCMesh3D.cpp:91
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 NCMesh3D.cpp:236
std::vector< int > all_to_valid_elemMap
Definition NCMesh3D.hpp:479
int n_faces() const override
number of faces
Definition NCMesh3D.hpp:189
int valid_to_all_edge(const int id) const
Definition NCMesh3D.hpp:403
Navigation3D::Index next_around_edge(Navigation3D::Index idx) const override
Definition NCMesh3D.cpp:565
int face_edge(const int f_id, const int le_id) const
Definition NCMesh3D.cpp:67
int n_cell_faces(const int c_id) const override
Definition NCMesh3D.hpp:219
void traverse_edge(Eigen::Vector2i v, double p1, double p2, int depth, std::vector< follower_edge > &list) const
Definition NCMesh3D.cpp:979
std::unordered_map< Eigen::Vector2i, int, ArrayHasher2D > midpointMap
Definition NCMesh3D.hpp:475
int n_cells() const override
number of cells
Definition NCMesh3D.hpp:188
void build_element_vertex_adjacency()
void prepare_mesh() override
method used to finalize the mesh.
Definition NCMesh3D.hpp:344
std::vector< ncBoundary > edges
Definition NCMesh3D.hpp:472
int valid_to_all_face(const int id) const
Definition NCMesh3D.hpp:415
void bounding_box(RowVectorNd &min, RowVectorNd &max) const override
computes the bbox of the mesh
Definition NCMesh3D.cpp:198
void append(const Mesh &mesh) override
appends a new mesh to the end of this
Definition NCMesh3D.cpp:841
std::vector< int > refineHistory
Definition NCMesh3D.hpp:484
double edge_length(const int gid) const override
edge length
Definition NCMesh3D.cpp:156
int n_edges() const override
number of edges
Definition NCMesh3D.hpp:197
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 NCMesh3D.cpp:215
int get_edge(Eigen::Vector2i v)
Definition NCMesh3D.cpp:946
void set_point(const int global_index, const RowVectorNd &p) override
Set the point.
Definition NCMesh3D.cpp:169
int add_element(Eigen::Vector4i v, int parent=-1)
int get_face(Eigen::Vector3i v)
Definition NCMesh3D.cpp:967
void attach_higher_order_nodes(const Eigen::MatrixXd &V, const std::vector< std::vector< int > > &nodes) override
attach high order nodes
Definition NCMesh3D.cpp:129
int n_face_vertices(const int f_id) const override
number of vertices of a face
Definition NCMesh3D.hpp:214
RowVectorNd cell_barycenter(const int c) const override
cell barycenter
Definition NCMesh3D.cpp:189
std::vector< uint32_t > edge_neighs(const int e_gid) const override
Definition NCMesh3D.cpp:495
int all_to_valid_elem(const int id) const
Definition NCMesh3D.hpp:422
int n_vertices() const override
number of vertices
Definition NCMesh3D.hpp:205
std::vector< ncVert > vertices
Definition NCMesh3D.hpp:471
Navigation3D::Index get_index_from_element_edge(int hi, int v0, int v1) const override
Definition NCMesh3D.cpp:406
std::unordered_map< Eigen::Vector2i, int, ArrayHasher2D > edgeMap
Definition NCMesh3D.hpp:476
void traverse_face(int v1, int v2, int v3, Eigen::Vector2d p1, Eigen::Vector2d p2, Eigen::Vector2d p3, int depth, std::vector< follower_face > &face_list, std::vector< int > &edge_list) const
void refine(const int n_refinement, const double t) override
refine the mesh
Definition NCMesh3D.cpp:75
void normalize() override
normalize the mesh
Definition NCMesh3D.cpp:136
std::vector< int > all_to_valid_vertexMap
Definition NCMesh3D.hpp:480
int all_to_valid_edge(const int id) const
Definition NCMesh3D.hpp:398
void get_face_elements_neighs(const int f_id, std::vector< int > &ids) const
Definition NCMesh3D.cpp:586
std::unique_ptr< Mesh > copy() const override
Create a copy of the mesh.
Definition NCMesh3D.cpp:866
int valid_to_all_elem(const int id) const
Definition NCMesh3D.hpp:427
void refine_element(int id_full)
Definition NCMesh3D.cpp:593
Navigation3D::Index switch_vertex(Navigation3D::Index idx) const override
Definition NCMesh3D.cpp:504
RowVectorNd kernel(const int cell_id) const override
Definition NCMesh3D.cpp:369
bool is_boundary_vertex(const int vertex_global_id) const override
is vertex boundary
Definition NCMesh3D.hpp:229
int cell_face(const int c_id, const int lf_id) const override
Definition NCMesh3D.hpp:221
bool build_from_matrices(const Eigen::MatrixXd &V, const Eigen::MatrixXi &F) override
build a mesh from matrices
Definition NCMesh3D.cpp:101
void compute_elements_tag() override
compute element types, see ElementType
Definition NCMesh3D.cpp:148
RowVectorNd point(const int global_index) const override
point coordinates
Definition NCMesh3D.cpp:164
std::vector< int > all_to_valid_edgeMap
Definition NCMesh3D.hpp:481
int find_edge(Eigen::Vector2i v) const
Definition NCMesh3D.cpp:937
Navigation3D::Index get_index_from_element(int hi, int lf, int lv) const override
Definition NCMesh3D.cpp:374
bool is_boundary_face(const int face_global_id) const override
is face boundary
Definition NCMesh3D.hpp:231
int cell_vertex(const int f_id, const int lv_id) const override
id of the vertex of a cell
Definition NCMesh3D.hpp:220
std::vector< int > all_to_valid_faceMap
Definition NCMesh3D.hpp:482
void coarsen_element(int id_full)
Definition NCMesh3D.cpp:706
Navigation3D::Index next_around_face(Navigation3D::Index idx) const override
Definition NCMesh3D.cpp:569
std::vector< int > valid_to_all_elemMap
Definition NCMesh3D.hpp:479
std::vector< int > valid_to_all_edgeMap
Definition NCMesh3D.hpp:481
RowVectorNd face_barycenter(const int f) const override
face barycenter
Definition NCMesh3D.cpp:181
int n_cell_edges(const int c_id) const override
Definition NCMesh3D.hpp:218
Navigation3D::Index switch_element(Navigation3D::Index idx) const override
Definition NCMesh3D.cpp:546
void get_vertex_elements_neighs(const int v_id, std::vector< int > &ids) const override
Definition NCMesh3D.cpp:574
std::vector< ncElem > elements
Definition NCMesh3D.hpp:470
std::unordered_map< Eigen::Vector3i, int, ArrayHasher3D > faceMap
Definition NCMesh3D.hpp:477
RowVectorNd edge_barycenter(const int e) const override
edge barycenter
Definition NCMesh3D.cpp:174
std::vector< int > valid_to_all_faceMap
Definition NCMesh3D.hpp:482
std::vector< uint32_t > vertex_neighs(const int v_gid) const override
Definition NCMesh3D.cpp:487
std::vector< int > valid_to_all_vertexMap
Definition NCMesh3D.hpp:480
std::array< int, 4 > get_ordered_vertices_from_tet(const int element_index) const override
void update_elements_tag() override
Update elements types.
Definition NCMesh3D.cpp:152
int valid_to_all_vertex(const int id) const
Definition NCMesh3D.hpp:391
int edge_vertex(const int e_id, const int lv_id) const override
id of the edge vertex
Definition NCMesh3D.hpp:225
void refine_elements(const std::vector< int > &ids)
Definition NCMesh3D.cpp:696
int get_vertex(Eigen::Vector2i v)
Definition NCMesh3D.cpp:924
int find_face(Eigen::Vector3i v) const
Definition NCMesh3D.cpp:958
void get_edge_elements_neighs(const int e_id, std::vector< int > &ids) const override
Definition NCMesh3D.cpp:580
Navigation3D::Index switch_face(Navigation3D::Index idx) const override
Definition NCMesh3D.cpp:525
int face_vertex(const int f_id, const int lv_id) const override
id of the face vertex
Definition NCMesh3D.hpp:223
int all_to_valid_face(const int id) const
Definition NCMesh3D.hpp:410
bool load(const std::string &path) override
loads a mesh from the path
Definition NCMesh3D.cpp:871
Navigation3D::Index get_index_from_element_face(int hi, int v0, int v1, int v2) const override
Definition NCMesh3D.cpp:439
void set_body_ids(const std::vector< int > &body_ids) override
Set the volume sections.
Definition NCMesh3D.cpp:256
void set_boundary_ids(const std::vector< int > &boundary_ids) override
Set the boundary selection from a vector.
Definition NCMesh3D.cpp:248
std::vector< ncBoundary > faces
Definition NCMesh3D.hpp:473
Navigation3D::Index switch_edge(Navigation3D::Index idx) const override
Definition NCMesh3D.cpp:517
bool endswith(const std::string &str, const std::string &suffix)
std::tuple< bool, int, Tree > is_valid(const int dim, const std::vector< basis::ElementBases > &bases, const std::vector< basis::ElementBases > &gbases, const Eigen::VectorXd &u, const double threshold, const unsigned max_iter)
Definition Jacobian.cpp:201
Eigen::Matrix< double, 1, Eigen::Dynamic, Eigen::RowMajor, 1, 3 > RowVectorNd
Definition Types.hpp:13