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 for (auto fid : cell.fs)
508 {
509 cell.vs.insert(cell.vs.end(), mesh_.faces[fid].vs.begin(), mesh_.faces[fid].vs.end());
510 }
511 sort(cell.vs.begin(), cell.vs.end());
512 cell.vs.erase(unique(cell.vs.begin(), cell.vs.end()), cell.vs.end());
513
514 // Compute a point in the kernel (assumes the barycenter is ok)
515 Eigen::RowVector3d p(0, 0, 0);
516 for (int v : cell.vs)
517 {
518 p += mesh_.points.col(v).transpose();
519 }
520 p /= cell.vs.size();
521 mesh_.elements[c].v_in_Kernel.push_back(p[0]);
522 mesh_.elements[c].v_in_Kernel.push_back(p[1]);
523 mesh_.elements[c].v_in_Kernel.push_back(p[2]);
524 }
525 mesh_.type = is_hex ? MeshType::HEX : (M.cells.are_simplices() ? MeshType::TET : MeshType::HYB);
526 }
527
529 // if (is_simplicial()) {
530 // MeshProcessing3D::orient_volume_mesh(mesh_);
531 // }
533 return true;
534 }
535
536 bool CMesh3D::save(const std::string &path) const
537 {
538
539 if (!StringUtils::endswith(path, ".HYBRID"))
540 {
541 GEO::Mesh M;
542 to_geogram_mesh(*this, M);
543 GEO::mesh_save(M, path);
544 return true;
545 }
546
547 std::fstream f(path, std::ios::out);
548
549 f << mesh_.points.cols() << " " << mesh_.faces.size() << " " << 3 * mesh_.elements.size() << std::endl;
550 for (int i = 0; i < mesh_.points.cols(); i++)
551 f << mesh_.points(0, i) << " " << mesh_.points(1, i) << " " << mesh_.points(2, i) << std::endl;
552
553 for (auto f_ : mesh_.faces)
554 {
555 f << f_.vs.size() << " ";
556 for (auto vid : f_.vs)
557 f << vid << " ";
558 f << std::endl;
559 }
560
561 for (uint32_t i = 0; i < mesh_.elements.size(); i++)
562 {
563 f << mesh_.elements[i].fs.size() << " ";
564 for (auto fid : mesh_.elements[i].fs)
565 f << fid << " ";
566 f << std::endl;
567 f << mesh_.elements[i].fs_flag.size() << " ";
568 for (auto f_flag : mesh_.elements[i].fs_flag)
569 f << f_flag << " ";
570 f << std::endl;
571 }
572
573 for (uint32_t i = 0; i < mesh_.elements.size(); i++)
574 {
575 f << mesh_.elements[i].hex << std::endl;
576 }
577
578 f << "KERNEL"
579 << " " << mesh_.elements.size() << std::endl;
580 for (uint32_t i = 0; i < mesh_.elements.size(); i++)
581 {
582 f << mesh_.elements[i].v_in_Kernel[0] << " " << mesh_.elements[i].v_in_Kernel[1] << " " << mesh_.elements[i].v_in_Kernel[2] << std::endl;
583 }
584 f.close();
585
586 return true;
587 }
588
589 bool CMesh3D::build_from_matrices(const Eigen::MatrixXd &V, const Eigen::MatrixXi &F)
590 {
591 assert(F.cols() == 4 || F.cols() == 5 || F.cols() == 6 || F.cols() == 8);
592 edge_nodes_.clear();
593 face_nodes_.clear();
594 cell_nodes_.clear();
595
596 GEO::Mesh M;
597 M.vertices.create_vertices((int)V.rows());
598 for (int i = 0; i < (int)M.vertices.nb(); ++i)
599 {
600 GEO::vec3 &p = M.vertices.point(i);
601 p[0] = V(i, 0);
602 p[1] = V(i, 1);
603 p[2] = V(i, 2);
604 }
605
606 static const std::vector<int> permute_tet = {0, 1, 2, 3};
607 static const std::vector<int> permute_pyramid = {0, 1, 2, 3, 4};
608 static const std::vector<int> permute_prism = {0, 1, 2, 3, 4, 5};
609 // polyfem uses the msh file format for hexes ordering!
610 static const std::vector<int> permute_hex = {1, 0, 2, 3, 5, 4, 6, 7};
611
612 auto add_cell = [&](int c, GEO::MeshCellType t, int nv, const std::vector<int> &perm) {
613 GEO::index_t cid = M.cells.create_cells(1, t);
614 for (int lv = 0; lv < nv; ++lv)
615 {
616 int vi = F(c, perm[lv]);
617 assert(vi >= 0 && vi < V.rows());
618 M.cells.set_vertex(cid, lv, GEO::index_t(vi));
619 }
620 };
621
622 for (int c = 0; c < F.rows(); ++c)
623 {
624 int nV;
625 for (nV = 0; nV < F.cols(); ++nV)
626 {
627 if (F(c, nV) == -1)
628 break;
629 }
630
631#ifndef NDEBUG
632 for (int k = nV; k < F.cols(); ++k)
633 {
634 assert(F(c, k) == -1);
635 }
636#endif
637 if (nV == 4)
638 add_cell(c, GEO::MESH_TET, 4, permute_tet);
639 else if (nV == 5)
640 add_cell(c, GEO::MESH_PYRAMID, 5, permute_pyramid);
641 else if (nV == 6)
642 add_cell(c, GEO::MESH_PRISM, 6, permute_prism);
643 else if (nV == 8)
644 add_cell(c, GEO::MESH_HEX, 8, permute_hex);
645 else
646 log_and_throw_error(fmt::format("Invalid number of vertices {}", nV));
647 }
648 M.cells.connect();
649
650 return load(M);
651 }
652
653 void CMesh3D::attach_higher_order_nodes(const Eigen::MatrixXd &V, const std::vector<std::vector<int>> &nodes)
654 {
655 edge_nodes_.clear();
656 face_nodes_.clear();
657 cell_nodes_.clear();
658
659 edge_nodes_.resize(n_edges());
660 face_nodes_.resize(n_faces());
661 cell_nodes_.resize(n_cells());
662
663 orders_.resize(n_cells(), 1);
664
665 const auto attach_p2 = [&](const Navigation3D::Index &index, const std::vector<int> &nodes_ids) {
666 auto &n = edge_nodes_[index.edge];
667
668 if (n.nodes.size() > 0)
669 return;
670
671 n.v1 = index.vertex;
672 n.v2 = switch_vertex(index).vertex;
673
674 const int n_v1 = index.vertex;
675 const int n_v2 = switch_vertex(index).vertex;
676
677 int node_index = 0;
678
679 if ((n_v1 == nodes_ids[0] && n_v2 == nodes_ids[1]) || (n_v2 == nodes_ids[0] && n_v1 == nodes_ids[1]))
680 node_index = 4;
681 else if ((n_v1 == nodes_ids[1] && n_v2 == nodes_ids[2]) || (n_v2 == nodes_ids[1] && n_v1 == nodes_ids[2]))
682 node_index = 5;
683 else if ((n_v1 == nodes_ids[2] && n_v2 == nodes_ids[3]) || (n_v2 == nodes_ids[2] && n_v1 == nodes_ids[3]))
684 node_index = 8;
685
686 else if ((n_v1 == nodes_ids[0] && n_v2 == nodes_ids[3]) || (n_v2 == nodes_ids[0] && n_v1 == nodes_ids[3]))
687 node_index = 7;
688 else if ((n_v1 == nodes_ids[0] && n_v2 == nodes_ids[2]) || (n_v2 == nodes_ids[0] && n_v1 == nodes_ids[2]))
689 node_index = 6;
690 else
691 node_index = 9;
692
693 n.nodes.resize(1, 3);
694 n.nodes << V(nodes_ids[node_index], 0), V(nodes_ids[node_index], 1), V(nodes_ids[node_index], 2);
695 n.nodes_ids.push_back(nodes_ids[node_index]);
696 };
697
698 const auto attach_p3 = [&](const Navigation3D::Index &index, const std::vector<int> &nodes_ids) {
699 auto &n = edge_nodes_[index.edge];
700
701 if (n.nodes.size() > 0)
702 return;
703
704 n.v1 = index.vertex;
705 n.v2 = switch_vertex(index).vertex;
706
707 const int n_v1 = index.vertex;
708 const int n_v2 = switch_vertex(index).vertex;
709
710 int node_index1 = 0;
711 int node_index2 = 0;
712 if (n_v1 == nodes_ids[0] && n_v2 == nodes_ids[1])
713 {
714 node_index1 = 4;
715 node_index2 = 5;
716 }
717 else if (n_v2 == nodes_ids[0] && n_v1 == nodes_ids[1])
718 {
719 node_index1 = 5;
720 node_index2 = 4;
721 }
722 else if (n_v1 == nodes_ids[1] && n_v2 == nodes_ids[2])
723 {
724 node_index1 = 6;
725 node_index2 = 7;
726 }
727 else if (n_v2 == nodes_ids[1] && n_v1 == nodes_ids[2])
728 {
729 node_index1 = 7;
730 node_index2 = 6;
731 }
732 else if (n_v1 == nodes_ids[2] && n_v2 == nodes_ids[3])
733 {
734 node_index1 = 13;
735 node_index2 = 12;
736 }
737 else if (n_v2 == nodes_ids[2] && n_v1 == nodes_ids[3])
738 {
739 node_index1 = 12;
740 node_index2 = 13;
741 }
742
743 else if (n_v1 == nodes_ids[0] && n_v2 == nodes_ids[3])
744 {
745 node_index1 = 11;
746 node_index2 = 10;
747 }
748 else if (n_v2 == nodes_ids[0] && n_v1 == nodes_ids[3])
749 {
750 node_index1 = 10;
751 node_index2 = 11;
752 }
753 else if (n_v1 == nodes_ids[0] && n_v2 == nodes_ids[2])
754 {
755 node_index1 = 9;
756 node_index2 = 8;
757 }
758 else if (n_v2 == nodes_ids[0] && n_v1 == nodes_ids[2])
759 {
760 node_index1 = 8;
761 node_index2 = 9;
762 }
763
764 else if (n_v2 == nodes_ids[1] && n_v1 == nodes_ids[3])
765 {
766 node_index1 = 14;
767 node_index2 = 15;
768 }
769 else
770 {
771 node_index1 = 15;
772 node_index2 = 14;
773 }
774
775 n.nodes.resize(2, 3);
776 n.nodes.row(0) << V(nodes_ids[node_index1], 0), V(nodes_ids[node_index1], 1), V(nodes_ids[node_index1], 2);
777 n.nodes.row(1) << V(nodes_ids[node_index2], 0), V(nodes_ids[node_index2], 1), V(nodes_ids[node_index2], 2);
778 n.nodes_ids.push_back(nodes_ids[node_index1]);
779 n.nodes_ids.push_back(nodes_ids[node_index2]);
780 };
781
782 const auto attach_p3_face = [&](const Navigation3D::Index &index, const std::vector<int> &nodes_ids, int id) {
783 auto &n = face_nodes_[index.face];
784 if (n.nodes.size() <= 0)
785 {
786 n.v1 = face_vertex(index.face, 0);
787 n.v2 = face_vertex(index.face, 1);
788 n.v3 = face_vertex(index.face, 2);
789 n.nodes.resize(1, 3);
790 n.nodes << V(nodes_ids[id], 0), V(nodes_ids[id], 1), V(nodes_ids[id], 2);
791 n.nodes_ids.push_back(nodes_ids[id]);
792 }
793 };
794
795 const auto attach_p4 = [&](const Navigation3D::Index &index, const std::vector<int> &nodes_ids) {
796 auto &n = edge_nodes_[index.edge];
797
798 if (n.nodes.size() > 0)
799 return;
800
801 n.v1 = index.vertex;
802 n.v2 = switch_vertex(index).vertex;
803
804 const int n_v1 = index.vertex;
805 const int n_v2 = switch_vertex(index).vertex;
806
807 int node_index1 = 0;
808 int node_index2 = 0;
809 int node_index3 = 0;
810 if (n_v1 == nodes_ids[0] && n_v2 == nodes_ids[1])
811 {
812 node_index1 = 4;
813 node_index2 = 5;
814 node_index3 = 6;
815 }
816 else if (n_v2 == nodes_ids[0] && n_v1 == nodes_ids[1])
817 {
818 node_index1 = 6;
819 node_index2 = 5;
820 node_index3 = 4;
821 }
822
823 else if (n_v1 == nodes_ids[1] && n_v2 == nodes_ids[2])
824 {
825 node_index1 = 7;
826 node_index2 = 8;
827 node_index3 = 9;
828 }
829 else if (n_v2 == nodes_ids[1] && n_v1 == nodes_ids[2])
830 {
831 node_index1 = 9;
832 node_index2 = 8;
833 node_index3 = 7;
834 }
835
836 else if (n_v2 == nodes_ids[0] && n_v1 == nodes_ids[2])
837 {
838 node_index1 = 10;
839 node_index2 = 11;
840 node_index3 = 12;
841 }
842 else if (n_v1 == nodes_ids[0] && n_v2 == nodes_ids[2])
843 {
844 node_index1 = 12;
845 node_index2 = 11;
846 node_index3 = 10;
847 }
848
849 else if (n_v2 == nodes_ids[0] && n_v1 == nodes_ids[3])
850 {
851 node_index1 = 13;
852 node_index2 = 14;
853 node_index3 = 15;
854 }
855 else if (n_v1 == nodes_ids[0] && n_v2 == nodes_ids[3])
856 {
857 node_index1 = 15;
858 node_index2 = 14;
859 node_index3 = 13;
860 }
861
862 else if (n_v2 == nodes_ids[2] && n_v1 == nodes_ids[3])
863 {
864 node_index1 = 16;
865 node_index2 = 17;
866 node_index3 = 18;
867 }
868 else if (n_v1 == nodes_ids[2] && n_v2 == nodes_ids[3])
869 {
870 node_index1 = 18;
871 node_index2 = 17;
872 node_index3 = 16;
873 }
874
875 else if (n_v2 == nodes_ids[1] && n_v1 == nodes_ids[3])
876 {
877 node_index1 = 19;
878 node_index2 = 20;
879 node_index3 = 21;
880 }
881 else if (n_v1 == nodes_ids[1] && n_v2 == nodes_ids[3])
882 {
883 node_index1 = 21;
884 node_index2 = 20;
885 node_index3 = 19;
886 }
887 else
888 {
889 assert(false);
890 }
891
892 n.nodes.resize(3, 3);
893 n.nodes.row(0) << V(nodes_ids[node_index1], 0), V(nodes_ids[node_index1], 1), V(nodes_ids[node_index1], 2);
894 n.nodes.row(1) << V(nodes_ids[node_index2], 0), V(nodes_ids[node_index2], 1), V(nodes_ids[node_index2], 2);
895 n.nodes.row(2) << V(nodes_ids[node_index3], 0), V(nodes_ids[node_index3], 1), V(nodes_ids[node_index3], 2);
896 n.nodes_ids.push_back(nodes_ids[node_index1]);
897 n.nodes_ids.push_back(nodes_ids[node_index2]);
898 n.nodes_ids.push_back(nodes_ids[node_index3]);
899 };
900
901 const auto attach_p4_face = [&](const Navigation3D::Index &index, const std::vector<int> &nodes_ids) {
902 auto &n = face_nodes_[index.face];
903 if (n.nodes.size() <= 0)
904 {
905 n.v1 = face_vertex(index.face, 0);
906 n.v2 = face_vertex(index.face, 1);
907 n.v3 = face_vertex(index.face, 2);
908
909 std::array<int, 3> vid = {{n.v1, n.v2, n.v3}};
910 std::sort(vid.begin(), vid.end());
911
912 std::array<int, 3> c1 = {{nodes_ids[0], nodes_ids[1], nodes_ids[2]}}; // 22
913 std::array<int, 3> c2 = {{nodes_ids[0], nodes_ids[1], nodes_ids[3]}}; // 25
914 std::array<int, 3> c3 = {{nodes_ids[0], nodes_ids[2], nodes_ids[3]}}; // 28
915 std::array<int, 3> c4 = {{nodes_ids[1], nodes_ids[2], nodes_ids[3]}}; // 31
916
917 std::sort(c1.begin(), c1.end());
918 std::sort(c2.begin(), c2.end());
919 std::sort(c3.begin(), c3.end());
920 std::sort(c4.begin(), c4.end());
921
922 int id = 0;
923 int index0 = 0;
924 int index1 = 1;
925 int index2 = 2;
926 if (vid == c1)
927 {
928 id = 22;
929 n.v1 = nodes_ids[0];
930 n.v2 = nodes_ids[1];
931 n.v3 = nodes_ids[2];
932
933 index0 = 0;
934 index1 = 2;
935 index2 = 1; // ok
936 }
937 else if (vid == c2)
938 {
939 id = 25;
940 n.v1 = nodes_ids[0];
941 n.v2 = nodes_ids[1];
942 n.v3 = nodes_ids[3];
943
944 index0 = 0;
945 index1 = 1;
946 index2 = 2; // ok
947 }
948 else if (vid == c3)
949 {
950 id = 28;
951 n.v1 = nodes_ids[0];
952 n.v2 = nodes_ids[2];
953 n.v3 = nodes_ids[3];
954
955 index0 = 0;
956 index1 = 2;
957 index2 = 1; // ok
958 }
959 else if (vid == c4)
960 {
961 id = 31;
962 n.v1 = nodes_ids[1];
963 n.v2 = nodes_ids[2];
964 n.v3 = nodes_ids[3];
965
966 index0 = 1;
967 index1 = 2;
968 index2 = 0; // ok
969 }
970 else
971 {
972 // the face nees to be one of the 4 above
973 assert(false);
974 }
975
976 n.nodes.resize(3, 3);
977 assert(id + index0 < nodes_ids.size());
978 assert(id + index1 < nodes_ids.size());
979 assert(id + index2 < nodes_ids.size());
980 n.nodes.row(0) << V(nodes_ids[id + index0], 0), V(nodes_ids[id + index0], 1), V(nodes_ids[id + index0], 2);
981 n.nodes.row(1) << V(nodes_ids[id + index1], 0), V(nodes_ids[id + index1], 1), V(nodes_ids[id + index1], 2);
982 n.nodes.row(2) << V(nodes_ids[id + index2], 0), V(nodes_ids[id + index2], 1), V(nodes_ids[id + index2], 2);
983 n.nodes_ids.push_back(nodes_ids[id + index0]);
984 n.nodes_ids.push_back(nodes_ids[id + index1]);
985 n.nodes_ids.push_back(nodes_ids[id + index2]);
986 }
987 };
988
989 const auto attach_p4_cell = [&](const Navigation3D::Index &index, const std::vector<int> &nodes_ids) {
990 auto &n = cell_nodes_[index.element];
991 assert(nodes_ids.size() == 35);
992 assert(n.nodes.size() == 0);
993
994 if (n.nodes.size() <= 0)
995 {
996 n.v1 = cell_vertex(index.element, 0);
997 n.v2 = cell_vertex(index.element, 1);
998 n.v3 = cell_vertex(index.element, 2);
999 n.v4 = cell_vertex(index.element, 3);
1000 n.nodes.resize(1, 3);
1001
1002 n.nodes << V(nodes_ids[34], 0), V(nodes_ids[34], 1), V(nodes_ids[34], 2);
1003 n.nodes_ids.push_back(nodes_ids[34]);
1004 }
1005 };
1006
1007 assert(nodes.size() == n_cells());
1008
1009 for (int c = 0; c < n_cells(); ++c)
1010 {
1011 auto index = get_index_from_element(c);
1012
1013 const auto &nodes_ids = nodes[c];
1014
1015 if (nodes_ids.size() == 4)
1016 {
1017 orders_(c) = 1;
1018 continue;
1019 }
1020 // P2
1021 else if (nodes_ids.size() == 10)
1022 {
1023 orders_(c) = 2;
1024
1025 for (int le = 0; le < 3; ++le)
1026 {
1027 attach_p2(index, nodes_ids);
1028 index = next_around_face(index);
1029 }
1030
1031 index = switch_vertex(switch_edge(switch_face(index)));
1032 attach_p2(index, nodes_ids);
1033
1034 index = switch_edge(index);
1035 attach_p2(index, nodes_ids);
1036
1037 index = switch_edge(switch_face(index));
1038 attach_p2(index, nodes_ids);
1039 }
1040 // P3
1041 else if (nodes_ids.size() == 20)
1042 {
1043 orders_(c) = 3;
1044
1045 for (int le = 0; le < 3; ++le)
1046 {
1047 attach_p3(index, nodes_ids);
1048 index = next_around_face(index);
1049 }
1050
1051 {
1052 index = switch_vertex(switch_edge(switch_face(index)));
1053 attach_p3(index, nodes_ids);
1054
1055 index = switch_edge(index);
1056 attach_p3(index, nodes_ids);
1057
1058 index = switch_edge(switch_face(index));
1059 attach_p3(index, nodes_ids);
1060 }
1061
1062 {
1063 index = get_index_from_element(c);
1064 std::array<int, 4> indices;
1065
1066 {
1067 std::array<int, 3> f16 = {{nodes_ids[0], nodes_ids[1], nodes_ids[2]}};
1068 std::array<int, 3> f17 = {{nodes_ids[3], nodes_ids[1], nodes_ids[0]}};
1069 std::array<int, 3> f18 = {{nodes_ids[0], nodes_ids[2], nodes_ids[3]}};
1070 std::array<int, 3> f19 = {{nodes_ids[1], nodes_ids[2], nodes_ids[3]}};
1071 std::sort(f16.begin(), f16.end());
1072 std::sort(f17.begin(), f17.end());
1073 std::sort(f18.begin(), f18.end());
1074 std::sort(f19.begin(), f19.end());
1075
1076 auto tmp = index;
1077 std::array<int, 3> f0 = {{face_vertex(tmp.face, 0), face_vertex(tmp.face, 1), face_vertex(tmp.face, 2)}};
1078 tmp = switch_face(index);
1079 std::array<int, 3> f1 = {{face_vertex(tmp.face, 0), face_vertex(tmp.face, 1), face_vertex(tmp.face, 2)}};
1080 tmp = switch_face(next_around_face(index));
1081 std::array<int, 3> f2 = {{face_vertex(tmp.face, 0), face_vertex(tmp.face, 1), face_vertex(tmp.face, 2)}};
1083 std::array<int, 3> f3 = {{face_vertex(tmp.face, 0), face_vertex(tmp.face, 1), face_vertex(tmp.face, 2)}};
1084
1085 std::sort(f0.begin(), f0.end());
1086 std::sort(f1.begin(), f1.end());
1087 std::sort(f2.begin(), f2.end());
1088 std::sort(f3.begin(), f3.end());
1089
1090 const std::array<std::array<int, 3>, 4> faces = {{f0, f1, f2, f3}};
1091 const std::array<std::array<int, 3>, 4> nodes = {{f16, f17, f18, f19}};
1092 for (int i = 0; i < 4; ++i)
1093 {
1094 const auto &f = faces[i];
1095 bool found = false;
1096 for (int j = 0; j < 4; ++j)
1097 {
1098 if (nodes[j] == f)
1099 {
1100 indices[i] = j + 16;
1101 found = true;
1102 break;
1103 }
1104 }
1105
1106 assert(found);
1107 }
1108 }
1109
1110 attach_p3_face(index, nodes_ids, indices[0]);
1111 attach_p3_face(switch_face(index), nodes_ids, indices[1]);
1112 attach_p3_face(switch_face(next_around_face(index)), nodes_ids, indices[2]);
1113 attach_p3_face(switch_face(next_around_face(next_around_face(index))), nodes_ids, indices[3]);
1114 }
1115 }
1116 // P4
1117 else if (nodes_ids.size() == 35)
1118 {
1119 orders_(c) = 4;
1120 for (int le = 0; le < 3; ++le)
1121 {
1122 attach_p4(index, nodes_ids);
1123 index = next_around_face(index);
1124 }
1125
1126 {
1127 index = switch_vertex(switch_edge(switch_face(index)));
1128 attach_p4(index, nodes_ids);
1129
1130 index = switch_edge(index);
1131 attach_p4(index, nodes_ids);
1132
1133 index = switch_edge(switch_face(index));
1134 attach_p4(index, nodes_ids);
1135 }
1136
1137 {
1138 index = get_index_from_element(c);
1139
1140 attach_p4_face(index, nodes_ids);
1141 attach_p4_face(switch_face(index), nodes_ids);
1142 attach_p4_face(switch_face(next_around_face(index)), nodes_ids);
1143 attach_p4_face(switch_face(next_around_face(next_around_face(index))), nodes_ids);
1144 }
1145
1146 attach_p4_cell(get_index_from_element(c), nodes_ids);
1147 }
1148 // unsupported
1149 else
1150 {
1151 assert(false);
1152 }
1153 }
1154 }
1155
1157 {
1158 const auto &V = mesh_.points;
1159 min = V.rowwise().minCoeff().transpose();
1160 max = V.rowwise().maxCoeff().transpose();
1161 }
1162
1164 {
1165 RowVectorNd minV, maxV;
1166 bounding_box(minV, maxV);
1167 auto &V = mesh_.points;
1168 const auto shift = V.rowwise().minCoeff().eval();
1169 const double scaling = 1.0 / (V.rowwise().maxCoeff() - V.rowwise().minCoeff()).maxCoeff();
1170 V = (V.colwise() - shift) * scaling;
1171
1172 for (int i = 0; i < n_cells(); ++i)
1173 {
1174 for (int d = 0; d < 3; ++d)
1175 {
1176 auto val = mesh_.elements[i].v_in_Kernel[d];
1177 mesh_.elements[i].v_in_Kernel[d] = (val - shift(d)) * scaling;
1178 }
1179 }
1180
1181 for (auto &n : edge_nodes_)
1182 {
1183 if (n.nodes.size() > 0)
1184 n.nodes = (n.nodes.rowwise() - shift.transpose()) * scaling;
1185 }
1186 for (auto &n : face_nodes_)
1187 {
1188 if (n.nodes.size() > 0)
1189 n.nodes = (n.nodes.rowwise() - shift.transpose()) * scaling;
1190 }
1191 for (auto &n : cell_nodes_)
1192 {
1193 if (n.nodes.size() > 0)
1194 n.nodes = (n.nodes.rowwise() - shift.transpose()) * scaling;
1195 }
1196
1197 logger().debug("-- bbox before normalization:");
1198 logger().debug(" min : {}", minV);
1199 logger().debug(" max : {}", maxV);
1200 logger().debug(" extent: {}", maxV - minV);
1201 bounding_box(minV, maxV);
1202 logger().debug("-- bbox after normalization:");
1203 logger().debug(" min : {}", minV);
1204 logger().debug(" max : {}", maxV);
1205 logger().debug(" extent: {}", maxV - minV);
1206
1207 // V.row(1) /= 100.;
1208
1209 // for(int i = 0; i < n_cells(); ++i)
1210 // {
1211 // mesh_.elements[i].v_in_Kernel[1] /= 100.;
1212 // }
1213
1214 Eigen::MatrixXd p0, p1, p;
1215 get_edges(p0, p1);
1216 p = p0 - p1;
1217 logger().debug("-- edge length after normalization:");
1218 logger().debug(" min: ", p.rowwise().norm().minCoeff());
1219 logger().debug(" max: ", p.rowwise().norm().maxCoeff());
1220 logger().debug(" avg: ", p.rowwise().norm().mean());
1221 }
1222
1223 // void CMesh3D::triangulate_faces(Eigen::MatrixXi &tris, Eigen::MatrixXd &pts, std::vector<int> &ranges) const
1224 // {
1225 // ranges.clear();
1226
1227 // std::vector<Eigen::MatrixXi> local_tris(mesh_.elements.size());
1228 // std::vector<Eigen::MatrixXd> local_pts(mesh_.elements.size());
1229 // Eigen::MatrixXi tets;
1230
1231 // int total_tris = 0;
1232 // int total_pts = 0;
1233
1234 // ranges.push_back(0);
1235
1236 // Eigen::MatrixXd face_barys;
1237 // face_barycenters(face_barys);
1238
1239 // Eigen::MatrixXd cell_barys;
1240 // cell_barycenters(cell_barys);
1241
1242 // for (std::size_t e = 0; e < mesh_.elements.size(); ++e)
1243 // {
1244 // const Element &el = mesh_.elements[e];
1245
1246 // const int n_vertices = el.vs.size();
1247 // const int n_faces = el.fs.size();
1248
1249 // Eigen::MatrixXd local_pt(n_vertices + n_faces, 3);
1250
1251 // std::map<int, int> global_to_local;
1252
1253 // for (int i = 0; i < n_vertices; ++i)
1254 // {
1255 // const int global_index = el.vs[i];
1256 // local_pt.row(i) = mesh_.points.col(global_index).transpose();
1257 // global_to_local[global_index] = i;
1258 // }
1259
1260 // int n_local_faces = 0;
1261 // for (int i = 0; i < n_faces; ++i)
1262 // {
1263 // const Face &f = mesh_.faces[el.fs[i]];
1264 // n_local_faces += f.vs.size();
1265
1266 // local_pt.row(n_vertices + i) = face_barys.row(f.id); // node_from_face(f.id);
1267 // }
1268
1269 // Eigen::MatrixXi local_faces(n_local_faces, 3);
1270
1271 // int face_index = 0;
1272 // for (int i = 0; i < n_faces; ++i)
1273 // {
1274 // const Face &f = mesh_.faces[el.fs[i]];
1275 // const int n_face_vertices = f.vs.size();
1276
1277 // const Eigen::RowVector3d e0 = (point(f.vs[0]) - local_pt.row(n_vertices + i));
1278 // const Eigen::RowVector3d e1 = (point(f.vs[1]) - local_pt.row(n_vertices + i));
1279 // const Eigen::RowVector3d normal = e0.cross(e1);
1280 // // const Eigen::RowVector3d check_dir = (node_from_element(e)-p);
1281 // const Eigen::RowVector3d check_dir = (cell_barys.row(e) - point(f.vs[1]));
1282
1283 // const bool reverse_order = normal.dot(check_dir) > 0;
1284
1285 // for (int j = 0; j < n_face_vertices; ++j)
1286 // {
1287 // const int jp = (j + 1) % n_face_vertices;
1288 // if (reverse_order)
1289 // {
1290 // local_faces(face_index, 0) = global_to_local[f.vs[jp]];
1291 // local_faces(face_index, 1) = global_to_local[f.vs[j]];
1292 // }
1293 // else
1294 // {
1295 // local_faces(face_index, 0) = global_to_local[f.vs[j]];
1296 // local_faces(face_index, 1) = global_to_local[f.vs[jp]];
1297 // }
1298 // local_faces(face_index, 2) = n_vertices + i;
1299
1300 // ++face_index;
1301 // }
1302 // }
1303
1304 // local_pts[e] = local_pt;
1305 // local_tris[e] = local_faces;
1306
1307 // total_tris += local_tris[e].rows();
1308 // total_pts += local_pts[e].rows();
1309
1310 // ranges.push_back(total_tris);
1311
1312 // assert(local_pts[e].rows() == local_pt.rows());
1313 // }
1314
1315 // tris.resize(total_tris, 3);
1316 // pts.resize(total_pts, 3);
1317
1318 // int tri_index = 0;
1319 // int pts_index = 0;
1320 // for (std::size_t i = 0; i < local_tris.size(); ++i)
1321 // {
1322 // tris.block(tri_index, 0, local_tris[i].rows(), local_tris[i].cols()) = local_tris[i].array() + pts_index;
1323 // tri_index += local_tris[i].rows();
1324
1325 // pts.block(pts_index, 0, local_pts[i].rows(), local_pts[i].cols()) = local_pts[i];
1326 // pts_index += local_pts[i].rows();
1327 // }
1328 // }
1329
1330 bool CMesh3D::is_boundary_element(const int element_global_id) const
1331 {
1332 const auto &fs = mesh_.elements[element_global_id].fs;
1333
1334 for (auto f_id : fs)
1335 {
1336 if (is_boundary_face(f_id))
1337 return true;
1338 }
1339
1340 const auto &vs = mesh_.elements[element_global_id].vs;
1341
1342 for (auto v_id : vs)
1343 {
1344 if (is_boundary_vertex(v_id))
1345 return true;
1346 }
1347
1348 return false;
1349 }
1350
1351 void CMesh3D::compute_boundary_ids(const std::function<int(const size_t, const std::vector<int> &, const RowVectorNd &, bool)> &marker)
1352 {
1353 boundary_ids_.resize(n_faces());
1354
1355 for (int f = 0; f < n_faces(); ++f)
1356 {
1357 const bool is_boundary = is_boundary_face(f);
1358 std::vector<int> vs(n_face_vertices(f));
1359 for (int vid = 0; vid < vs.size(); ++vid)
1360 vs[vid] = face_vertex(f, vid);
1361
1362 const auto p = face_barycenter(f);
1363
1364 std::sort(vs.begin(), vs.end());
1365 boundary_ids_[f] = marker(f, vs, p, is_boundary);
1366 }
1367 }
1368
1369 void CMesh3D::compute_body_ids(const std::function<int(const size_t, const std::vector<int> &, const RowVectorNd &)> &marker)
1370 {
1371 body_ids_.resize(n_elements());
1372 std::fill(body_ids_.begin(), body_ids_.end(), -1);
1373
1374 for (int e = 0; e < n_elements(); ++e)
1375 {
1376 const auto bary = cell_barycenter(e);
1377 body_ids_[e] = marker(e, element_vertices(e), bary);
1378 }
1379 }
1380
1381 void CMesh3D::set_point(const int global_index, const RowVectorNd &p)
1382 {
1383 mesh_.points.col(global_index) = p.transpose();
1384 if (mesh_.vertices[global_index].v.size() == 3)
1385 {
1386 mesh_.vertices[global_index].v[0] = p[0];
1387 mesh_.vertices[global_index].v[1] = p[1];
1388 mesh_.vertices[global_index].v[2] = p[2];
1389 }
1390 }
1391
1392 RowVectorNd CMesh3D::point(const int global_index) const
1393 {
1394 RowVectorNd pt = mesh_.points.col(global_index).transpose();
1395 return pt;
1396 }
1397
1398 RowVectorNd CMesh3D::kernel(const int c) const
1399 {
1400 RowVectorNd pt(3);
1401 pt << mesh_.elements[c].v_in_Kernel[0], mesh_.elements[c].v_in_Kernel[1], mesh_.elements[c].v_in_Kernel[2];
1402 return pt;
1403 }
1404
1406 {
1407 std::vector<ElementType> &ele_tag = elements_tag_;
1408 ele_tag.clear();
1409
1410 ele_tag.resize(mesh_.elements.size());
1411 for (auto &t : ele_tag)
1413
1414 // boundary flags
1415 std::vector<bool> bv_flag(mesh_.vertices.size(), false), be_flag(mesh_.edges.size(), false), bf_flag(mesh_.faces.size(), false);
1416 for (auto f : mesh_.faces)
1417 if (f.boundary)
1418 bf_flag[f.id] = true;
1419 else
1420 {
1421 for (auto nhid : f.neighbor_hs)
1422 if (!mesh_.elements[nhid].hex)
1423 bf_flag[f.id] = true;
1424 }
1425 for (uint32_t i = 0; i < mesh_.faces.size(); ++i)
1426 if (bf_flag[i])
1427 for (uint32_t j = 0; j < mesh_.faces[i].vs.size(); ++j)
1428 {
1429 uint32_t eid = mesh_.faces[i].es[j];
1430 be_flag[eid] = true;
1431 bv_flag[mesh_.faces[i].vs[j]] = true;
1432 }
1433
1434 for (auto &ele : mesh_.elements)
1435 {
1436 if (ele.hex)
1437 {
1438 bool attaching_non_hex = false, on_boundary = false;
1439 ;
1440 for (auto vid : ele.vs)
1441 {
1442 for (auto eleid : mesh_.vertices[vid].neighbor_hs)
1443 if (!mesh_.elements[eleid].hex)
1444 {
1445 attaching_non_hex = true;
1446 break;
1447 }
1448 if (mesh_.vertices[vid].boundary)
1449 {
1450 on_boundary = true;
1451 break;
1452 }
1453 if (on_boundary || attaching_non_hex)
1454 break;
1455 }
1456 if (attaching_non_hex)
1457 {
1458 ele_tag[ele.id] = ElementType::INTERFACE_CUBE;
1459 continue;
1460 }
1461
1462 if (on_boundary)
1463 {
1465 // has no boundary edge--> singular
1466 bool boundary_edge = false, boundary_edge_singular = false, interior_edge_singular = false;
1467 int n_interior_edge_singular = 0;
1468 for (auto eid : ele.es)
1469 {
1470 int en = 0;
1471 if (be_flag[eid])
1472 {
1473 boundary_edge = true;
1474 for (auto nhid : mesh_.edges[eid].neighbor_hs)
1475 if (mesh_.elements[nhid].hex)
1476 en++;
1477 if (en > 2)
1478 boundary_edge_singular = true;
1479 }
1480 else
1481 {
1482 for (auto nhid : mesh_.edges[eid].neighbor_hs)
1483 if (mesh_.elements[nhid].hex)
1484 en++;
1485 if (en != 4)
1486 {
1487 interior_edge_singular = true;
1488 n_interior_edge_singular++;
1489 }
1490 }
1491 }
1492 if (!boundary_edge || boundary_edge_singular || n_interior_edge_singular > 1)
1493 continue;
1494
1495 bool has_singular_v = false, has_iregular_v = false;
1496 int n_in_irregular_v = 0;
1497 for (auto vid : ele.vs)
1498 {
1499 int vn = 0;
1500 if (bv_flag[vid])
1501 {
1502 int nh = 0;
1503 for (auto nhid : mesh_.vertices[vid].neighbor_hs)
1504 if (mesh_.elements[nhid].hex)
1505 nh++;
1506 if (nh > 4)
1507 has_iregular_v = true;
1508 continue; // not sure the conditions
1509 }
1510 else
1511 {
1512 if (mesh_.vertices[vid].neighbor_hs.size() != 8)
1513 n_in_irregular_v++;
1514 int n_irregular_e = 0;
1515 for (auto eid : mesh_.vertices[vid].neighbor_es)
1516 {
1517 if (mesh_.edges[eid].neighbor_hs.size() != 4)
1518 n_irregular_e++;
1519 }
1520 if (n_irregular_e != 0 && n_irregular_e != 2)
1521 {
1522 has_singular_v = true;
1523 break;
1524 }
1525 }
1526 }
1527 int n_irregular_e = 0;
1528 for (auto eid : ele.es)
1529 if (!be_flag[eid] && mesh_.edges[eid].neighbor_hs.size() != 4)
1530 n_irregular_e++;
1531 if (has_singular_v)
1532 continue;
1533 if (!has_singular_v)
1534 {
1535 if (n_irregular_e == 1)
1536 {
1538 }
1539 else if (n_irregular_e == 0 && n_in_irregular_v == 0 && !has_iregular_v)
1540 ele_tag[ele.id] = ElementType::REGULAR_BOUNDARY_CUBE;
1541 else
1542 continue;
1543 }
1544 continue;
1545 }
1546
1547 // type 1
1548 bool has_irregular_v = false;
1549 for (auto vid : ele.vs)
1550 if (mesh_.vertices[vid].neighbor_hs.size() != 8)
1551 {
1552 has_irregular_v = true;
1553 break;
1554 }
1555 if (!has_irregular_v)
1556 {
1557 ele_tag[ele.id] = ElementType::REGULAR_INTERIOR_CUBE;
1558 continue;
1559 }
1560 // type 2
1561 bool has_singular_v = false;
1562 int n_irregular_v = 0;
1563 for (auto vid : ele.vs)
1564 {
1565 if (mesh_.vertices[vid].neighbor_hs.size() != 8)
1566 n_irregular_v++;
1567 int n_irregular_e = 0;
1568 for (auto eid : mesh_.vertices[vid].neighbor_es)
1569 {
1570 if (mesh_.edges[eid].neighbor_hs.size() != 4)
1571 n_irregular_e++;
1572 }
1573 if (n_irregular_e != 0 && n_irregular_e != 2)
1574 {
1575 has_singular_v = true;
1576 break;
1577 }
1578 }
1579 if (!has_singular_v && n_irregular_v == 2)
1580 {
1582 continue;
1583 }
1584
1586 }
1587 else
1588 {
1589 ele_tag[ele.id] = ElementType::INTERIOR_POLYTOPE;
1590 for (auto fid : ele.fs)
1591 if (mesh_.faces[fid].boundary)
1592 {
1593 ele_tag[ele.id] = ElementType::BOUNDARY_POLYTOPE;
1594 break;
1595 }
1596 }
1597 }
1598
1599 // TODO correct?
1600 for (auto &ele : mesh_.elements)
1601 {
1602 if (ele.vs.size() == 4)
1603 ele_tag[ele.id] = ElementType::SIMPLEX;
1604 else if (ele.vs.size() == 5)
1605 ele_tag[ele.id] = ElementType::PYRAMID;
1606 else if (ele.vs.size() == 6)
1607 ele_tag[ele.id] = ElementType::PRISM;
1608 }
1609 }
1610
1611 double CMesh3D::quad_area(const int gid) const
1612 {
1613 const int n_vertices = n_face_vertices(gid);
1614 assert(n_vertices == 4);
1615
1616 const auto &vertices = mesh_.faces[gid].vs;
1617
1618 const auto v1 = point(vertices[0]);
1619 const auto v2 = point(vertices[1]);
1620 const auto v3 = point(vertices[2]);
1621 const auto v4 = point(vertices[3]);
1622
1623 const Eigen::Vector3d e0 = (v2 - v1).transpose();
1624 const Eigen::Vector3d e1 = (v3 - v1).transpose();
1625
1626 const Eigen::Vector3d e2 = (v2 - v4).transpose();
1627 const Eigen::Vector3d e3 = (v3 - v4).transpose();
1628
1629 return e0.cross(e1).norm() / 2 + e2.cross(e3).norm() / 2;
1630 }
1631
1633 {
1634 const int v0 = mesh_.edges[e].vs[0];
1635 const int v1 = mesh_.edges[e].vs[1];
1636 return 0.5 * (point(v0) + point(v1));
1637 }
1638
1640 {
1641 const int n_vertices = n_face_vertices(f);
1642 RowVectorNd bary(3);
1643 bary.setZero();
1644
1645 const auto &vertices = mesh_.faces[f].vs;
1646 for (int lv = 0; lv < n_vertices; ++lv)
1647 {
1648 bary += point(vertices[lv]);
1649 }
1650 return bary / n_vertices;
1651 }
1652
1654 {
1655 const int n_vertices = n_cell_vertices(c);
1656 RowVectorNd bary(3);
1657 bary.setZero();
1658
1659 const auto &vertices = mesh_.elements[c].vs;
1660 for (int lv = 0; lv < n_vertices; ++lv)
1661 {
1662 bary += point(vertices[lv]);
1663 }
1664 return bary / n_vertices;
1665 }
1666
1668 {
1669 m.vertices.clear();
1670 m.edges.clear();
1671 m.faces.clear();
1672 m.vertices.resize(gm.vertices.nb());
1673 m.faces.resize(gm.facets.nb());
1674 for (uint32_t i = 0; i < m.vertices.size(); i++)
1675 {
1676 Vertex v;
1677 v.id = i;
1678 v.v.push_back(gm.vertices.point_ptr(i)[0]);
1679 v.v.push_back(gm.vertices.point_ptr(i)[1]);
1680 v.v.push_back(gm.vertices.point_ptr(i)[2]);
1681 m.vertices[i] = v;
1682 }
1683 m.points.resize(3, m.vertices.size());
1684 for (uint32_t i = 0; i < m.vertices.size(); i++)
1685 {
1686 m.points(0, i) = m.vertices[i].v[0];
1687 m.points(1, i) = m.vertices[i].v[1];
1688 m.points(2, i) = m.vertices[i].v[2];
1689 }
1690
1691 if (m.type == MeshType::TRI || m.type == MeshType::QUA || m.type == MeshType::H_SUR)
1692 {
1693 for (uint32_t i = 0; i < m.faces.size(); i++)
1694 {
1695 Face f;
1696 f.id = i;
1697 f.vs.resize(gm.facets.nb_vertices(i));
1698 for (uint32_t j = 0; j < f.vs.size(); j++)
1699 {
1700 f.vs[j] = gm.facets.vertex(i, j);
1701 }
1702 m.faces[i] = f;
1703 }
1705 }
1706 }
1707
1708 void CMesh3D::elements_boxes(std::vector<std::array<Eigen::Vector3d, 2>> &boxes) const
1709 {
1710 boxes.resize(n_elements());
1711
1712 for (int i = 0; i < n_elements(); ++i)
1713 {
1714 auto &box = boxes[i];
1715 box[0].setConstant(std::numeric_limits<double>::max());
1716 box[1].setConstant(std::numeric_limits<double>::min());
1717
1718 for (int j = 0; j < n_cell_vertices(i); ++j)
1719 {
1720 const int v_id = cell_vertex(i, j);
1721 for (int d = 0; d < 3; ++d)
1722 {
1723 box[0][d] = std::min(box[0][d], point(v_id)[d]);
1724 box[1][d] = std::max(box[1][d], point(v_id)[d]);
1725 }
1726 }
1727 }
1728 }
1729
1730 void CMesh3D::barycentric_coords(const RowVectorNd &p, const int el_id, Eigen::MatrixXd &coord) const
1731 {
1732 assert(is_simplex(el_id));
1733
1734 const auto indices = get_ordered_vertices_from_tet(el_id);
1735
1736 const auto A = point(indices[0]);
1737 const auto B = point(indices[1]);
1738 const auto C = point(indices[2]);
1739 const auto D = point(indices[3]);
1740
1741 igl::barycentric_coordinates(p, A, B, C, D, coord);
1742 }
1743
1744 void CMesh3D::append(const Mesh &mesh)
1745 {
1746 assert(typeid(mesh) == typeid(CMesh3D));
1747 Mesh::append(mesh);
1748
1749 const CMesh3D &mesh3d = dynamic_cast<const CMesh3D &>(mesh);
1750 mesh_.append(mesh3d.mesh_);
1751
1754 }
1755
1756 std::unique_ptr<Mesh> CMesh3D::copy() const
1757 {
1758 return std::make_unique<CMesh3D>(*this);
1759 }
1760
1761 } // namespace mesh
1762} // namespace polyfem
int V
double val
Definition Assembler.cpp:89
Eigen::RowVectorXd point
int y
int z
int x
RowVectorNd cell_barycenter(const int c) const override
cell barycenter
Definition CMesh3D.cpp:1653
RowVectorNd edge_barycenter(const int e) const override
edge barycenter
Definition CMesh3D.cpp:1632
bool save(const std::string &path) const override
Definition CMesh3D.cpp:536
static void geomesh_2_mesh_storage(const GEO::Mesh &gm, Mesh3DStorage &m)
Definition CMesh3D.cpp:1667
RowVectorNd point(const int vertex_id) const override
point coordinates
Definition CMesh3D.cpp:1392
void normalize() override
normalize the mesh
Definition CMesh3D.cpp:1163
int edge_vertex(const int e_id, const int lv_id) const override
id of the edge vertex
Definition CMesh3D.hpp:45
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:44
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:1351
RowVectorNd face_barycenter(const int f) const override
face barycenter
Definition CMesh3D.cpp:1639
int n_vertices() const override
number of vertices
Definition CMesh3D.hpp:35
Mesh3DStorage mesh_
Definition CMesh3D.hpp:131
bool is_boundary_face(const int face_global_id) const override
is face boundary
Definition CMesh3D.hpp:52
double quad_area(const int gid) const override
area of a quad face of an hex mesh
Definition CMesh3D.cpp:1611
Navigation3D::Index next_around_face(Navigation3D::Index idx) const override
Definition CMesh3D.hpp:94
bool is_boundary_vertex(const int vertex_global_id) const override
is vertex boundary
Definition CMesh3D.hpp:50
RowVectorNd kernel(const int cell_id) const override
Definition CMesh3D.cpp:1398
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:1708
void attach_higher_order_nodes(const Eigen::MatrixXd &V, const std::vector< std::vector< int > > &nodes) override
attach high order nodes
Definition CMesh3D.cpp:653
void set_point(const int global_index, const RowVectorNd &p) override
Set the point.
Definition CMesh3D.cpp:1381
void bounding_box(RowVectorNd &min, RowVectorNd &max) const override
computes the bbox of the mesh
Definition CMesh3D.cpp:1156
void append(const Mesh &mesh) override
appends a new mesh to the end of this
Definition CMesh3D.cpp:1744
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:87
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:77
std::unique_ptr< Mesh > copy() const override
Create a copy of the mesh.
Definition CMesh3D.cpp:1756
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:1405
Navigation3D::Index switch_edge(Navigation3D::Index idx) const override
Definition CMesh3D.hpp:88
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:89
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:1730
bool build_from_matrices(const Eigen::MatrixXd &V, const Eigen::MatrixXi &F) override
build a mesh from matrices
Definition CMesh3D.cpp:589
bool is_boundary_element(const int element_global_id) const override
is cell boundary
Definition CMesh3D.cpp:1330
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:1369
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< bool > fs_flag
std::vector< uint32_t > vs
std::vector< double > v