PolyFEM
Loading...
Searching...
No Matches
Mesh3D.cpp
Go to the documentation of this file.
4
6
7#include <igl/barycentric_coordinates.h>
8
9#include <geogram/mesh/mesh_io.h>
10#include <fstream>
11
12namespace polyfem
13{
14 using namespace utils;
15
16 namespace mesh
17 {
18 double Mesh3D::tri_area(const int gid) const
19 {
20 const int n_vertices = n_face_vertices(gid);
21 assert(n_vertices == 3);
22
23 const auto v1 = point(face_vertex(gid, 0));
24 const auto v2 = point(face_vertex(gid, 1));
25 const auto v3 = point(face_vertex(gid, 2));
26
27 const Eigen::Vector3d e0 = (v2 - v1).transpose();
28 const Eigen::Vector3d e1 = (v3 - v1).transpose();
29
30 return e0.cross(e1).norm() / 2;
31 }
32
33 void Mesh3D::get_edges(Eigen::MatrixXd &p0, Eigen::MatrixXd &p1) const
34 {
35 p0.resize(n_edges(), 3);
36 p1.resize(p0.rows(), p0.cols());
37
38 for (std::size_t e = 0; e < n_edges(); ++e)
39 {
40 const int v0 = edge_vertex(e, 0);
41 const int v1 = edge_vertex(e, 1);
42
43 p0.row(e) = point(v0);
44 p1.row(e) = point(v1);
45 }
46 }
47
48 void Mesh3D::get_edges(Eigen::MatrixXd &p0, Eigen::MatrixXd &p1, const std::vector<bool> &valid_elements) const
49 {
50 int count = 0;
51 for (size_t i = 0; i < valid_elements.size(); ++i)
52 {
53 if (valid_elements[i])
54 {
55 count += n_cell_edges(i);
56 }
57 }
58
59 p0.resize(count, 3);
60 p1.resize(count, 3);
61
62 count = 0;
63
64 for (size_t i = 0; i < valid_elements.size(); ++i)
65 {
66 if (!valid_elements[i])
67 continue;
68
69 for (size_t ei = 0; ei < n_cell_edges(i); ++ei)
70 {
71 const int e = cell_edge(i, ei);
72 p0.row(count) = point(edge_vertex(e, 0));
73 p1.row(count) = point(edge_vertex(e, 1));
74
75 ++count;
76 }
77 }
78 }
79
80 std::pair<RowVectorNd, int> Mesh3D::edge_node(const Navigation3D::Index &index, const int n_new_nodes, const int i) const
81 {
82 if (orders_.size() <= 0 || orders_(index.element) == 1 || edge_nodes_.empty() || edge_nodes_[index.edge].nodes.rows() != n_new_nodes)
83 {
84 const auto v1 = point(index.vertex);
85 const auto v2 = point(switch_vertex(index).vertex);
86
87 const double t = i / (n_new_nodes + 1.0);
88
89 return std::make_pair((1 - t) * v1 + t * v2, -1);
90 }
91
92 const auto &n = edge_nodes_[index.edge];
93 if (n.v1 == index.vertex)
94 return std::make_pair(n.nodes.row(i - 1), n.nodes_ids[i - 1]);
95 else
96 return std::make_pair(n.nodes.row(n.nodes.rows() - i), n.nodes_ids[n.nodes_ids.size() - i]);
97 }
98
99 std::pair<RowVectorNd, int> Mesh3D::face_node(const Navigation3D::Index &index, const int n_new_nodes, const int n_new_nodesq, const int i, const int j) const
100 {
101 assert(is_prism(index.element));
102
103 const int tmp = n_new_nodes == 2 ? 3 : n_new_nodes; // ?
104
105 const bool is_prism_tri = n_face_vertices(index.face) == 3;
106 const bool is_prism_quad = n_face_vertices(index.face) == 4;
107
108 // for (int i = 0; i < face_nodes_.size(); ++i)
109 // {
110 // std::cout << "face " << i << ": " << face_nodes_[i].nodes.rows() << " nodes" << std::endl;
111 // }
112 if (is_prism_tri)
113 {
114 if (orders_.size() <= 0 || orders_(index.element) == 1 || orders_(index.element) == 2 || face_nodes_.empty() || face_nodes_[index.face].nodes.rows() != tmp)
115 {
116 const auto v1 = point(index.vertex);
117 const auto v2 = point(switch_vertex(index).vertex);
118 const auto v3 = point(switch_vertex(switch_edge(index)).vertex);
119
120 const double b2 = i / (n_new_nodes + 2.0);
121 const double b3 = j / (n_new_nodes + 2.0);
122 const double b1 = 1 - b3 - b2;
123 assert(b3 < 1);
124 assert(b3 > 0);
125
126 return std::make_pair(b1 * v1 + b2 * v2 + b3 * v3, -1);
127 }
128
129 const int ii = i - 1;
130 const int jj = j - 1;
131
132 assert(orders_(index.element) == 3 || orders_(index.element) == 4);
133 const auto &n = face_nodes_[index.face];
134 int lindex = jj * n_new_nodes + ii;
135
136 if (orders_(index.element) == 4) // high order geometric mesh
137 {
138 static const std::array<int, 3> remapping = {{0, 2, 1}};
139 if (n.v1 == index.vertex)
140 {
141 if (n.v2 != next_around_face(index).vertex)
142 {
143 lindex = remapping[lindex];
144 assert(n.v3 == next_around_face(index).vertex);
145 }
146 else
147 {
148 assert(n.v2 == next_around_face(index).vertex);
149 }
150 }
151 else if (n.v2 == index.vertex)
152 {
153
154 if (n.v3 != next_around_face(index).vertex)
155 {
156 lindex = remapping[lindex];
157 assert(n.v1 == next_around_face(index).vertex);
158 }
159 else
160 {
161 assert(n.v3 == switch_vertex(index).vertex);
162 }
163
164 lindex = (lindex + 1) % 3;
165 }
166 else if (n.v3 == index.vertex)
167 {
168
169 if (n.v1 != next_around_face(index).vertex)
170 {
171 lindex = remapping[lindex];
172 assert(n.v2 == next_around_face(index).vertex);
173 }
174 else
175 {
176 assert(n.v1 == switch_vertex(index).vertex);
177 }
178
179 lindex = (lindex + 2) % 3;
180 }
181 else
182 {
183 // assert(false);
184 }
185 }
186
187 return std::make_pair(n.nodes.row(lindex), n.nodes_ids[lindex]);
188 }
189 else if (is_prism_quad)
190 {
191 // supports only blilinear quads
192 assert(orders_.size() <= 0 || orders_(index.element) == 1);
193
194 const int lindex = (j - 1) * n_new_nodes + (i - 1);
195
196 const auto v1 = point(index.vertex);
197 const auto v2 = point(switch_vertex(index).vertex);
198 const auto v3 = point(switch_vertex(switch_edge(switch_vertex(index))).vertex);
199 const auto v4 = point(switch_vertex(switch_edge(index)).vertex);
200
201 if (is_prism_quad)
202 {
203 if (n_face_vertices(switch_face(index).face) == 4)
204 {
205 const double b1 = i / (n_new_nodesq + 1.0);
206 const double b2 = j / (n_new_nodes + 1.0);
207 assert(b1 <= 1);
208 assert(b2 <= 1);
209 assert(b1 >= 0);
210 assert(b2 >= 0);
211 return std::make_pair(v1 * (1 - b1) * (1 - b2) + v2 * b1 * (1 - b2) + v3 * b1 * b2 + v4 * (1 - b1) * b2, -1);
212 }
213 else
214 {
215 const double b1 = i / (n_new_nodes + 1.0);
216 const double b2 = j / (n_new_nodesq + 1.0);
217 assert(b1 <= 1);
218 assert(b2 <= 1);
219 assert(b1 >= 0);
220 assert(b2 >= 0);
221 return std::make_pair(v1 * (1 - b1) * (1 - b2) + v2 * b1 * (1 - b2) + v3 * b1 * b2 + v4 * (1 - b1) * b2, -1);
222 }
223 }
224 const double b1 = i / (n_new_nodes + 1.0);
225 const double b2 = j / (n_new_nodes + 1.0);
226
227 return std::make_pair(v1 * (1 - b1) * (1 - b2) + v2 * b1 * (1 - b2) + v3 * b1 * b2 + v4 * (1 - b1) * b2, -1);
228 }
229
230 assert(false);
231 return std::make_pair(RowVectorNd(3, 1), -1);
232 }
233
234 std::pair<RowVectorNd, int> Mesh3D::face_node(const Navigation3D::Index &index, const int n_new_nodes, const int i, const int j) const
235 {
236 assert(!is_prism(index.element));
237
238 const int tmp = n_new_nodes == 2 ? 3 : n_new_nodes;
239
240 const bool is_pyramid_tri = is_pyramid(index.element) && n_face_vertices(index.face) == 3;
241 const bool is_pyramid_quad = is_pyramid(index.element) && n_face_vertices(index.face) == 4;
242
243 if (is_simplex(index.element) || is_pyramid_tri)
244 {
245 if (orders_.size() <= 0 || orders_(index.element) == 1 || orders_(index.element) == 2 || face_nodes_.empty() || face_nodes_[index.face].nodes.rows() != tmp)
246 {
247 const auto v1 = point(index.vertex);
248 const auto v2 = point(switch_vertex(index).vertex);
249 const auto v3 = point(switch_vertex(switch_edge(index)).vertex);
250
251 const double b2 = i / (n_new_nodes + 2.0);
252 const double b3 = j / (n_new_nodes + 2.0);
253 const double b1 = 1 - b3 - b2;
254 assert(b3 < 1);
255 assert(b3 > 0);
256
257 return std::make_pair(b1 * v1 + b2 * v2 + b3 * v3, -1);
258 }
259
260 const int ii = i - 1;
261 const int jj = j - 1;
262
263 assert(orders_(index.element) == 3 || orders_(index.element) == 4);
264 const auto &n = face_nodes_[index.face];
265 int lindex = jj * n_new_nodes + ii;
266
267 if (orders_(index.element) == 4)
268 {
269 static const std::array<int, 3> remapping = {{0, 2, 1}};
270 if (n.v1 == index.vertex)
271 {
272 if (n.v2 != next_around_face(index).vertex)
273 {
274 lindex = remapping[lindex];
275 assert(n.v3 == next_around_face(index).vertex);
276 }
277 else
278 {
279 assert(n.v2 == next_around_face(index).vertex);
280 }
281 }
282 else if (n.v2 == index.vertex)
283 {
284
285 if (n.v3 != next_around_face(index).vertex)
286 {
287 lindex = remapping[lindex];
288 assert(n.v1 == next_around_face(index).vertex);
289 }
290 else
291 {
292 assert(n.v3 == switch_vertex(index).vertex);
293 }
294
295 lindex = (lindex + 1) % 3;
296 }
297 else if (n.v3 == index.vertex)
298 {
299
300 if (n.v1 != next_around_face(index).vertex)
301 {
302 lindex = remapping[lindex];
303 assert(n.v2 == next_around_face(index).vertex);
304 }
305 else
306 {
307 assert(n.v1 == switch_vertex(index).vertex);
308 }
309
310 lindex = (lindex + 2) % 3;
311 }
312 else
313 {
314 // assert(false);
315 }
316 }
317
318 return std::make_pair(n.nodes.row(lindex), n.nodes_ids[lindex]);
319 }
320 else if (is_cube(index.element) || is_pyramid_quad)
321 {
322 // supports only blilinear quads
323 assert(orders_.size() <= 0 || orders_(index.element) == 1);
324
325 const auto v1 = point(index.vertex);
326 const auto v2 = point(switch_vertex(index).vertex);
327 const auto v3 = point(switch_vertex(switch_edge(switch_vertex(index))).vertex);
328 const auto v4 = point(switch_vertex(switch_edge(index)).vertex);
329
330 const double b1 = i / (n_new_nodes + 1.0);
331 const double b2 = j / (n_new_nodes + 1.0);
332
333 return std::make_pair(v1 * (1 - b1) * (1 - b2) + v2 * b1 * (1 - b2) + v3 * b1 * b2 + v4 * (1 - b1) * b2, -1);
334 }
335
336 assert(false);
337 return std::make_pair(RowVectorNd(3, 1), -1);
338 }
339
340 std::pair<RowVectorNd, int> Mesh3D::cell_node(const Navigation3D::Index &index, const int n_new_nodes, const int i, const int j, const int k) const
341 {
342 if (is_simplex(index.element) && orders_.size() > 0 && orders_(index.element) == n_new_nodes + 3)
343 {
344 assert(n_new_nodes == 1); // test higher than 4 order meshes
345 const auto &n = cell_nodes_[index.element];
346 assert(n.nodes.rows() == 1);
347 return std::make_pair(n.nodes, n.nodes_ids[0]);
348 }
349
350 if (n_new_nodes == 1)
351 return std::make_pair(cell_barycenter(index.element), -1);
352
353 if (is_simplex(index.element))
354 {
355 if (n_new_nodes == 1)
356 return std::make_pair(cell_barycenter(index.element), -1);
357 else
358 {
359 const auto v1 = point(index.vertex);
360 const auto v2 = point(switch_vertex(index).vertex);
361 const auto v3 = point(switch_vertex(switch_edge(switch_vertex(index))).vertex);
362 const auto v4 = point(switch_vertex(switch_edge(switch_face(index))).vertex);
363
364 const double w1 = double(i) / (n_new_nodes + 3);
365 const double w2 = double(j) / (n_new_nodes + 3);
366 const double w3 = double(k) / (n_new_nodes + 3);
367 const double w4 = 1 - w1 - w2 - w3;
368
369 // return v1 * w3
370 // + v2 * w4
371 // + v3 * w1
372 // + v4 * w2;
373
374 return std::make_pair(w4 * v1 + w1 * v2 + w2 * v3 + w3 * v4, -1);
375 }
376 }
377 else if (is_cube(index.element))
378 {
379 // supports only blilinear hexes
380 assert(orders_.size() <= 0 || orders_(index.element) == 1);
381
382 const auto v1 = point(index.vertex);
383 const auto v2 = point(switch_vertex(index).vertex);
384 const auto v3 = point(switch_vertex(switch_edge(switch_vertex(index))).vertex);
385 const auto v4 = point(switch_vertex(switch_edge(index)).vertex);
386
388 const auto v5 = point(index1.vertex);
389 const auto v6 = point(switch_vertex(index1).vertex);
390 const auto v7 = point(switch_vertex(switch_edge(switch_vertex(index1))).vertex);
391 const auto v8 = point(switch_vertex(switch_edge(index1)).vertex);
392
393 const double b1 = i / (n_new_nodes + 1.0);
394 const double b2 = j / (n_new_nodes + 1.0);
395
396 const double b3 = k / (n_new_nodes + 1.0);
397
398 RowVectorNd blin1 = v1 * (1 - b1) * (1 - b2) + v2 * b1 * (1 - b2) + v3 * b1 * b2 + v4 * (1 - b1) * b2;
399 RowVectorNd blin2 = v5 * (1 - b1) * (1 - b2) + v6 * b1 * (1 - b2) + v7 * b1 * b2 + v8 * (1 - b1) * b2;
400
401 return std::make_pair((1 - b3) * blin1 + b3 * blin2, -1);
402 }
403 else if (is_pyramid(index.element))
404 {
405 // n_new_nodes = p-1, k = z-level (1..n-1), i,j = grid indices
406 const double n = n_new_nodes;
407 const double zv = 1.0 - k / n; // z coordinate
408
409 double xv, yv;
410 if (k == 1) // single node at centroid of slice
411 {
412 xv = 0.5 * (1.0 - zv);
413 yv = 0.5 * (1.0 - zv);
414 }
415 else // k×k grid
416 {
417 const double hk = 1.0 / (k + 1);
418 xv = i * hk * (1.0 - zv);
419 yv = j * hk * (1.0 - zv);
420 }
421
422 const auto vids = get_ordered_vertices_from_pyramid(index.element);
423 const auto v0 = point(vids[0]);
424 const auto v1 = point(vids[1]);
425 const auto v2 = point(vids[2]);
426 const auto v3 = point(vids[3]);
427 const auto v4 = point(vids[4]);
428
429 const double x = xv;
430 const double y = yv;
431 const double z = zv;
432 const double one_minus_z = 1.0 - z;
433
434 const double N0 = (one_minus_z * (one_minus_z - x - y) + x * y) / one_minus_z;
435 const double N1 = x * (one_minus_z - y) / one_minus_z;
436 const double N2 = x * y / one_minus_z;
437 const double N3 = y * (one_minus_z - x) / one_minus_z;
438 const double N4 = z;
439
440 const RowVectorNd node = N0 * v0 + N1 * v1 + N2 * v2 + N3 * v3 + N4 * v4;
441
442 return std::make_pair(node, -1);
443 }
444
445 assert(false);
446 return std::make_pair(RowVectorNd(3, 1), -1);
447 }
448
449 void Mesh3D::to_face_functions(std::array<std::function<Navigation3D::Index(Navigation3D::Index)>, 6> &to_face) const
450 {
451 // top
452 to_face[0] = [&](Navigation3D::Index idx) { return switch_face(switch_edge(switch_vertex(switch_edge(switch_face(idx))))); };
453 // bottom
454 to_face[1] = [&](Navigation3D::Index idx) { return idx; };
455
456 // left
457 to_face[2] = [&](Navigation3D::Index idx) { return switch_face(switch_edge(switch_vertex(idx))); };
458 // right
459 to_face[3] = [&](Navigation3D::Index idx) { return switch_face(switch_edge(idx)); };
460
461 // back
462 to_face[4] = [&](Navigation3D::Index idx) { return switch_face(switch_edge(switch_vertex(switch_edge(switch_vertex(idx))))); };
463 // front
464 to_face[5] = [&](Navigation3D::Index idx) { return switch_face(idx); };
465 }
466
467 void Mesh3D::to_vertex_functions(std::array<std::function<Navigation3D::Index(Navigation3D::Index)>, 8> &to_vertex) const
468 {
469 to_vertex[0] = [&](Navigation3D::Index idx) { return idx; };
470 to_vertex[1] = [&](Navigation3D::Index idx) { return switch_vertex(idx); };
471 to_vertex[2] = [&](Navigation3D::Index idx) { return switch_vertex(switch_edge(switch_vertex(idx))); };
472 to_vertex[3] = [&](Navigation3D::Index idx) { return switch_vertex(switch_edge(idx)); };
473
474 to_vertex[4] = [&](Navigation3D::Index idx) { return switch_vertex(switch_edge(switch_face(idx))); };
475 to_vertex[5] = [&](Navigation3D::Index idx) { return switch_vertex(switch_edge(switch_vertex(switch_edge(switch_face(idx))))); };
477 to_vertex[7] = [&](Navigation3D::Index idx) { return switch_vertex(switch_edge(switch_face(switch_vertex(switch_edge(idx))))); };
478 }
479
480 void Mesh3D::to_edge_functions(std::array<std::function<Navigation3D::Index(Navigation3D::Index)>, 12> &to_edge) const
481 {
482 to_edge[0] = [&](Navigation3D::Index idx) { return idx; };
483 to_edge[1] = [&](Navigation3D::Index idx) { return switch_edge(switch_vertex(idx)); };
484 to_edge[2] = [&](Navigation3D::Index idx) { return switch_edge(switch_vertex(switch_edge(switch_vertex(idx)))); };
486
487 to_edge[4] = [&](Navigation3D::Index idx) { return switch_edge(switch_face(idx)); };
488 to_edge[5] = [&](Navigation3D::Index idx) { return switch_edge(switch_face(switch_edge(switch_vertex(idx)))); };
491
492 to_edge[8] = [&](Navigation3D::Index idx) { return switch_edge(switch_vertex(switch_edge(switch_face(idx)))); };
496 }
497
498 // v7────v6
499 // ╱┆ ╱│
500 // v4─┼──v5 │
501 // │v3┄┄┄┼v2
502 // │╱ │╱
503 // v0────v1
504 std::array<int, 8> Mesh3D::get_ordered_vertices_from_hex(const int element_index) const
505 {
506 assert(is_cube(element_index));
507 auto idx = get_index_from_element(element_index);
508 std::array<int, 8> v;
509
510 std::array<std::function<Navigation3D::Index(Navigation3D::Index)>, 8> to_vertex;
511 to_vertex_functions(to_vertex);
512 for (int i = 0; i < 8; ++i)
513 v[i] = to_vertex[i](idx).vertex;
514
515 // for (int lv = 0; lv < 4; ++lv) {
516 // v[lv] = idx.vertex;
517 // idx = next_around_face_of_element(idx);
518 // }
519 // // assert(idx == get_index_from_element(element_index));
520 // idx = switch_face(switch_edge(switch_vertex(switch_edge(switch_face(idx)))));
521 // for (int lv = 0; lv < 4; ++lv) {
522 // v[4+lv] = idx.vertex;
523 // idx = next_around_face_of_element(idx);
524 // }
525 return v;
526 }
527
528 std::array<int, 4> Mesh3D::get_ordered_vertices_from_tet(const int element_index) const
529 {
530 auto idx = get_index_from_element(element_index);
531 std::array<int, 4> v;
532
533 for (int lv = 0; lv < 3; ++lv)
534 {
535 v[lv] = idx.vertex;
536 idx = next_around_face(idx);
537 }
538 // assert(idx == get_index_from_element(element_index));
540 v[3] = idx.vertex;
541
542 return v;
543 }
544
545 // v5
546 // ╱┆ \
547 // v3─┼──v4
548 // │v2 |
549 // │╱ \ │
550 // v0────v1
551 std::array<int, 6> Mesh3D::get_ordered_vertices_from_prism(const int element_index) const
552 {
553 assert(is_prism(element_index));
554 auto idx = get_index_from_element(element_index);
555 std::array<int, 6> v;
556
557 Navigation3D::Index start = idx;
558
559 for (int i = 0; i < 3; ++i)
560 idx = next_around_face(idx);
561
562 if (idx.vertex != start.vertex)
563 start = switch_face(idx);
564
565 for (int i = 0; i < 3; ++i)
566 {
567 v[i] = start.vertex;
568 start = next_around_face(start);
569 }
570 assert(start.vertex == v[0]);
571
573 for (int i = 0; i < 3; ++i)
574 {
575 v[i + 3] = start.vertex;
576 start = next_around_face(start);
577 }
578 assert(start.vertex == v[3]);
579 return v;
580 }
581
582 std::array<int, 5> Mesh3D::get_ordered_vertices_from_pyramid(const int element_index) const
583 {
584 auto idx = get_index_from_element(element_index);
585 std::array<int, 5> v;
586
587 Navigation3D::Index base; // we want to start navigation from base
588 if (n_face_vertices(idx.face) == 4)
589 {
590 base = idx;
591 }
592 else
593 {
594 Navigation3D::Index tmp = idx;
595 bool found = false;
596 for (int k = 0; k < 3; ++k)
597 {
598 auto nb = switch_face(tmp);
599 if (n_face_vertices(nb.face) == 4)
600 {
601 base = nb;
602 found = true;
603 break;
604 }
605 tmp = next_around_face(tmp);
606 }
607 assert(found);
608 }
609
610 idx = base;
611 for (int lv = 0; lv < 4; ++lv)
612 {
613 v[lv] = idx.vertex;
614 idx = next_around_face(idx);
615 }
616 // assert(idx == get_index_from_element(element_index));
618 v[4] = idx.vertex;
619
620 return v;
621 }
622
623 void Mesh3D::elements_boxes(std::vector<std::array<Eigen::Vector3d, 2>> &boxes) const
624 {
625 boxes.resize(n_elements());
626
627 for (int i = 0; i < n_elements(); ++i)
628 {
629 auto &box = boxes[i];
630 box[0].setConstant(std::numeric_limits<double>::max());
631 box[1].setConstant(std::numeric_limits<double>::min());
632
633 for (int j = 0; j < n_cell_vertices(i); ++j)
634 {
635 const int v_id = cell_vertex(i, j);
636 for (int d = 0; d < 3; ++d)
637 {
638 box[0][d] = std::min(box[0][d], point(v_id)[d]);
639 box[1][d] = std::max(box[1][d], point(v_id)[d]);
640 }
641 }
642 }
643 }
644
645 void Mesh3D::barycentric_coords(const RowVectorNd &p, const int el_id, Eigen::MatrixXd &coord) const
646 {
647 assert(is_simplex(el_id));
648
649 const auto indices = get_ordered_vertices_from_tet(el_id);
650
651 const auto A = point(indices[0]);
652 const auto B = point(indices[1]);
653 const auto C = point(indices[2]);
654 const auto D = point(indices[3]);
655
656 igl::barycentric_coordinates(p, A, B, C, D, coord);
657 }
658
659 void Mesh3D::compute_cell_jacobian(const int el_id, const Eigen::MatrixXd &reference_map, Eigen::MatrixXd &jacobian) const
660 {
661 assert(is_simplex(el_id));
662
663 const auto indices = get_ordered_vertices_from_tet(el_id);
664
665 const auto A = point(indices[0]);
666 const auto B = point(indices[1]);
667 const auto C = point(indices[2]);
668 const auto D = point(indices[3]);
669
670 Eigen::MatrixXd coords(4, 4);
671 coords << A, 1, B, 1, C, 1, D, 1;
672 coords.transposeInPlace();
673
674 jacobian = coords * reference_map;
675
676 assert(jacobian.determinant() > 0);
677 }
678
679 } // namespace mesh
680} // namespace polyfem
Eigen::RowVectorXd point
int y
int z
int x
void to_vertex_functions(std::array< std::function< Navigation3D::Index(Navigation3D::Index)>, 8 > &to_vertex) const
Definition Mesh3D.cpp:467
virtual Navigation3D::Index get_index_from_element(int hi, int lf, int lv) const =0
double tri_area(const int gid) const override
area of a tri face of a tet mesh
Definition Mesh3D.cpp:18
void compute_cell_jacobian(const int el_id, const Eigen::MatrixXd &reference_map, Eigen::MatrixXd &jacobian) const
Definition Mesh3D.cpp:659
virtual int n_cell_edges(const int c_id) const =0
virtual int cell_edge(const int c_id, const int le_id) const =0
std::array< int, 5 > get_ordered_vertices_from_pyramid(const int element_index) const
Definition Mesh3D.cpp:582
void elements_boxes(std::vector< std::array< Eigen::Vector3d, 2 > > &boxes) const override
constructs a box around every element (3d cell, 2d face)
Definition Mesh3D.cpp:623
std::array< int, 8 > get_ordered_vertices_from_hex(const int element_index) const
Definition Mesh3D.cpp:504
std::pair< RowVectorNd, int > cell_node(const Navigation3D::Index &index, const int n_new_nodes, const int i, const int j, const int k) const
Definition Mesh3D.cpp:340
void get_edges(Eigen::MatrixXd &p0, Eigen::MatrixXd &p1) const override
Get all the edges.
Definition Mesh3D.cpp:33
virtual Navigation3D::Index switch_edge(Navigation3D::Index idx) const =0
void barycentric_coords(const RowVectorNd &p, const int el_id, Eigen::MatrixXd &coord) const override
constructs barycentric coodiantes for a point p.
Definition Mesh3D.cpp:645
std::pair< RowVectorNd, int > face_node(const Navigation3D::Index &index, const int n_new_nodes, const int i, const int j) const
Definition Mesh3D.cpp:234
std::pair< RowVectorNd, int > edge_node(const Navigation3D::Index &index, const int n_new_nodes, const int i) const
Definition Mesh3D.cpp:80
virtual std::array< int, 4 > get_ordered_vertices_from_tet(const int element_index) const
Definition Mesh3D.cpp:528
void to_edge_functions(std::array< std::function< Navigation3D::Index(Navigation3D::Index)>, 12 > &to_edge) const
Definition Mesh3D.cpp:480
std::array< int, 6 > get_ordered_vertices_from_prism(const int element_index) const
Definition Mesh3D.cpp:551
virtual Navigation3D::Index next_around_face(Navigation3D::Index idx) const =0
virtual Navigation3D::Index switch_face(Navigation3D::Index idx) const =0
void to_face_functions(std::array< std::function< Navigation3D::Index(Navigation3D::Index)>, 6 > &to_face) const
Definition Mesh3D.cpp:449
virtual Navigation3D::Index switch_vertex(Navigation3D::Index idx) const =0
int n_elements() const
utitlity to return the number of elements, cells or faces in 3d and 2d
Definition Mesh.hpp:174
virtual int n_vertices() const =0
number of vertices
Eigen::MatrixXi orders_
list of geometry orders, one per cell
Definition Mesh.hpp:738
bool is_cube(const int el_id) const
checks if element is cube compatible
Definition Mesh.cpp:437
bool is_simplex(const int el_id) const
checks if element is simplex
Definition Mesh.cpp:507
bool is_prism(const int el_id) const
checks if element is a prism
Definition Mesh.cpp:512
std::vector< CellNodes > cell_nodes_
high-order nodes associates to cells
Definition Mesh.hpp:747
virtual int edge_vertex(const int e_id, const int lv_id) const =0
id of the edge vertex
std::vector< FaceNodes > face_nodes_
high-order nodes associates to faces
Definition Mesh.hpp:745
std::vector< EdgeNodes > edge_nodes_
high-order nodes associates to edges
Definition Mesh.hpp:743
bool is_pyramid(const int el_id) const
checks if element is a pyramid
Definition Mesh.cpp:517
virtual RowVectorNd cell_barycenter(const int c) const =0
cell barycenter
virtual int n_edges() const =0
number of edges
virtual int cell_vertex(const int f_id, const int lv_id) const =0
id of the vertex of a cell
virtual int n_face_vertices(const int f_id) const =0
number of vertices of a face
virtual int n_cell_vertices(const int c_id) const =0
number of vertices of a cell
virtual int face_vertex(const int f_id, const int lv_id) const =0
id of the face vertex
Eigen::Matrix< double, 1, Eigen::Dynamic, Eigen::RowMajor, 1, 3 > RowVectorNd
Definition Types.hpp:13