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 i, const int j) const
100 {
101 const int tmp = n_new_nodes == 2 ? 3 : n_new_nodes;
102
103 const bool is_prism_tri = is_prism(index.element) && n_face_vertices(index.face) == 3;
104 const bool is_prism_quad = is_prism(index.element) && n_face_vertices(index.face) == 4;
105
106 if (is_simplex(index.element) || is_prism_tri)
107 {
108 if (orders_.size() <= 0 || orders_(index.element) == 1 || orders_(index.element) == 2 || face_nodes_.empty() || face_nodes_[index.face].nodes.rows() != tmp)
109 {
110 const auto v1 = point(index.vertex);
111 const auto v2 = point(switch_vertex(index).vertex);
112 const auto v3 = point(switch_vertex(switch_edge(index)).vertex);
113
114 const double b2 = i / (n_new_nodes + 2.0);
115 const double b3 = j / (n_new_nodes + 2.0);
116 const double b1 = 1 - b3 - b2;
117 assert(b3 < 1);
118 assert(b3 > 0);
119
120 return std::make_pair(b1 * v1 + b2 * v2 + b3 * v3, -1);
121 }
122
123 const int ii = i - 1;
124 const int jj = j - 1;
125
126 assert(orders_(index.element) == 3 || orders_(index.element) == 4);
127 const auto &n = face_nodes_[index.face];
128 int lindex = jj * n_new_nodes + ii;
129
130 if (orders_(index.element) == 4)
131 {
132 static const std::array<int, 3> remapping = {{0, 2, 1}};
133 if (n.v1 == index.vertex)
134 {
135 if (n.v2 != next_around_face(index).vertex)
136 {
137 lindex = remapping[lindex];
138 assert(n.v3 == next_around_face(index).vertex);
139 }
140 else
141 {
142 assert(n.v2 == next_around_face(index).vertex);
143 }
144 }
145 else if (n.v2 == index.vertex)
146 {
147
148 if (n.v3 != next_around_face(index).vertex)
149 {
150 lindex = remapping[lindex];
151 assert(n.v1 == next_around_face(index).vertex);
152 }
153 else
154 {
155 assert(n.v3 == switch_vertex(index).vertex);
156 }
157
158 lindex = (lindex + 1) % 3;
159 }
160 else if (n.v3 == index.vertex)
161 {
162
163 if (n.v1 != next_around_face(index).vertex)
164 {
165 lindex = remapping[lindex];
166 assert(n.v2 == next_around_face(index).vertex);
167 }
168 else
169 {
170 assert(n.v1 == switch_vertex(index).vertex);
171 }
172
173 lindex = (lindex + 2) % 3;
174 }
175 else
176 {
177 // assert(false);
178 }
179 }
180
181 return std::make_pair(n.nodes.row(lindex), n.nodes_ids[lindex]);
182 }
183 else if (is_cube(index.element) || is_prism_quad)
184 {
185 // supports only blilinear quads
186 assert(orders_.size() <= 0 || orders_(index.element) == 1);
187
188 const auto v1 = point(index.vertex);
189 const auto v2 = point(switch_vertex(index).vertex);
190 const auto v3 = point(switch_vertex(switch_edge(switch_vertex(index))).vertex);
191 const auto v4 = point(switch_vertex(switch_edge(index)).vertex);
192
193 const double b1 = i / (n_new_nodes + 1.0);
194 const double b2 = j / (n_new_nodes + 1.0);
195
196 return std::make_pair(v1 * (1 - b1) * (1 - b2) + v2 * b1 * (1 - b2) + v3 * b1 * b2 + v4 * (1 - b1) * b2, -1);
197 }
198
199 assert(false);
200 return std::make_pair(RowVectorNd(3, 1), -1);
201 }
202
203 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
204 {
205 if (is_simplex(index.element) && orders_.size() > 0 && orders_(index.element) == n_new_nodes + 3)
206 {
207 assert(n_new_nodes == 1); // test higher than 4 order meshes
208 const auto &n = cell_nodes_[index.element];
209 assert(n.nodes.rows() == 1);
210 return std::make_pair(n.nodes, n.nodes_ids[0]);
211 }
212
213 if (n_new_nodes == 1)
214 return std::make_pair(cell_barycenter(index.element), -1);
215
216 if (is_simplex(index.element))
217 {
218 if (n_new_nodes == 1)
219 return std::make_pair(cell_barycenter(index.element), -1);
220 else
221 {
222 const auto v1 = point(index.vertex);
223 const auto v2 = point(switch_vertex(index).vertex);
224 const auto v3 = point(switch_vertex(switch_edge(switch_vertex(index))).vertex);
225 const auto v4 = point(switch_vertex(switch_edge(switch_face(index))).vertex);
226
227 const double w1 = double(i) / (n_new_nodes + 3);
228 const double w2 = double(j) / (n_new_nodes + 3);
229 const double w3 = double(k) / (n_new_nodes + 3);
230 const double w4 = 1 - w1 - w2 - w3;
231
232 // return v1 * w3
233 // + v2 * w4
234 // + v3 * w1
235 // + v4 * w2;
236
237 return std::make_pair(w4 * v1 + w1 * v2 + w2 * v3 + w3 * v4, -1);
238 }
239 }
240 else if (is_cube(index.element))
241 {
242 // supports only blilinear hexes
243 assert(orders_.size() <= 0 || orders_(index.element) == 1);
244
245 const auto v1 = point(index.vertex);
246 const auto v2 = point(switch_vertex(index).vertex);
247 const auto v3 = point(switch_vertex(switch_edge(switch_vertex(index))).vertex);
248 const auto v4 = point(switch_vertex(switch_edge(index)).vertex);
249
251 const auto v5 = point(index1.vertex);
252 const auto v6 = point(switch_vertex(index1).vertex);
253 const auto v7 = point(switch_vertex(switch_edge(switch_vertex(index1))).vertex);
254 const auto v8 = point(switch_vertex(switch_edge(index1)).vertex);
255
256 const double b1 = i / (n_new_nodes + 1.0);
257 const double b2 = j / (n_new_nodes + 1.0);
258
259 const double b3 = k / (n_new_nodes + 1.0);
260
261 RowVectorNd blin1 = v1 * (1 - b1) * (1 - b2) + v2 * b1 * (1 - b2) + v3 * b1 * b2 + v4 * (1 - b1) * b2;
262 RowVectorNd blin2 = v5 * (1 - b1) * (1 - b2) + v6 * b1 * (1 - b2) + v7 * b1 * b2 + v8 * (1 - b1) * b2;
263
264 return std::make_pair((1 - b3) * blin1 + b3 * blin2, -1);
265 }
266
267 assert(false);
268 return std::make_pair(RowVectorNd(3, 1), -1);
269 }
270
271 void Mesh3D::to_face_functions(std::array<std::function<Navigation3D::Index(Navigation3D::Index)>, 6> &to_face) const
272 {
273 // top
274 to_face[0] = [&](Navigation3D::Index idx) { return switch_face(switch_edge(switch_vertex(switch_edge(switch_face(idx))))); };
275 // bottom
276 to_face[1] = [&](Navigation3D::Index idx) { return idx; };
277
278 // left
279 to_face[2] = [&](Navigation3D::Index idx) { return switch_face(switch_edge(switch_vertex(idx))); };
280 // right
281 to_face[3] = [&](Navigation3D::Index idx) { return switch_face(switch_edge(idx)); };
282
283 // back
284 to_face[4] = [&](Navigation3D::Index idx) { return switch_face(switch_edge(switch_vertex(switch_edge(switch_vertex(idx))))); };
285 // front
286 to_face[5] = [&](Navigation3D::Index idx) { return switch_face(idx); };
287 }
288
289 void Mesh3D::to_vertex_functions(std::array<std::function<Navigation3D::Index(Navigation3D::Index)>, 8> &to_vertex) const
290 {
291 to_vertex[0] = [&](Navigation3D::Index idx) { return idx; };
292 to_vertex[1] = [&](Navigation3D::Index idx) { return switch_vertex(idx); };
293 to_vertex[2] = [&](Navigation3D::Index idx) { return switch_vertex(switch_edge(switch_vertex(idx))); };
294 to_vertex[3] = [&](Navigation3D::Index idx) { return switch_vertex(switch_edge(idx)); };
295
296 to_vertex[4] = [&](Navigation3D::Index idx) { return switch_vertex(switch_edge(switch_face(idx))); };
297 to_vertex[5] = [&](Navigation3D::Index idx) { return switch_vertex(switch_edge(switch_vertex(switch_edge(switch_face(idx))))); };
299 to_vertex[7] = [&](Navigation3D::Index idx) { return switch_vertex(switch_edge(switch_face(switch_vertex(switch_edge(idx))))); };
300 }
301
302 void Mesh3D::to_edge_functions(std::array<std::function<Navigation3D::Index(Navigation3D::Index)>, 12> &to_edge) const
303 {
304 to_edge[0] = [&](Navigation3D::Index idx) { return idx; };
305 to_edge[1] = [&](Navigation3D::Index idx) { return switch_edge(switch_vertex(idx)); };
306 to_edge[2] = [&](Navigation3D::Index idx) { return switch_edge(switch_vertex(switch_edge(switch_vertex(idx)))); };
308
309 to_edge[4] = [&](Navigation3D::Index idx) { return switch_edge(switch_face(idx)); };
310 to_edge[5] = [&](Navigation3D::Index idx) { return switch_edge(switch_face(switch_edge(switch_vertex(idx)))); };
313
314 to_edge[8] = [&](Navigation3D::Index idx) { return switch_edge(switch_vertex(switch_edge(switch_face(idx)))); };
318 }
319
320 // v7────v6
321 // ╱┆ ╱│
322 // v4─┼──v5 │
323 // │v3┄┄┄┼v2
324 // │╱ │╱
325 // v0────v1
326 std::array<int, 8> Mesh3D::get_ordered_vertices_from_hex(const int element_index) const
327 {
328 assert(is_cube(element_index));
329 auto idx = get_index_from_element(element_index);
330 std::array<int, 8> v;
331
332 std::array<std::function<Navigation3D::Index(Navigation3D::Index)>, 8> to_vertex;
333 to_vertex_functions(to_vertex);
334 for (int i = 0; i < 8; ++i)
335 v[i] = to_vertex[i](idx).vertex;
336
337 // for (int lv = 0; lv < 4; ++lv) {
338 // v[lv] = idx.vertex;
339 // idx = next_around_face_of_element(idx);
340 // }
341 // // assert(idx == get_index_from_element(element_index));
342 // idx = switch_face(switch_edge(switch_vertex(switch_edge(switch_face(idx)))));
343 // for (int lv = 0; lv < 4; ++lv) {
344 // v[4+lv] = idx.vertex;
345 // idx = next_around_face_of_element(idx);
346 // }
347 return v;
348 }
349
350 std::array<int, 4> Mesh3D::get_ordered_vertices_from_tet(const int element_index) const
351 {
352 auto idx = get_index_from_element(element_index);
353 std::array<int, 4> v;
354
355 for (int lv = 0; lv < 3; ++lv)
356 {
357 v[lv] = idx.vertex;
358 idx = next_around_face(idx);
359 }
360 // assert(idx == get_index_from_element(element_index));
362 v[3] = idx.vertex;
363
364 return v;
365 }
366
367 // v5
368 // ╱┆ \
369 // v3─┼──v4
370 // │v2 |
371 // │╱ \ │
372 // v0────v1
373 std::array<int, 6> Mesh3D::get_ordered_vertices_from_prism(const int element_index) const
374 {
375 assert(is_prism(element_index));
376 auto idx = get_index_from_element(element_index);
377 std::array<int, 6> v;
378
379 Navigation3D::Index start = idx;
380
381 for (int i = 0; i < 3; ++i)
382 idx = next_around_face(idx);
383
384 if (idx.vertex != start.vertex)
385 start = switch_face(idx);
386
387 for (int i = 0; i < 3; ++i)
388 {
389 v[i] = start.vertex;
390 start = next_around_face(start);
391 }
392 assert(start.vertex == v[0]);
393
395 for (int i = 0; i < 3; ++i)
396 {
397 v[i + 3] = start.vertex;
398 start = next_around_face(start);
399 }
400 assert(start.vertex == v[3]);
401 return v;
402 }
403
404 void Mesh3D::elements_boxes(std::vector<std::array<Eigen::Vector3d, 2>> &boxes) const
405 {
406 boxes.resize(n_elements());
407
408 for (int i = 0; i < n_elements(); ++i)
409 {
410 auto &box = boxes[i];
411 box[0].setConstant(std::numeric_limits<double>::max());
412 box[1].setConstant(std::numeric_limits<double>::min());
413
414 for (int j = 0; j < n_cell_vertices(i); ++j)
415 {
416 const int v_id = cell_vertex(i, j);
417 for (int d = 0; d < 3; ++d)
418 {
419 box[0][d] = std::min(box[0][d], point(v_id)[d]);
420 box[1][d] = std::max(box[1][d], point(v_id)[d]);
421 }
422 }
423 }
424 }
425
426 void Mesh3D::barycentric_coords(const RowVectorNd &p, const int el_id, Eigen::MatrixXd &coord) const
427 {
428 assert(is_simplex(el_id));
429
430 const auto indices = get_ordered_vertices_from_tet(el_id);
431
432 const auto A = point(indices[0]);
433 const auto B = point(indices[1]);
434 const auto C = point(indices[2]);
435 const auto D = point(indices[3]);
436
437 igl::barycentric_coordinates(p, A, B, C, D, coord);
438 }
439
440 void Mesh3D::compute_cell_jacobian(const int el_id, const Eigen::MatrixXd &reference_map, Eigen::MatrixXd &jacobian) const
441 {
442 assert(is_simplex(el_id));
443
444 const auto indices = get_ordered_vertices_from_tet(el_id);
445
446 const auto A = point(indices[0]);
447 const auto B = point(indices[1]);
448 const auto C = point(indices[2]);
449 const auto D = point(indices[3]);
450
451 Eigen::MatrixXd coords(4, 4);
452 coords << A, 1, B, 1, C, 1, D, 1;
453 coords.transposeInPlace();
454
455 jacobian = coords * reference_map;
456
457 assert(jacobian.determinant() > 0);
458 }
459
460 } // namespace mesh
461} // namespace polyfem
void to_vertex_functions(std::array< std::function< Navigation3D::Index(Navigation3D::Index)>, 8 > &to_vertex) const
Definition Mesh3D.cpp:289
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:440
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
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:404
std::array< int, 8 > get_ordered_vertices_from_hex(const int element_index) const
Definition Mesh3D.cpp:326
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:203
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:426
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:99
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:350
void to_edge_functions(std::array< std::function< Navigation3D::Index(Navigation3D::Index)>, 12 > &to_edge) const
Definition Mesh3D.cpp:302
std::array< int, 6 > get_ordered_vertices_from_prism(const int element_index) const
Definition Mesh3D.cpp:373
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:271
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:162
virtual int n_vertices() const =0
number of vertices
Eigen::MatrixXi orders_
list of geometry orders, one per cell
Definition Mesh.hpp:684
bool is_cube(const int el_id) const
checks if element is cube compatible
Definition Mesh.cpp:352
virtual RowVectorNd point(const int global_index) const =0
point coordinates
bool is_simplex(const int el_id) const
checks if element is simplex
Definition Mesh.cpp:422
bool is_prism(const int el_id) const
checks if element is a prism
Definition Mesh.cpp:427
std::vector< CellNodes > cell_nodes_
high-order nodes associates to cells
Definition Mesh.hpp:693
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:691
std::vector< EdgeNodes > edge_nodes_
high-order nodes associates to edges
Definition Mesh.hpp:689
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