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