PolyFEM
Loading...
Searching...
No Matches
CMesh3D.cpp
Go to the documentation of this file.
5
7
8#include <igl/barycentric_coordinates.h>
9
10#include <geogram/mesh/mesh_io.h>
11#include <fstream>
12#include <unordered_map>
13
14using namespace polyfem::utils;
15
16namespace polyfem
17{
18 namespace mesh
19 {
20 void CMesh3D::remove_elements(const std::vector<bool> &keep)
21 {
22 assert(keep.size() == n_cells());
23
24 auto face_key = [this](const int f) {
25 std::vector<int> key(n_face_vertices(f));
26 for (int lv = 0; lv < key.size(); ++lv)
27 key[lv] = face_vertex(f, lv);
28 std::sort(key.begin(), key.end());
29 return key;
30 };
31 auto edge_key = [this](const int e) {
32 return std::pair<int, int>(
33 std::min(edge_vertex(e, 0), edge_vertex(e, 1)),
34 std::max(edge_vertex(e, 0), edge_vertex(e, 1)));
35 };
36
37 std::unordered_map<std::vector<int>, int, utils::HashVector> old_boundary_ids;
38 std::unordered_map<std::vector<int>, FaceNodes, utils::HashVector> old_face_nodes;
39 for (int f = 0; f < n_faces(); ++f)
40 {
41 const auto key = face_key(f);
42 if (has_boundary_ids())
43 old_boundary_ids[key] = boundary_ids_[f];
44 if (f < face_nodes_.size())
45 old_face_nodes[key] = face_nodes_[f];
46 }
47
48 std::unordered_map<std::pair<int, int>, EdgeNodes, utils::HashPair> old_edge_nodes;
49 for (int e = 0; e < n_edges() && e < edge_nodes_.size(); ++e)
50 old_edge_nodes[edge_key(e)] = edge_nodes_[e];
51
52 if (cell_nodes_.size() == keep.size())
53 {
54 std::vector<CellNodes> filtered;
55 for (int c = 0; c < keep.size(); ++c)
56 if (keep[c])
57 filtered.push_back(cell_nodes_[c]);
58 cell_nodes_ = std::move(filtered);
59 }
61
62 std::vector<bool> used_faces(mesh_.faces.size(), false);
63 for (int c = 0; c < keep.size(); ++c)
64 if (keep[c])
65 for (const int f : mesh_.elements[c].fs)
66 used_faces[f] = true;
67
68 std::vector<int> old_to_new_face(mesh_.faces.size(), -1);
69 std::vector<Face> faces;
70 faces.reserve(std::count(used_faces.begin(), used_faces.end(), true));
71 for (int f = 0; f < used_faces.size(); ++f)
72 {
73 if (!used_faces[f])
74 continue;
75 old_to_new_face[f] = faces.size();
76 faces.push_back(mesh_.faces[f]);
77 faces.back().id = faces.size() - 1;
78 }
79
80 std::vector<Element> elements;
81 elements.reserve(std::count(keep.begin(), keep.end(), true));
82 for (int c = 0; c < keep.size(); ++c)
83 {
84 if (!keep[c])
85 continue;
86 elements.push_back(mesh_.elements[c]);
87 auto &element = elements.back();
88 element.id = elements.size() - 1;
89 for (auto &f : element.fs)
90 f = old_to_new_face[f];
91 }
92 mesh_.faces = std::move(faces);
93 mesh_.elements = std::move(elements);
94
96
97 if (!old_boundary_ids.empty())
98 {
99 boundary_ids_.resize(n_faces());
100 for (int f = 0; f < n_faces(); ++f)
101 {
102 const auto it = old_boundary_ids.find(face_key(f));
103 boundary_ids_[f] = it == old_boundary_ids.end() ? get_default_boundary_id(f) : it->second;
104 }
105 }
106 else
107 boundary_ids_.clear();
108
109 face_nodes_.clear();
110 if (!old_face_nodes.empty())
111 {
112 face_nodes_.resize(n_faces());
113 for (int f = 0; f < n_faces(); ++f)
114 {
115 const auto it = old_face_nodes.find(face_key(f));
116 if (it != old_face_nodes.end())
117 face_nodes_[f] = it->second;
118 }
119 }
120
121 edge_nodes_.clear();
122 if (!old_edge_nodes.empty())
123 {
124 edge_nodes_.resize(n_edges());
125 for (int e = 0; e < n_edges(); ++e)
126 {
127 const auto it = old_edge_nodes.find(edge_key(e));
128 if (it != old_edge_nodes.end())
129 edge_nodes_[e] = it->second;
130 }
131 }
132
133 in_ordered_edges_.resize(n_edges(), 2);
134 for (int e = 0; e < n_edges(); ++e)
135 in_ordered_edges_.row(e) << edge_vertex(e, 0), edge_vertex(e, 1);
136 const int max_face_size = n_faces() == 0 ? 0 : std::max_element(mesh_.faces.begin(), mesh_.faces.end(), [](const Face &a, const Face &b) { return a.vs.size() < b.vs.size(); })->vs.size();
137 in_ordered_faces_.setConstant(n_faces(), max_face_size, -1);
138 for (int f = 0; f < n_faces(); ++f)
139 for (int lv = 0; lv < n_face_vertices(f); ++lv)
140 in_ordered_faces_(f, lv) = face_vertex(f, lv);
142 }
143
144 void CMesh3D::refine(const int n_refinement, const double t)
145 {
146 if (n_refinement <= 0)
147 {
148 return;
149 }
150
151 // TODO refine high order mesh!
152 orders_.resize(0, 0);
153 if (mesh_.type == MeshType::TET)
154 {
156 }
157 else
158 {
159 for (size_t i = 0; i < elements_tag().size(); ++i)
160 {
162 mesh_.elements[i].hex = false;
163 }
164
165 bool reverse_grow = false;
166 std::vector<int> parent_nodes;
167 MeshProcessing3D::refine_catmul_clark_polar(mesh_, n_refinement, reverse_grow, parent_nodes);
168 }
169
172
173 in_ordered_vertices_ = Eigen::VectorXi::LinSpaced(n_vertices(), 0, n_vertices() - 1);
174 assert(in_ordered_vertices_[0] == 0);
175 assert(in_ordered_vertices_[1] == 1);
176 assert(in_ordered_vertices_[2] == 2);
177 assert(in_ordered_vertices_[in_ordered_vertices_.size() - 1] == n_vertices() - 1);
178
179 in_ordered_edges_.resize(mesh_.edges.size(), 2);
180
181 for (int e = 0; e < (int)mesh_.edges.size(); ++e)
182 {
183 assert(mesh_.edges[e].vs.size() == 2);
184 for (int lv = 0; lv < 2; ++lv)
185 {
186 in_ordered_edges_(e, lv) = mesh_.edges[e].vs[lv];
187 }
188 }
189 assert(in_ordered_edges_.size() > 0);
190
191 in_ordered_faces_.resize(mesh_.faces.size(), mesh_.faces[0].vs.size());
192
193 for (int f = 0; f < (int)mesh_.faces.size(); ++f)
194 {
195 assert(in_ordered_faces_.cols() == mesh_.faces[f].vs.size());
196
197 for (int lv = 0; lv < in_ordered_faces_.cols(); ++lv)
198 {
199 in_ordered_faces_(f, lv) = mesh_.faces[f].vs[lv];
200 }
201 }
202 assert(in_ordered_faces_.size() > 0);
203 }
204
205 bool CMesh3D::load(const std::string &path)
206 {
207 edge_nodes_.clear();
208 face_nodes_.clear();
209 cell_nodes_.clear();
210
211 if (!StringUtils::endswith(path, ".HYBRID"))
212 {
213 GEO::Mesh M;
214 GEO::mesh_load(path, M);
215 return load(M);
216 }
217
218 FILE *f = fopen(path.data(), "rt");
219 if (!f)
220 return false;
221
222 int nv, np, nh;
223 auto _ = fscanf(f, "%d %d %d", &nv, &np, &nh);
224 nh /= 3;
225
226 mesh_.points.resize(3, nv);
227 mesh_.vertices.resize(nv);
228
229 for (int i = 0; i < nv; i++)
230 {
231 double x, y, z;
232 auto _ = fscanf(f, "%lf %lf %lf", &x, &y, &z);
233 mesh_.points(0, i) = x;
234 mesh_.points(1, i) = y;
235 mesh_.points(2, i) = z;
236 Vertex v;
237 v.id = i;
238 mesh_.vertices[i] = v;
239 }
240 mesh_.faces.resize(np);
241 for (int i = 0; i < np; i++)
242 {
243 Face &p = mesh_.faces[i];
244 p.id = i;
245 int nw;
246
247 auto _ = fscanf(f, "%d", &nw);
248 p.vs.resize(nw);
249 for (int j = 0; j < nw; j++)
250 {
251 auto _ = fscanf(f, "%u", &(p.vs[j]));
252 }
253 }
254 mesh_.elements.resize(nh);
255 for (int i = 0; i < nh; i++)
256 {
257 Element &h = mesh_.elements[i];
258 h.id = i;
259
260 int nf;
261 auto _ = fscanf(f, "%d", &nf);
262 h.fs.resize(nf);
263
264 for (int j = 0; j < nf; j++)
265 {
266 auto _ = fscanf(f, "%u", &(h.fs[j]));
267 }
268
269 for (auto fid : h.fs)
270 h.vs.insert(h.vs.end(), mesh_.faces[fid].vs.begin(), mesh_.faces[fid].vs.end());
271 sort(h.vs.begin(), h.vs.end());
272 h.vs.erase(unique(h.vs.begin(), h.vs.end()), h.vs.end());
273
274 int tmp;
275 auto __ = fscanf(f, "%d", &tmp);
276 for (int j = 0; j < nf; j++)
277 {
278 int s;
279 auto _ = fscanf(f, "%d", &s);
280 h.fs_flag.push_back(s);
281 }
282 }
283 for (int i = 0; i < nh; i++)
284 {
285 int tmp;
286 auto _ = fscanf(f, "%d", &tmp);
287 mesh_.elements[i].hex = tmp;
288 }
289
290 char s[1024], sread[1024];
291 int find = false, num = 0;
292 while (!feof(f) && !find)
293 {
294 auto _ = fgets(s, 1024, f);
295 if (sscanf(s, "%s%d", sread, &num) == 2 && (strcmp(sread, "KERNEL") == 0))
296 find = true;
297 }
298 if (find)
299 {
300 for (int i = 0; i < nh; i++)
301 {
302 double x, y, z;
303 auto _ = fscanf(f, "%lf %lf %lf", &x, &y, &z);
304 mesh_.elements[i].v_in_Kernel.push_back(x);
305 mesh_.elements[i].v_in_Kernel.push_back(y);
306 mesh_.elements[i].v_in_Kernel.push_back(z);
307 }
308 }
309
310 fclose(f);
311
312 // remove horrible kernels and replace with barycenters
313 for (int c = 0; c < n_cells(); ++c)
314 {
315 auto bary = cell_barycenter(c);
316 for (int d = 0; d < 3; ++d)
317 mesh_.elements[c].v_in_Kernel[d] = bary(d);
318 }
319
321 // if(is_simplicial())
322 // MeshProcessing3D::orient_volume_mesh(mesh_);
324 return true;
325 }
326
327 // load from a geogram surface mesh (for debugging), or volume mesh
328 // if loading a surface mesh, it assumes there is only one polyhedral cell, and the last vertex id a point in the kernel
329 bool CMesh3D::load(const GEO::Mesh &M)
330 {
331 edge_nodes_.clear();
332 face_nodes_.clear();
333 cell_nodes_.clear();
334
335 assert(M.vertices.dimension() == 3);
336
337 // Set vertices
338 const int nv = M.vertices.nb();
339 mesh_.points.resize(3, nv);
340 mesh_.vertices.resize(nv);
341 for (int i = 0; i < nv; ++i)
342 {
343 mesh_.points(0, i) = M.vertices.point(i)[0];
344 mesh_.points(1, i) = M.vertices.point(i)[1];
345 mesh_.points(2, i) = M.vertices.point(i)[2];
346 Vertex v;
347 v.id = i;
348 mesh_.vertices[i] = v;
349 }
350
351 // Set cells
352 if (M.cells.nb() == 0)
353 {
354
355 bool last_isolated = true;
356
357 // Set faces
358 mesh_.faces.resize(M.facets.nb());
359 for (int i = 0; i < (int)M.facets.nb(); ++i)
360 {
361 Face &face = mesh_.faces[i];
362 face.id = i;
363
364 face.vs.resize(M.facets.nb_vertices(i));
365 for (int j = 0; j < (int)M.facets.nb_vertices(i); ++j)
366 {
367 face.vs[j] = M.facets.vertex(i, j);
368 if ((int)face.vs[j] == nv - 1)
369 {
370 last_isolated = false;
371 }
372 }
373 }
374
375 // Assumes there is only 1 polyhedron described by a closed input surface
376 mesh_.elements.resize(1);
377 for (int i = 0; i < 1; ++i)
378 {
379 Element &cell = mesh_.elements[i];
380 cell.id = i;
381
382 int nf = M.facets.nb();
383 cell.fs.resize(nf);
384
385 for (int j = 0; j < nf; ++j)
386 {
387 cell.fs[j] = j;
388 }
389
390 for (auto fid : cell.fs)
391 {
392 cell.vs.insert(cell.vs.end(), mesh_.faces[fid].vs.begin(), mesh_.faces[fid].vs.end());
393 }
394 sort(cell.vs.begin(), cell.vs.end());
395 cell.vs.erase(unique(cell.vs.begin(), cell.vs.end()), cell.vs.end());
396
397 for (int j = 0; j < nf; ++j)
398 {
399 cell.fs_flag.push_back(1);
400 }
401
402 if (last_isolated)
403 {
404 cell.v_in_Kernel.push_back(M.vertices.point(nv - 1)[0]);
405 cell.v_in_Kernel.push_back(M.vertices.point(nv - 1)[1]);
406 cell.v_in_Kernel.push_back(M.vertices.point(nv - 1)[2]);
407 }
408 else
409 {
410 // Compute a point in the kernel (assumes the barycenter is ok)
411 Eigen::RowVector3d p(0, 0, 0);
412 for (int v : cell.vs)
413 {
414 p += mesh_.points.col(v).transpose();
415 }
416 p /= cell.vs.size();
417 cell.v_in_Kernel.push_back(p[0]);
418 cell.v_in_Kernel.push_back(p[1]);
419 cell.v_in_Kernel.push_back(p[2]);
420 }
421 }
422
423 for (int i = 0; i < 1; ++i)
424 {
425 mesh_.elements[i].hex = false;
426 } // FIME me here!
427
428 mesh_.type = M.cells.are_simplices() ? MeshType::TET : MeshType::HYB;
429 }
430 else
431 {
432
433 // Set faces
434 mesh_.faces.clear();
435 // for (int f = 0; f < (int) M.facets.nb(); ++f) {
436 // Face &face = mesh_.faces[f];
437 // face.id = -1;
438 // face.vs.clear();
439 // // face.id = f;
440
441 // // face.vs.resize(M.facets.nb_vertices(f));
442 // // for (int lv = 0; lv < (int) M.facets.nb_vertices(f); ++lv) {
443 // // face.vs[lv] = M.facets.vertex(f, lv);
444 // // }
445 // }
446
447 auto opposite_cell_facet = [&M](int c, int cf) {
448 GEO::index_t c2 = M.cell_facets.adjacent_cell(cf);
449 if (c2 == GEO::NO_FACET)
450 {
451 return -1;
452 }
453 for (int lf = 0; lf < (int)M.cells.nb_facets(c2); ++lf)
454 {
455 if (c == (int)M.cells.adjacent(c2, lf))
456 {
457 return (int)M.cells.facet(c2, lf);
458 }
459 }
460 assert(false);
461 return -1;
462 };
463
464 std::vector<int> cell_facet_to_facet(M.cell_facets.nb(), -1);
465
466 // Creates 1 hex or polyhedral element for each cell of the input mesh
467 int facet_counter = 0;
468 mesh_.elements.resize(M.cells.nb());
469 bool is_hex = true;
470 for (int c = 0; c < (int)M.cells.nb(); ++c)
471 {
472 Element &cell = mesh_.elements[c];
473 cell.id = c;
474 cell.hex = (M.cells.type(c) == GEO::MESH_HEX);
475
476 is_hex = is_hex && cell.hex;
477
478 int nf = M.cells.nb_facets(c);
479 cell.fs.resize(nf);
480
481 for (int lf = 0; lf < nf; ++lf)
482 {
483 int cf = M.cells.facet(c, lf);
484 int cf2 = opposite_cell_facet(c, cf);
485 if (cf2 < 0 || cell_facet_to_facet[cf2] < 0)
486 {
487 mesh_.faces.emplace_back();
488 Face &face = mesh_.faces[facet_counter];
489 assert(face.vs.empty());
490 face.vs.resize(M.cells.facet_nb_vertices(c, lf));
491 for (int lv = 0; lv < (int)M.cells.facet_nb_vertices(c, lf); ++lv)
492 {
493 face.vs[lv] = M.cells.facet_vertex(c, lf, lv);
494 }
495 cell.fs_flag.push_back(0);
496 cell.fs[lf] = face.id = facet_counter;
497 cell_facet_to_facet[cf] = facet_counter;
498 ++facet_counter;
499 }
500 else
501 {
502 cell.fs[lf] = cell_facet_to_facet[cf2];
503 cell.fs_flag.push_back(1);
504 }
505 }
506
507 cell.input_vs.resize(M.cells.nb_vertices(c));
508 for (int lv = 0; lv < (int)M.cells.nb_vertices(c); ++lv)
509 cell.input_vs[lv] = M.cells.vertex(c, lv);
510
511 // Compute a point in the kernel (assumes the barycenter is ok)
512 Eigen::RowVector3d p(0, 0, 0);
513 for (int v : cell.input_vs)
514 {
515 p += mesh_.points.col(v).transpose();
516 }
517 p /= cell.input_vs.size();
518 mesh_.elements[c].v_in_Kernel.push_back(p[0]);
519 mesh_.elements[c].v_in_Kernel.push_back(p[1]);
520 mesh_.elements[c].v_in_Kernel.push_back(p[2]);
521 }
522 mesh_.type = is_hex ? MeshType::HEX : (M.cells.are_simplices() ? MeshType::TET : MeshType::HYB);
523 }
524
526 // if (is_simplicial()) {
527 // MeshProcessing3D::orient_volume_mesh(mesh_);
528 // }
530 return true;
531 }
532
533 bool CMesh3D::save(const std::string &path) const
534 {
535
536 if (!StringUtils::endswith(path, ".HYBRID"))
537 {
538 GEO::Mesh M;
539 to_geogram_mesh(*this, M);
540 GEO::mesh_save(M, path);
541 return true;
542 }
543
544 std::fstream f(path, std::ios::out);
545
546 f << mesh_.points.cols() << " " << mesh_.faces.size() << " " << 3 * mesh_.elements.size() << std::endl;
547 for (int i = 0; i < mesh_.points.cols(); i++)
548 f << mesh_.points(0, i) << " " << mesh_.points(1, i) << " " << mesh_.points(2, i) << std::endl;
549
550 for (auto f_ : mesh_.faces)
551 {
552 f << f_.vs.size() << " ";
553 for (auto vid : f_.vs)
554 f << vid << " ";
555 f << std::endl;
556 }
557
558 for (uint32_t i = 0; i < mesh_.elements.size(); i++)
559 {
560 f << mesh_.elements[i].fs.size() << " ";
561 for (auto fid : mesh_.elements[i].fs)
562 f << fid << " ";
563 f << std::endl;
564 f << mesh_.elements[i].fs_flag.size() << " ";
565 for (auto f_flag : mesh_.elements[i].fs_flag)
566 f << f_flag << " ";
567 f << std::endl;
568 }
569
570 for (uint32_t i = 0; i < mesh_.elements.size(); i++)
571 {
572 f << mesh_.elements[i].hex << std::endl;
573 }
574
575 f << "KERNEL"
576 << " " << mesh_.elements.size() << std::endl;
577 for (uint32_t i = 0; i < mesh_.elements.size(); i++)
578 {
579 f << mesh_.elements[i].v_in_Kernel[0] << " " << mesh_.elements[i].v_in_Kernel[1] << " " << mesh_.elements[i].v_in_Kernel[2] << std::endl;
580 }
581 f.close();
582
583 return true;
584 }
585
586 bool CMesh3D::build_from_matrices(const Eigen::MatrixXd &V, const Eigen::MatrixXi &F)
587 {
588 assert(F.cols() == 4 || F.cols() == 5 || F.cols() == 6 || F.cols() == 8);
589 edge_nodes_.clear();
590 face_nodes_.clear();
591 cell_nodes_.clear();
592
593 GEO::Mesh M;
594 M.vertices.create_vertices((int)V.rows());
595 for (int i = 0; i < (int)M.vertices.nb(); ++i)
596 {
597 GEO::vec3 &p = M.vertices.point(i);
598 p[0] = V(i, 0);
599 p[1] = V(i, 1);
600 p[2] = V(i, 2);
601 }
602
603 static const std::vector<int> permute_tet = {0, 1, 2, 3};
604 static const std::vector<int> permute_pyramid = {0, 1, 2, 3, 4};
605 static const std::vector<int> permute_prism = {0, 1, 2, 3, 4, 5};
606 // polyfem uses the msh file format for hexes ordering!
607 static const std::vector<int> permute_hex = {1, 0, 2, 3, 5, 4, 6, 7};
608
609 auto add_cell = [&](int c, GEO::MeshCellType t, int nv, const std::vector<int> &perm) {
610 GEO::index_t cid = M.cells.create_cells(1, t);
611 for (int lv = 0; lv < nv; ++lv)
612 {
613 int vi = F(c, perm[lv]);
614 assert(vi >= 0 && vi < V.rows());
615 M.cells.set_vertex(cid, lv, GEO::index_t(vi));
616 }
617 };
618
619 for (int c = 0; c < F.rows(); ++c)
620 {
621 int nV;
622 for (nV = 0; nV < F.cols(); ++nV)
623 {
624 if (F(c, nV) == -1)
625 break;
626 }
627
628#ifndef NDEBUG
629 for (int k = nV; k < F.cols(); ++k)
630 {
631 assert(F(c, k) == -1);
632 }
633#endif
634 if (nV == 4)
635 add_cell(c, GEO::MESH_TET, 4, permute_tet);
636 else if (nV == 5)
637 add_cell(c, GEO::MESH_PYRAMID, 5, permute_pyramid);
638 else if (nV == 6)
639 add_cell(c, GEO::MESH_PRISM, 6, permute_prism);
640 else if (nV == 8)
641 add_cell(c, GEO::MESH_HEX, 8, permute_hex);
642 else
643 log_and_throw_error(fmt::format("Invalid number of vertices {}", nV));
644 }
645 M.cells.connect();
646
647 return load(M);
648 }
649
650 void CMesh3D::attach_higher_order_nodes(const Eigen::MatrixXd &V, const std::vector<std::vector<int>> &nodes)
651 {
652 edge_nodes_.clear();
653 face_nodes_.clear();
654 cell_nodes_.clear();
655
656 edge_nodes_.resize(n_edges());
657 face_nodes_.resize(n_faces());
658 cell_nodes_.resize(n_cells());
659
660 orders_.resize(n_cells(), 1);
661
662 const auto attach_p2 = [&](const Navigation3D::Index &index, const std::vector<int> &nodes_ids) {
663 auto &n = edge_nodes_[index.edge];
664
665 if (n.nodes.size() > 0)
666 return;
667
668 n.v1 = index.vertex;
669 n.v2 = switch_vertex(index).vertex;
670
671 const int n_v1 = index.vertex;
672 const int n_v2 = switch_vertex(index).vertex;
673
674 int node_index = 0;
675
676 if ((n_v1 == nodes_ids[0] && n_v2 == nodes_ids[1]) || (n_v2 == nodes_ids[0] && n_v1 == nodes_ids[1]))
677 node_index = 4;
678 else if ((n_v1 == nodes_ids[1] && n_v2 == nodes_ids[2]) || (n_v2 == nodes_ids[1] && n_v1 == nodes_ids[2]))
679 node_index = 5;
680 else if ((n_v1 == nodes_ids[2] && n_v2 == nodes_ids[3]) || (n_v2 == nodes_ids[2] && n_v1 == nodes_ids[3]))
681 node_index = 8;
682
683 else if ((n_v1 == nodes_ids[0] && n_v2 == nodes_ids[3]) || (n_v2 == nodes_ids[0] && n_v1 == nodes_ids[3]))
684 node_index = 7;
685 else if ((n_v1 == nodes_ids[0] && n_v2 == nodes_ids[2]) || (n_v2 == nodes_ids[0] && n_v1 == nodes_ids[2]))
686 node_index = 6;
687 else
688 node_index = 9;
689
690 n.nodes.resize(1, 3);
691 n.nodes << V(nodes_ids[node_index], 0), V(nodes_ids[node_index], 1), V(nodes_ids[node_index], 2);
692 n.nodes_ids.push_back(nodes_ids[node_index]);
693 };
694
695 const auto attach_p3 = [&](const Navigation3D::Index &index, const std::vector<int> &nodes_ids) {
696 auto &n = edge_nodes_[index.edge];
697
698 if (n.nodes.size() > 0)
699 return;
700
701 n.v1 = index.vertex;
702 n.v2 = switch_vertex(index).vertex;
703
704 const int n_v1 = index.vertex;
705 const int n_v2 = switch_vertex(index).vertex;
706
707 int node_index1 = 0;
708 int node_index2 = 0;
709 if (n_v1 == nodes_ids[0] && n_v2 == nodes_ids[1])
710 {
711 node_index1 = 4;
712 node_index2 = 5;
713 }
714 else if (n_v2 == nodes_ids[0] && n_v1 == nodes_ids[1])
715 {
716 node_index1 = 5;
717 node_index2 = 4;
718 }
719 else if (n_v1 == nodes_ids[1] && n_v2 == nodes_ids[2])
720 {
721 node_index1 = 6;
722 node_index2 = 7;
723 }
724 else if (n_v2 == nodes_ids[1] && n_v1 == nodes_ids[2])
725 {
726 node_index1 = 7;
727 node_index2 = 6;
728 }
729 else if (n_v1 == nodes_ids[2] && n_v2 == nodes_ids[3])
730 {
731 node_index1 = 13;
732 node_index2 = 12;
733 }
734 else if (n_v2 == nodes_ids[2] && n_v1 == nodes_ids[3])
735 {
736 node_index1 = 12;
737 node_index2 = 13;
738 }
739
740 else if (n_v1 == nodes_ids[0] && n_v2 == nodes_ids[3])
741 {
742 node_index1 = 11;
743 node_index2 = 10;
744 }
745 else if (n_v2 == nodes_ids[0] && n_v1 == nodes_ids[3])
746 {
747 node_index1 = 10;
748 node_index2 = 11;
749 }
750 else if (n_v1 == nodes_ids[0] && n_v2 == nodes_ids[2])
751 {
752 node_index1 = 9;
753 node_index2 = 8;
754 }
755 else if (n_v2 == nodes_ids[0] && n_v1 == nodes_ids[2])
756 {
757 node_index1 = 8;
758 node_index2 = 9;
759 }
760
761 else if (n_v2 == nodes_ids[1] && n_v1 == nodes_ids[3])
762 {
763 node_index1 = 14;
764 node_index2 = 15;
765 }
766 else
767 {
768 node_index1 = 15;
769 node_index2 = 14;
770 }
771
772 n.nodes.resize(2, 3);
773 n.nodes.row(0) << V(nodes_ids[node_index1], 0), V(nodes_ids[node_index1], 1), V(nodes_ids[node_index1], 2);
774 n.nodes.row(1) << V(nodes_ids[node_index2], 0), V(nodes_ids[node_index2], 1), V(nodes_ids[node_index2], 2);
775 n.nodes_ids.push_back(nodes_ids[node_index1]);
776 n.nodes_ids.push_back(nodes_ids[node_index2]);
777 };
778
779 const auto attach_p3_face = [&](const Navigation3D::Index &index, const std::vector<int> &nodes_ids, int id) {
780 auto &n = face_nodes_[index.face];
781 if (n.nodes.size() <= 0)
782 {
783 n.v1 = face_vertex(index.face, 0);
784 n.v2 = face_vertex(index.face, 1);
785 n.v3 = face_vertex(index.face, 2);
786 n.nodes.resize(1, 3);
787 n.nodes << V(nodes_ids[id], 0), V(nodes_ids[id], 1), V(nodes_ids[id], 2);
788 n.nodes_ids.push_back(nodes_ids[id]);
789 }
790 };
791
792 const auto attach_p4 = [&](const Navigation3D::Index &index, const std::vector<int> &nodes_ids) {
793 auto &n = edge_nodes_[index.edge];
794
795 if (n.nodes.size() > 0)
796 return;
797
798 n.v1 = index.vertex;
799 n.v2 = switch_vertex(index).vertex;
800
801 const int n_v1 = index.vertex;
802 const int n_v2 = switch_vertex(index).vertex;
803
804 int node_index1 = 0;
805 int node_index2 = 0;
806 int node_index3 = 0;
807 if (n_v1 == nodes_ids[0] && n_v2 == nodes_ids[1])
808 {
809 node_index1 = 4;
810 node_index2 = 5;
811 node_index3 = 6;
812 }
813 else if (n_v2 == nodes_ids[0] && n_v1 == nodes_ids[1])
814 {
815 node_index1 = 6;
816 node_index2 = 5;
817 node_index3 = 4;
818 }
819
820 else if (n_v1 == nodes_ids[1] && n_v2 == nodes_ids[2])
821 {
822 node_index1 = 7;
823 node_index2 = 8;
824 node_index3 = 9;
825 }
826 else if (n_v2 == nodes_ids[1] && n_v1 == nodes_ids[2])
827 {
828 node_index1 = 9;
829 node_index2 = 8;
830 node_index3 = 7;
831 }
832
833 else if (n_v2 == nodes_ids[0] && n_v1 == nodes_ids[2])
834 {
835 node_index1 = 10;
836 node_index2 = 11;
837 node_index3 = 12;
838 }
839 else if (n_v1 == nodes_ids[0] && n_v2 == nodes_ids[2])
840 {
841 node_index1 = 12;
842 node_index2 = 11;
843 node_index3 = 10;
844 }
845
846 else if (n_v2 == nodes_ids[0] && n_v1 == nodes_ids[3])
847 {
848 node_index1 = 13;
849 node_index2 = 14;
850 node_index3 = 15;
851 }
852 else if (n_v1 == nodes_ids[0] && n_v2 == nodes_ids[3])
853 {
854 node_index1 = 15;
855 node_index2 = 14;
856 node_index3 = 13;
857 }
858
859 else if (n_v2 == nodes_ids[2] && n_v1 == nodes_ids[3])
860 {
861 node_index1 = 16;
862 node_index2 = 17;
863 node_index3 = 18;
864 }
865 else if (n_v1 == nodes_ids[2] && n_v2 == nodes_ids[3])
866 {
867 node_index1 = 18;
868 node_index2 = 17;
869 node_index3 = 16;
870 }
871
872 else if (n_v2 == nodes_ids[1] && n_v1 == nodes_ids[3])
873 {
874 node_index1 = 19;
875 node_index2 = 20;
876 node_index3 = 21;
877 }
878 else if (n_v1 == nodes_ids[1] && n_v2 == nodes_ids[3])
879 {
880 node_index1 = 21;
881 node_index2 = 20;
882 node_index3 = 19;
883 }
884 else
885 {
886 assert(false);
887 }
888
889 n.nodes.resize(3, 3);
890 n.nodes.row(0) << V(nodes_ids[node_index1], 0), V(nodes_ids[node_index1], 1), V(nodes_ids[node_index1], 2);
891 n.nodes.row(1) << V(nodes_ids[node_index2], 0), V(nodes_ids[node_index2], 1), V(nodes_ids[node_index2], 2);
892 n.nodes.row(2) << V(nodes_ids[node_index3], 0), V(nodes_ids[node_index3], 1), V(nodes_ids[node_index3], 2);
893 n.nodes_ids.push_back(nodes_ids[node_index1]);
894 n.nodes_ids.push_back(nodes_ids[node_index2]);
895 n.nodes_ids.push_back(nodes_ids[node_index3]);
896 };
897
898 const auto attach_p4_face = [&](const Navigation3D::Index &index, const std::vector<int> &nodes_ids) {
899 auto &n = face_nodes_[index.face];
900 if (n.nodes.size() <= 0)
901 {
902 n.v1 = face_vertex(index.face, 0);
903 n.v2 = face_vertex(index.face, 1);
904 n.v3 = face_vertex(index.face, 2);
905
906 std::array<int, 3> vid = {{n.v1, n.v2, n.v3}};
907 std::sort(vid.begin(), vid.end());
908
909 std::array<int, 3> c1 = {{nodes_ids[0], nodes_ids[1], nodes_ids[2]}}; // 22
910 std::array<int, 3> c2 = {{nodes_ids[0], nodes_ids[1], nodes_ids[3]}}; // 25
911 std::array<int, 3> c3 = {{nodes_ids[0], nodes_ids[2], nodes_ids[3]}}; // 28
912 std::array<int, 3> c4 = {{nodes_ids[1], nodes_ids[2], nodes_ids[3]}}; // 31
913
914 std::sort(c1.begin(), c1.end());
915 std::sort(c2.begin(), c2.end());
916 std::sort(c3.begin(), c3.end());
917 std::sort(c4.begin(), c4.end());
918
919 int id = 0;
920 int index0 = 0;
921 int index1 = 1;
922 int index2 = 2;
923 if (vid == c1)
924 {
925 id = 22;
926 n.v1 = nodes_ids[0];
927 n.v2 = nodes_ids[1];
928 n.v3 = nodes_ids[2];
929
930 index0 = 0;
931 index1 = 2;
932 index2 = 1; // ok
933 }
934 else if (vid == c2)
935 {
936 id = 25;
937 n.v1 = nodes_ids[0];
938 n.v2 = nodes_ids[1];
939 n.v3 = nodes_ids[3];
940
941 index0 = 0;
942 index1 = 1;
943 index2 = 2; // ok
944 }
945 else if (vid == c3)
946 {
947 id = 28;
948 n.v1 = nodes_ids[0];
949 n.v2 = nodes_ids[2];
950 n.v3 = nodes_ids[3];
951
952 index0 = 0;
953 index1 = 2;
954 index2 = 1; // ok
955 }
956 else if (vid == c4)
957 {
958 id = 31;
959 n.v1 = nodes_ids[1];
960 n.v2 = nodes_ids[2];
961 n.v3 = nodes_ids[3];
962
963 index0 = 1;
964 index1 = 2;
965 index2 = 0; // ok
966 }
967 else
968 {
969 // the face nees to be one of the 4 above
970 assert(false);
971 }
972
973 n.nodes.resize(3, 3);
974 assert(id + index0 < nodes_ids.size());
975 assert(id + index1 < nodes_ids.size());
976 assert(id + index2 < nodes_ids.size());
977 n.nodes.row(0) << V(nodes_ids[id + index0], 0), V(nodes_ids[id + index0], 1), V(nodes_ids[id + index0], 2);
978 n.nodes.row(1) << V(nodes_ids[id + index1], 0), V(nodes_ids[id + index1], 1), V(nodes_ids[id + index1], 2);
979 n.nodes.row(2) << V(nodes_ids[id + index2], 0), V(nodes_ids[id + index2], 1), V(nodes_ids[id + index2], 2);
980 n.nodes_ids.push_back(nodes_ids[id + index0]);
981 n.nodes_ids.push_back(nodes_ids[id + index1]);
982 n.nodes_ids.push_back(nodes_ids[id + index2]);
983 }
984 };
985
986 const auto attach_p4_cell = [&](const Navigation3D::Index &index, const std::vector<int> &nodes_ids) {
987 auto &n = cell_nodes_[index.element];
988 assert(nodes_ids.size() == 35);
989 assert(n.nodes.size() == 0);
990
991 if (n.nodes.size() <= 0)
992 {
993 n.v1 = cell_vertex(index.element, 0);
994 n.v2 = cell_vertex(index.element, 1);
995 n.v3 = cell_vertex(index.element, 2);
996 n.v4 = cell_vertex(index.element, 3);
997 n.nodes.resize(1, 3);
998
999 n.nodes << V(nodes_ids[34], 0), V(nodes_ids[34], 1), V(nodes_ids[34], 2);
1000 n.nodes_ids.push_back(nodes_ids[34]);
1001 }
1002 };
1003
1004 assert(nodes.size() == n_cells());
1005
1006 for (int c = 0; c < n_cells(); ++c)
1007 {
1008 auto index = get_index_from_element(c);
1009
1010 const auto &nodes_ids = nodes[c];
1011
1012 if (nodes_ids.size() == 4)
1013 {
1014 orders_(c) = 1;
1015 continue;
1016 }
1017 // P2
1018 else if (nodes_ids.size() == 10)
1019 {
1020 orders_(c) = 2;
1021
1022 for (int le = 0; le < 3; ++le)
1023 {
1024 attach_p2(index, nodes_ids);
1025 index = next_around_face(index);
1026 }
1027
1028 index = switch_vertex(switch_edge(switch_face(index)));
1029 attach_p2(index, nodes_ids);
1030
1031 index = switch_edge(index);
1032 attach_p2(index, nodes_ids);
1033
1034 index = switch_edge(switch_face(index));
1035 attach_p2(index, nodes_ids);
1036 }
1037 // P3
1038 else if (nodes_ids.size() == 20)
1039 {
1040 orders_(c) = 3;
1041
1042 for (int le = 0; le < 3; ++le)
1043 {
1044 attach_p3(index, nodes_ids);
1045 index = next_around_face(index);
1046 }
1047
1048 {
1049 index = switch_vertex(switch_edge(switch_face(index)));
1050 attach_p3(index, nodes_ids);
1051
1052 index = switch_edge(index);
1053 attach_p3(index, nodes_ids);
1054
1055 index = switch_edge(switch_face(index));
1056 attach_p3(index, nodes_ids);
1057 }
1058
1059 {
1060 index = get_index_from_element(c);
1061 std::array<int, 4> indices;
1062
1063 {
1064 std::array<int, 3> f16 = {{nodes_ids[0], nodes_ids[1], nodes_ids[2]}};
1065 std::array<int, 3> f17 = {{nodes_ids[3], nodes_ids[1], nodes_ids[0]}};
1066 std::array<int, 3> f18 = {{nodes_ids[0], nodes_ids[2], nodes_ids[3]}};
1067 std::array<int, 3> f19 = {{nodes_ids[1], nodes_ids[2], nodes_ids[3]}};
1068 std::sort(f16.begin(), f16.end());
1069 std::sort(f17.begin(), f17.end());
1070 std::sort(f18.begin(), f18.end());
1071 std::sort(f19.begin(), f19.end());
1072
1073 auto tmp = index;
1074 std::array<int, 3> f0 = {{face_vertex(tmp.face, 0), face_vertex(tmp.face, 1), face_vertex(tmp.face, 2)}};
1075 tmp = switch_face(index);
1076 std::array<int, 3> f1 = {{face_vertex(tmp.face, 0), face_vertex(tmp.face, 1), face_vertex(tmp.face, 2)}};
1077 tmp = switch_face(next_around_face(index));
1078 std::array<int, 3> f2 = {{face_vertex(tmp.face, 0), face_vertex(tmp.face, 1), face_vertex(tmp.face, 2)}};
1080 std::array<int, 3> f3 = {{face_vertex(tmp.face, 0), face_vertex(tmp.face, 1), face_vertex(tmp.face, 2)}};
1081
1082 std::sort(f0.begin(), f0.end());
1083 std::sort(f1.begin(), f1.end());
1084 std::sort(f2.begin(), f2.end());
1085 std::sort(f3.begin(), f3.end());
1086
1087 const std::array<std::array<int, 3>, 4> faces = {{f0, f1, f2, f3}};
1088 const std::array<std::array<int, 3>, 4> nodes = {{f16, f17, f18, f19}};
1089 for (int i = 0; i < 4; ++i)
1090 {
1091 const auto &f = faces[i];
1092 bool found = false;
1093 for (int j = 0; j < 4; ++j)
1094 {
1095 if (nodes[j] == f)
1096 {
1097 indices[i] = j + 16;
1098 found = true;
1099 break;
1100 }
1101 }
1102
1103 assert(found);
1104 }
1105 }
1106
1107 attach_p3_face(index, nodes_ids, indices[0]);
1108 attach_p3_face(switch_face(index), nodes_ids, indices[1]);
1109 attach_p3_face(switch_face(next_around_face(index)), nodes_ids, indices[2]);
1110 attach_p3_face(switch_face(next_around_face(next_around_face(index))), nodes_ids, indices[3]);
1111 }
1112 }
1113 // P4
1114 else if (nodes_ids.size() == 35)
1115 {
1116 orders_(c) = 4;
1117 for (int le = 0; le < 3; ++le)
1118 {
1119 attach_p4(index, nodes_ids);
1120 index = next_around_face(index);
1121 }
1122
1123 {
1124 index = switch_vertex(switch_edge(switch_face(index)));
1125 attach_p4(index, nodes_ids);
1126
1127 index = switch_edge(index);
1128 attach_p4(index, nodes_ids);
1129
1130 index = switch_edge(switch_face(index));
1131 attach_p4(index, nodes_ids);
1132 }
1133
1134 {
1135 index = get_index_from_element(c);
1136
1137 attach_p4_face(index, nodes_ids);
1138 attach_p4_face(switch_face(index), nodes_ids);
1139 attach_p4_face(switch_face(next_around_face(index)), nodes_ids);
1140 attach_p4_face(switch_face(next_around_face(next_around_face(index))), nodes_ids);
1141 }
1142
1143 attach_p4_cell(get_index_from_element(c), nodes_ids);
1144 }
1145 // unsupported
1146 else
1147 {
1148 assert(false);
1149 }
1150 }
1151 }
1152
1154 {
1155 const auto &V = mesh_.points;
1156 min = V.rowwise().minCoeff().transpose();
1157 max = V.rowwise().maxCoeff().transpose();
1158 }
1159
1161 {
1162 RowVectorNd minV, maxV;
1163 bounding_box(minV, maxV);
1164 auto &V = mesh_.points;
1165 const auto shift = V.rowwise().minCoeff().eval();
1166 const double scaling = 1.0 / (V.rowwise().maxCoeff() - V.rowwise().minCoeff()).maxCoeff();
1167 V = (V.colwise() - shift) * scaling;
1168
1169 for (int i = 0; i < n_cells(); ++i)
1170 {
1171 for (int d = 0; d < 3; ++d)
1172 {
1173 auto val = mesh_.elements[i].v_in_Kernel[d];
1174 mesh_.elements[i].v_in_Kernel[d] = (val - shift(d)) * scaling;
1175 }
1176 }
1177
1178 for (auto &n : edge_nodes_)
1179 {
1180 if (n.nodes.size() > 0)
1181 n.nodes = (n.nodes.rowwise() - shift.transpose()) * scaling;
1182 }
1183 for (auto &n : face_nodes_)
1184 {
1185 if (n.nodes.size() > 0)
1186 n.nodes = (n.nodes.rowwise() - shift.transpose()) * scaling;
1187 }
1188 for (auto &n : cell_nodes_)
1189 {
1190 if (n.nodes.size() > 0)
1191 n.nodes = (n.nodes.rowwise() - shift.transpose()) * scaling;
1192 }
1193
1194 logger().debug("-- bbox before normalization:");
1195 logger().debug(" min : {}", minV);
1196 logger().debug(" max : {}", maxV);
1197 logger().debug(" extent: {}", maxV - minV);
1198 bounding_box(minV, maxV);
1199 logger().debug("-- bbox after normalization:");
1200 logger().debug(" min : {}", minV);
1201 logger().debug(" max : {}", maxV);
1202 logger().debug(" extent: {}", maxV - minV);
1203
1204 // V.row(1) /= 100.;
1205
1206 // for(int i = 0; i < n_cells(); ++i)
1207 // {
1208 // mesh_.elements[i].v_in_Kernel[1] /= 100.;
1209 // }
1210
1211 Eigen::MatrixXd p0, p1, p;
1212 get_edges(p0, p1);
1213 p = p0 - p1;
1214 logger().debug("-- edge length after normalization:");
1215 logger().debug(" min: ", p.rowwise().norm().minCoeff());
1216 logger().debug(" max: ", p.rowwise().norm().maxCoeff());
1217 logger().debug(" avg: ", p.rowwise().norm().mean());
1218 }
1219
1220 // void CMesh3D::triangulate_faces(Eigen::MatrixXi &tris, Eigen::MatrixXd &pts, std::vector<int> &ranges) const
1221 // {
1222 // ranges.clear();
1223
1224 // std::vector<Eigen::MatrixXi> local_tris(mesh_.elements.size());
1225 // std::vector<Eigen::MatrixXd> local_pts(mesh_.elements.size());
1226 // Eigen::MatrixXi tets;
1227
1228 // int total_tris = 0;
1229 // int total_pts = 0;
1230
1231 // ranges.push_back(0);
1232
1233 // Eigen::MatrixXd face_barys;
1234 // face_barycenters(face_barys);
1235
1236 // Eigen::MatrixXd cell_barys;
1237 // cell_barycenters(cell_barys);
1238
1239 // for (std::size_t e = 0; e < mesh_.elements.size(); ++e)
1240 // {
1241 // const Element &el = mesh_.elements[e];
1242
1243 // const int n_vertices = el.vs.size();
1244 // const int n_faces = el.fs.size();
1245
1246 // Eigen::MatrixXd local_pt(n_vertices + n_faces, 3);
1247
1248 // std::map<int, int> global_to_local;
1249
1250 // for (int i = 0; i < n_vertices; ++i)
1251 // {
1252 // const int global_index = el.vs[i];
1253 // local_pt.row(i) = mesh_.points.col(global_index).transpose();
1254 // global_to_local[global_index] = i;
1255 // }
1256
1257 // int n_local_faces = 0;
1258 // for (int i = 0; i < n_faces; ++i)
1259 // {
1260 // const Face &f = mesh_.faces[el.fs[i]];
1261 // n_local_faces += f.vs.size();
1262
1263 // local_pt.row(n_vertices + i) = face_barys.row(f.id); // node_from_face(f.id);
1264 // }
1265
1266 // Eigen::MatrixXi local_faces(n_local_faces, 3);
1267
1268 // int face_index = 0;
1269 // for (int i = 0; i < n_faces; ++i)
1270 // {
1271 // const Face &f = mesh_.faces[el.fs[i]];
1272 // const int n_face_vertices = f.vs.size();
1273
1274 // const Eigen::RowVector3d e0 = (point(f.vs[0]) - local_pt.row(n_vertices + i));
1275 // const Eigen::RowVector3d e1 = (point(f.vs[1]) - local_pt.row(n_vertices + i));
1276 // const Eigen::RowVector3d normal = e0.cross(e1);
1277 // // const Eigen::RowVector3d check_dir = (node_from_element(e)-p);
1278 // const Eigen::RowVector3d check_dir = (cell_barys.row(e) - point(f.vs[1]));
1279
1280 // const bool reverse_order = normal.dot(check_dir) > 0;
1281
1282 // for (int j = 0; j < n_face_vertices; ++j)
1283 // {
1284 // const int jp = (j + 1) % n_face_vertices;
1285 // if (reverse_order)
1286 // {
1287 // local_faces(face_index, 0) = global_to_local[f.vs[jp]];
1288 // local_faces(face_index, 1) = global_to_local[f.vs[j]];
1289 // }
1290 // else
1291 // {
1292 // local_faces(face_index, 0) = global_to_local[f.vs[j]];
1293 // local_faces(face_index, 1) = global_to_local[f.vs[jp]];
1294 // }
1295 // local_faces(face_index, 2) = n_vertices + i;
1296
1297 // ++face_index;
1298 // }
1299 // }
1300
1301 // local_pts[e] = local_pt;
1302 // local_tris[e] = local_faces;
1303
1304 // total_tris += local_tris[e].rows();
1305 // total_pts += local_pts[e].rows();
1306
1307 // ranges.push_back(total_tris);
1308
1309 // assert(local_pts[e].rows() == local_pt.rows());
1310 // }
1311
1312 // tris.resize(total_tris, 3);
1313 // pts.resize(total_pts, 3);
1314
1315 // int tri_index = 0;
1316 // int pts_index = 0;
1317 // for (std::size_t i = 0; i < local_tris.size(); ++i)
1318 // {
1319 // tris.block(tri_index, 0, local_tris[i].rows(), local_tris[i].cols()) = local_tris[i].array() + pts_index;
1320 // tri_index += local_tris[i].rows();
1321
1322 // pts.block(pts_index, 0, local_pts[i].rows(), local_pts[i].cols()) = local_pts[i];
1323 // pts_index += local_pts[i].rows();
1324 // }
1325 // }
1326
1327 bool CMesh3D::is_boundary_element(const int element_global_id) const
1328 {
1329 const auto &fs = mesh_.elements[element_global_id].fs;
1330
1331 for (auto f_id : fs)
1332 {
1333 if (is_boundary_face(f_id))
1334 return true;
1335 }
1336
1337 const auto &vs = mesh_.elements[element_global_id].vs;
1338
1339 for (auto v_id : vs)
1340 {
1341 if (is_boundary_vertex(v_id))
1342 return true;
1343 }
1344
1345 return false;
1346 }
1347
1348 void CMesh3D::compute_boundary_ids(const std::function<int(const size_t, const std::vector<int> &, const RowVectorNd &, bool)> &marker)
1349 {
1350 boundary_ids_.resize(n_faces());
1351
1352 for (int f = 0; f < n_faces(); ++f)
1353 {
1354 const bool is_boundary = is_boundary_face(f);
1355 std::vector<int> vs(n_face_vertices(f));
1356 for (int vid = 0; vid < vs.size(); ++vid)
1357 vs[vid] = face_vertex(f, vid);
1358
1359 const auto p = face_barycenter(f);
1360
1361 std::sort(vs.begin(), vs.end());
1362 boundary_ids_[f] = marker(f, vs, p, is_boundary);
1363 }
1364 }
1365
1366 void CMesh3D::compute_body_ids(const std::function<int(const size_t, const std::vector<int> &, const RowVectorNd &)> &marker)
1367 {
1368 body_ids_.resize(n_elements());
1369 std::fill(body_ids_.begin(), body_ids_.end(), -1);
1370
1371 for (int e = 0; e < n_elements(); ++e)
1372 {
1373 const auto bary = cell_barycenter(e);
1374 body_ids_[e] = marker(e, element_vertices(e), bary);
1375 }
1376 }
1377
1378 void CMesh3D::set_point(const int global_index, const RowVectorNd &p)
1379 {
1380 mesh_.points.col(global_index) = p.transpose();
1381 if (mesh_.vertices[global_index].v.size() == 3)
1382 {
1383 mesh_.vertices[global_index].v[0] = p[0];
1384 mesh_.vertices[global_index].v[1] = p[1];
1385 mesh_.vertices[global_index].v[2] = p[2];
1386 }
1387 }
1388
1389 RowVectorNd CMesh3D::point(const int global_index) const
1390 {
1391 RowVectorNd pt = mesh_.points.col(global_index).transpose();
1392 return pt;
1393 }
1394
1395 RowVectorNd CMesh3D::kernel(const int c) const
1396 {
1397 RowVectorNd pt(3);
1398 pt << mesh_.elements[c].v_in_Kernel[0], mesh_.elements[c].v_in_Kernel[1], mesh_.elements[c].v_in_Kernel[2];
1399 return pt;
1400 }
1401
1403 {
1404 std::vector<ElementType> &ele_tag = elements_tag_;
1405 ele_tag.clear();
1406
1407 ele_tag.resize(mesh_.elements.size());
1408 for (auto &t : ele_tag)
1410
1411 // boundary flags
1412 std::vector<bool> bv_flag(mesh_.vertices.size(), false), be_flag(mesh_.edges.size(), false), bf_flag(mesh_.faces.size(), false);
1413 for (auto f : mesh_.faces)
1414 if (f.boundary)
1415 bf_flag[f.id] = true;
1416 else
1417 {
1418 for (auto nhid : f.neighbor_hs)
1419 if (!mesh_.elements[nhid].hex)
1420 bf_flag[f.id] = true;
1421 }
1422 for (uint32_t i = 0; i < mesh_.faces.size(); ++i)
1423 if (bf_flag[i])
1424 for (uint32_t j = 0; j < mesh_.faces[i].vs.size(); ++j)
1425 {
1426 uint32_t eid = mesh_.faces[i].es[j];
1427 be_flag[eid] = true;
1428 bv_flag[mesh_.faces[i].vs[j]] = true;
1429 }
1430
1431 for (auto &ele : mesh_.elements)
1432 {
1433 if (ele.hex)
1434 {
1435 bool attaching_non_hex = false, on_boundary = false;
1436 ;
1437 for (auto vid : ele.vs)
1438 {
1439 for (auto eleid : mesh_.vertices[vid].neighbor_hs)
1440 if (!mesh_.elements[eleid].hex)
1441 {
1442 attaching_non_hex = true;
1443 break;
1444 }
1445 if (mesh_.vertices[vid].boundary)
1446 {
1447 on_boundary = true;
1448 break;
1449 }
1450 if (on_boundary || attaching_non_hex)
1451 break;
1452 }
1453 if (attaching_non_hex)
1454 {
1455 ele_tag[ele.id] = ElementType::INTERFACE_CUBE;
1456 continue;
1457 }
1458
1459 if (on_boundary)
1460 {
1462 // has no boundary edge--> singular
1463 bool boundary_edge = false, boundary_edge_singular = false, interior_edge_singular = false;
1464 int n_interior_edge_singular = 0;
1465 for (auto eid : ele.es)
1466 {
1467 int en = 0;
1468 if (be_flag[eid])
1469 {
1470 boundary_edge = true;
1471 for (auto nhid : mesh_.edges[eid].neighbor_hs)
1472 if (mesh_.elements[nhid].hex)
1473 en++;
1474 if (en > 2)
1475 boundary_edge_singular = true;
1476 }
1477 else
1478 {
1479 for (auto nhid : mesh_.edges[eid].neighbor_hs)
1480 if (mesh_.elements[nhid].hex)
1481 en++;
1482 if (en != 4)
1483 {
1484 interior_edge_singular = true;
1485 n_interior_edge_singular++;
1486 }
1487 }
1488 }
1489 if (!boundary_edge || boundary_edge_singular || n_interior_edge_singular > 1)
1490 continue;
1491
1492 bool has_singular_v = false, has_iregular_v = false;
1493 int n_in_irregular_v = 0;
1494 for (auto vid : ele.vs)
1495 {
1496 int vn = 0;
1497 if (bv_flag[vid])
1498 {
1499 int nh = 0;
1500 for (auto nhid : mesh_.vertices[vid].neighbor_hs)
1501 if (mesh_.elements[nhid].hex)
1502 nh++;
1503 if (nh > 4)
1504 has_iregular_v = true;
1505 continue; // not sure the conditions
1506 }
1507 else
1508 {
1509 if (mesh_.vertices[vid].neighbor_hs.size() != 8)
1510 n_in_irregular_v++;
1511 int n_irregular_e = 0;
1512 for (auto eid : mesh_.vertices[vid].neighbor_es)
1513 {
1514 if (mesh_.edges[eid].neighbor_hs.size() != 4)
1515 n_irregular_e++;
1516 }
1517 if (n_irregular_e != 0 && n_irregular_e != 2)
1518 {
1519 has_singular_v = true;
1520 break;
1521 }
1522 }
1523 }
1524 int n_irregular_e = 0;
1525 for (auto eid : ele.es)
1526 if (!be_flag[eid] && mesh_.edges[eid].neighbor_hs.size() != 4)
1527 n_irregular_e++;
1528 if (has_singular_v)
1529 continue;
1530 if (!has_singular_v)
1531 {
1532 if (n_irregular_e == 1)
1533 {
1535 }
1536 else if (n_irregular_e == 0 && n_in_irregular_v == 0 && !has_iregular_v)
1537 ele_tag[ele.id] = ElementType::REGULAR_BOUNDARY_CUBE;
1538 else
1539 continue;
1540 }
1541 continue;
1542 }
1543
1544 // type 1
1545 bool has_irregular_v = false;
1546 for (auto vid : ele.vs)
1547 if (mesh_.vertices[vid].neighbor_hs.size() != 8)
1548 {
1549 has_irregular_v = true;
1550 break;
1551 }
1552 if (!has_irregular_v)
1553 {
1554 ele_tag[ele.id] = ElementType::REGULAR_INTERIOR_CUBE;
1555 continue;
1556 }
1557 // type 2
1558 bool has_singular_v = false;
1559 int n_irregular_v = 0;
1560 for (auto vid : ele.vs)
1561 {
1562 if (mesh_.vertices[vid].neighbor_hs.size() != 8)
1563 n_irregular_v++;
1564 int n_irregular_e = 0;
1565 for (auto eid : mesh_.vertices[vid].neighbor_es)
1566 {
1567 if (mesh_.edges[eid].neighbor_hs.size() != 4)
1568 n_irregular_e++;
1569 }
1570 if (n_irregular_e != 0 && n_irregular_e != 2)
1571 {
1572 has_singular_v = true;
1573 break;
1574 }
1575 }
1576 if (!has_singular_v && n_irregular_v == 2)
1577 {
1579 continue;
1580 }
1581
1583 }
1584 else
1585 {
1586 ele_tag[ele.id] = ElementType::INTERIOR_POLYTOPE;
1587 for (auto fid : ele.fs)
1588 if (mesh_.faces[fid].boundary)
1589 {
1590 ele_tag[ele.id] = ElementType::BOUNDARY_POLYTOPE;
1591 break;
1592 }
1593 }
1594 }
1595
1596 // TODO correct?
1597 for (auto &ele : mesh_.elements)
1598 {
1599 if (ele.vs.size() == 4)
1600 ele_tag[ele.id] = ElementType::SIMPLEX;
1601 else if (ele.vs.size() == 5)
1602 ele_tag[ele.id] = ElementType::PYRAMID;
1603 else if (ele.vs.size() == 6)
1604 ele_tag[ele.id] = ElementType::PRISM;
1605 }
1606 }
1607
1608 double CMesh3D::quad_area(const int gid) const
1609 {
1610 const int n_vertices = n_face_vertices(gid);
1611 assert(n_vertices == 4);
1612
1613 const auto &vertices = mesh_.faces[gid].vs;
1614
1615 const auto v1 = point(vertices[0]);
1616 const auto v2 = point(vertices[1]);
1617 const auto v3 = point(vertices[2]);
1618 const auto v4 = point(vertices[3]);
1619
1620 const Eigen::Vector3d e0 = (v2 - v1).transpose();
1621 const Eigen::Vector3d e1 = (v3 - v1).transpose();
1622
1623 const Eigen::Vector3d e2 = (v2 - v4).transpose();
1624 const Eigen::Vector3d e3 = (v3 - v4).transpose();
1625
1626 return e0.cross(e1).norm() / 2 + e2.cross(e3).norm() / 2;
1627 }
1628
1630 {
1631 const int v0 = mesh_.edges[e].vs[0];
1632 const int v1 = mesh_.edges[e].vs[1];
1633 return 0.5 * (point(v0) + point(v1));
1634 }
1635
1637 {
1638 const int n_vertices = n_face_vertices(f);
1639 RowVectorNd bary(3);
1640 bary.setZero();
1641
1642 const auto &vertices = mesh_.faces[f].vs;
1643 for (int lv = 0; lv < n_vertices; ++lv)
1644 {
1645 bary += point(vertices[lv]);
1646 }
1647 return bary / n_vertices;
1648 }
1649
1651 {
1652 const int n_vertices = n_cell_vertices(c);
1653 RowVectorNd bary(3);
1654 bary.setZero();
1655
1656 const auto &vertices = mesh_.elements[c].vs;
1657 for (int lv = 0; lv < n_vertices; ++lv)
1658 {
1659 bary += point(vertices[lv]);
1660 }
1661 return bary / n_vertices;
1662 }
1663
1665 {
1666 m.vertices.clear();
1667 m.edges.clear();
1668 m.faces.clear();
1669 m.vertices.resize(gm.vertices.nb());
1670 m.faces.resize(gm.facets.nb());
1671 for (uint32_t i = 0; i < m.vertices.size(); i++)
1672 {
1673 Vertex v;
1674 v.id = i;
1675 v.v.push_back(gm.vertices.point_ptr(i)[0]);
1676 v.v.push_back(gm.vertices.point_ptr(i)[1]);
1677 v.v.push_back(gm.vertices.point_ptr(i)[2]);
1678 m.vertices[i] = v;
1679 }
1680 m.points.resize(3, m.vertices.size());
1681 for (uint32_t i = 0; i < m.vertices.size(); i++)
1682 {
1683 m.points(0, i) = m.vertices[i].v[0];
1684 m.points(1, i) = m.vertices[i].v[1];
1685 m.points(2, i) = m.vertices[i].v[2];
1686 }
1687
1688 if (m.type == MeshType::TRI || m.type == MeshType::QUA || m.type == MeshType::H_SUR)
1689 {
1690 for (uint32_t i = 0; i < m.faces.size(); i++)
1691 {
1692 Face f;
1693 f.id = i;
1694 f.vs.resize(gm.facets.nb_vertices(i));
1695 for (uint32_t j = 0; j < f.vs.size(); j++)
1696 {
1697 f.vs[j] = gm.facets.vertex(i, j);
1698 }
1699 m.faces[i] = f;
1700 }
1702 }
1703 }
1704
1705 void CMesh3D::elements_boxes(std::vector<std::array<Eigen::Vector3d, 2>> &boxes) const
1706 {
1707 boxes.resize(n_elements());
1708
1709 for (int i = 0; i < n_elements(); ++i)
1710 {
1711 auto &box = boxes[i];
1712 box[0].setConstant(std::numeric_limits<double>::max());
1713 box[1].setConstant(std::numeric_limits<double>::min());
1714
1715 for (int j = 0; j < n_cell_vertices(i); ++j)
1716 {
1717 const int v_id = cell_vertex(i, j);
1718 for (int d = 0; d < 3; ++d)
1719 {
1720 box[0][d] = std::min(box[0][d], point(v_id)[d]);
1721 box[1][d] = std::max(box[1][d], point(v_id)[d]);
1722 }
1723 }
1724 }
1725 }
1726
1727 void CMesh3D::barycentric_coords(const RowVectorNd &p, const int el_id, Eigen::MatrixXd &coord) const
1728 {
1729 assert(is_simplex(el_id));
1730
1731 const auto indices = get_ordered_vertices_from_tet(el_id);
1732
1733 const auto A = point(indices[0]);
1734 const auto B = point(indices[1]);
1735 const auto C = point(indices[2]);
1736 const auto D = point(indices[3]);
1737
1738 igl::barycentric_coordinates(p, A, B, C, D, coord);
1739 }
1740
1741 void CMesh3D::append(const Mesh &mesh)
1742 {
1743 assert(typeid(mesh) == typeid(CMesh3D));
1744 Mesh::append(mesh);
1745
1746 const CMesh3D &mesh3d = dynamic_cast<const CMesh3D &>(mesh);
1747 mesh_.append(mesh3d.mesh_);
1748
1751 }
1752
1753 std::unique_ptr<Mesh> CMesh3D::copy() const
1754 {
1755 return std::make_unique<CMesh3D>(*this);
1756 }
1757
1758 } // namespace mesh
1759} // namespace polyfem
int V
double val
Definition Assembler.cpp:90
Eigen::RowVectorXd point
int y
int z
int x
RowVectorNd cell_barycenter(const int c) const override
cell barycenter
Definition CMesh3D.cpp:1650
RowVectorNd edge_barycenter(const int e) const override
edge barycenter
Definition CMesh3D.cpp:1629
bool save(const std::string &path) const override
Definition CMesh3D.cpp:533
static void geomesh_2_mesh_storage(const GEO::Mesh &gm, Mesh3DStorage &m)
Definition CMesh3D.cpp:1664
RowVectorNd point(const int vertex_id) const override
point coordinates
Definition CMesh3D.cpp:1389
void normalize() override
normalize the mesh
Definition CMesh3D.cpp:1160
int edge_vertex(const int e_id, const int lv_id) const override
id of the edge vertex
Definition CMesh3D.hpp:49
void refine(const int n_refinement, const double t) override
refine the mesh
Definition CMesh3D.cpp:144
int n_edges() const override
number of edges
Definition CMesh3D.hpp:34
int face_vertex(const int f_id, const int lv_id) const override
id of the face vertex
Definition CMesh3D.hpp:48
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 CMesh3D.cpp:1348
RowVectorNd face_barycenter(const int f) const override
face barycenter
Definition CMesh3D.cpp:1636
int n_vertices() const override
number of vertices
Definition CMesh3D.hpp:35
Mesh3DStorage mesh_
Definition CMesh3D.hpp:135
bool is_boundary_face(const int face_global_id) const override
is face boundary
Definition CMesh3D.hpp:56
double quad_area(const int gid) const override
area of a quad face of an hex mesh
Definition CMesh3D.cpp:1608
Navigation3D::Index next_around_face(Navigation3D::Index idx) const override
Definition CMesh3D.hpp:98
bool is_boundary_vertex(const int vertex_global_id) const override
is vertex boundary
Definition CMesh3D.hpp:54
RowVectorNd kernel(const int cell_id) const override
Definition CMesh3D.cpp:1395
void elements_boxes(std::vector< std::array< Eigen::Vector3d, 2 > > &boxes) const override
constructs a box around every element (3d cell, 2d face)
Definition CMesh3D.cpp:1705
void attach_higher_order_nodes(const Eigen::MatrixXd &V, const std::vector< std::vector< int > > &nodes) override
attach high order nodes
Definition CMesh3D.cpp:650
void set_point(const int global_index, const RowVectorNd &p) override
Set the point.
Definition CMesh3D.cpp:1378
void bounding_box(RowVectorNd &min, RowVectorNd &max) const override
computes the bbox of the mesh
Definition CMesh3D.cpp:1153
void append(const Mesh &mesh) override
appends a new mesh to the end of this
Definition CMesh3D.cpp:1741
int n_cells() const override
number of cells
Definition CMesh3D.hpp:32
int n_faces() const override
number of faces
Definition CMesh3D.hpp:33
Navigation3D::Index switch_vertex(Navigation3D::Index idx) const override
Definition CMesh3D.hpp:91
bool load(const std::string &path) override
loads a mesh from the path
Definition CMesh3D.cpp:205
Navigation3D::Index get_index_from_element(int hi, int lf, int lv) const override
Definition CMesh3D.hpp:81
std::unique_ptr< Mesh > copy() const override
Create a copy of the mesh.
Definition CMesh3D.cpp:1753
void remove_elements(const std::vector< bool > &keep) override
Remove all top-dimensional elements whose mask entry is false.
Definition CMesh3D.cpp:20
void compute_elements_tag() override
compute element types, see ElementType
Definition CMesh3D.cpp:1402
Navigation3D::Index switch_edge(Navigation3D::Index idx) const override
Definition CMesh3D.hpp:92
int n_cell_vertices(const int c_id) const override
number of vertices of a cell
Definition CMesh3D.hpp:38
Navigation3D::Index switch_face(Navigation3D::Index idx) const override
Definition CMesh3D.hpp:93
void barycentric_coords(const RowVectorNd &p, const int el_id, Eigen::MatrixXd &coord) const override
constructs barycentric coodiantes for a point p.
Definition CMesh3D.cpp:1727
bool build_from_matrices(const Eigen::MatrixXd &V, const Eigen::MatrixXi &F) override
build a mesh from matrices
Definition CMesh3D.cpp:586
bool is_boundary_element(const int element_global_id) const override
is cell boundary
Definition CMesh3D.cpp:1327
int n_face_vertices(const int f_id) const override
number of vertices of a face
Definition CMesh3D.hpp:37
int cell_vertex(const int c_id, const int lv_id) const override
id of the vertex of a cell
Definition CMesh3D.hpp:41
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 CMesh3D.cpp:1366
void get_edges(Eigen::MatrixXd &p0, Eigen::MatrixXd &p1) const override
Get all the edges.
Definition Mesh3D.cpp:33
virtual std::array< int, 4 > get_ordered_vertices_from_tet(const int element_index) const
Definition Mesh3D.cpp:528
void append(const Mesh3DStorage &other)
std::vector< Element > elements
std::vector< Vertex > vertices
Class to store the high-order edge nodes.
Definition Mesh.hpp:53
Class to store the high-order face nodes.
Definition Mesh.hpp:62
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 has_boundary_ids() const
checks if surface selections are available
Definition Mesh.hpp:561
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 > boundary_ids_
list of surface labels
Definition Mesh.hpp:732
std::vector< CellNodes > cell_nodes_
high-order nodes associates to cells
Definition Mesh.hpp:747
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
const std::vector< ElementType > & elements_tag() const
Returns the elements types.
Definition Mesh.hpp:439
std::vector< EdgeNodes > edge_nodes_
high-order nodes associates to edges
Definition Mesh.hpp:743
std::vector< std::vector< int > > faces() const
list of sorted faces.
Definition Mesh.cpp:538
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 refine_red_refinement_tet(Mesh3DStorage &M, int iter)
void build_connectivity(Mesh3DStorage &hmi)
void refine_catmul_clark_polar(Mesh3DStorage &M, int iter, bool reverse, std::vector< int > &Parents)
void prepare_mesh(Mesh3DStorage &M)
int find(const Eigen::VectorXi &vec, int x)
Definition NCMesh2D.cpp:336
@ REGULAR_INTERIOR_CUBE
Triangle/tet element.
@ REGULAR_BOUNDARY_CUBE
Quad/Hex incident to more than 1 singular vertices (should not happen in 2D)
@ MULTI_SINGULAR_BOUNDARY_CUBE
Quad incident to exactly 1 singular vertex (in 2D); hex incident to exactly 1 singular interior edge,...
@ PRISM
Boundary polytope.
@ MULTI_SINGULAR_INTERIOR_CUBE
Quad/hex incident to exactly 1 singular vertex (in 2D) or edge (in 3D)
@ SIMPLE_SINGULAR_INTERIOR_CUBE
Regular quad/hex inside a 3^n patch.
@ INTERFACE_CUBE
Boundary hex that is not regular nor SimpleSingularBoundaryCube.
@ INTERIOR_POLYTOPE
Quad/hex that is at the interface with a polytope (if a cube has both external boundary and and inter...
@ SIMPLE_SINGULAR_BOUNDARY_CUBE
Boundary quad/hex, where all boundary vertices/edges are incident to at most 2 quads/hexes.
@ BOUNDARY_POLYTOPE
Interior polytope.
void to_geogram_mesh(const Eigen::MatrixXd &V, const Eigen::MatrixXi &F, GEO::Mesh &M)
Converts a triangle mesh to a Geogram mesh.
bool endswith(const std::string &str, const std::string &suffix)
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
void log_and_throw_error(const std::string &msg)
Definition Logger.cpp:73
std::vector< double > v_in_Kernel
std::vector< uint32_t > fs
std::vector< uint32_t > vs
std::vector< uint32_t > input_vs
std::vector< bool > fs_flag
std::vector< uint32_t > vs
std::vector< double > v