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