PolyFEM
Loading...
Searching...
No Matches
NCMesh2D.cpp
Go to the documentation of this file.
2
4
5#include <igl/writeOBJ.h>
6
8
9namespace polyfem
10{
11 namespace mesh
12 {
13 void NCMesh2D::remove_elements(const std::vector<bool> &keep)
14 {
15 assert(keep.size() == n_faces());
16
17 std::vector<int> old_node_ids(vertices.size(), -1);
18 if (has_node_ids())
19 for (int v = 0; v < n_vertices(); ++v)
20 old_node_ids[valid_to_all_vertex(v)] = node_ids_[v];
21 std::vector<int> old_boundary_ids(edges.size(), -1);
22 if (has_boundary_ids())
23 for (int e = 0; e < n_edges(); ++e)
24 old_boundary_ids[valid_to_all_edge(e)] = boundary_ids_[e];
25
26 for (int e = 0; e < keep.size(); ++e)
27 {
28 if (keep[e])
29 continue;
30 const int full_id = valid_to_all_elem(e);
31 auto &element = elements[full_id];
32 element.is_ghost = true;
33 for (const int edge : element.edges)
34 edges[edge].remove_element(full_id);
35 for (const int vertex : element.vertices)
36 --vertices[vertex].n_elem;
37 --n_elements;
38 }
41
42 if (has_node_ids())
43 {
44 node_ids_.resize(n_vertices());
45 for (int v = 0; v < n_vertices(); ++v)
46 node_ids_[v] = old_node_ids[valid_to_all_vertex(v)];
47 }
48 if (has_boundary_ids())
49 {
50 boundary_ids_.resize(n_edges());
51 for (int e = 0; e < n_edges(); ++e)
52 {
53 const int old_id = old_boundary_ids[valid_to_all_edge(e)];
54 boundary_ids_[e] = old_id < 0 ? get_default_boundary_id(e) : old_id;
55 edges[valid_to_all_edge(e)].boundary_id = boundary_ids_[e];
56 }
57 }
58 }
59
60 bool NCMesh2D::is_boundary_element(const int element_global_id) const
61 {
62 assert(index_prepared);
63 for (int le = 0; le < n_face_vertices(element_global_id); le++)
64 if (is_boundary_edge(face_edge(element_global_id, le)))
65 return true;
66
67 return false;
68 }
69
70 void NCMesh2D::refine(const int n_refinement, const double t)
71 {
72 if (n_refinement <= 0)
73 return;
75 std::vector<bool> refine_mask(elements.size(), false);
76 for (int i = 0; i < elements.size(); i++)
77 if (elements[i].is_valid())
78 refine_mask[i] = true;
79
80 for (int i = 0; i < refine_mask.size(); i++)
81 if (refine_mask[i])
83
84 refine(n_refinement - 1, t);
85 }
86
88 {
89 const Eigen::MatrixXd &V = data.vertices;
90 const Eigen::MatrixXi &F = data.elements;
91 if (F.cols() != 3 || F.minCoeff() < 0)
92 return false;
93 GEO::Mesh mesh_;
94 mesh_.clear(false, false);
95 to_geogram_mesh(V, F, mesh_);
96 orient_normals_2d(mesh_);
97
98 n_elements = 0;
99 elements.clear();
100 vertices.clear();
101 edges.clear();
102 midpointMap.clear();
103 edgeMap.clear();
104 refineHistory.clear();
105 index_prepared = false;
106 adj_prepared = false;
107
108 vertices.reserve(V.rows());
109 for (int i = 0; i < V.rows(); i++)
110 {
111 vertices.emplace_back(V.row(i));
112 }
113 for (int i = 0; i < F.rows(); i++)
114 {
115 add_element(F.row(i), -1);
116 }
117
118 prepare_mesh();
119
120 return true;
121 }
122
123 void NCMesh2D::attach_higher_order_nodes(const Eigen::MatrixXd &V, const std::vector<std::vector<int>> &nodes)
124 {
125 for (int f = 0; f < n_faces(); ++f)
126 if (nodes[f].size() != 3)
127 throw std::runtime_error("NCMesh doesn't support high order mesh!");
128 }
129 std::pair<RowVectorNd, int> NCMesh2D::edge_node(const Navigation::Index &index, const int n_new_nodes, const int i) const
130 {
131 const auto v1 = point(index.vertex);
132 const auto v2 = point(switch_vertex(index).vertex);
133
134 const double t = i / (n_new_nodes + 1.0);
135
136 return std::make_pair((1 - t) * v1 + t * v2, -1);
137 }
138 std::pair<RowVectorNd, int> NCMesh2D::face_node(const Navigation::Index &index, const int n_new_nodes, const int i, const int j) const
139 {
140 const auto v1 = point(index.vertex);
141 const auto v2 = point(switch_vertex(index).vertex);
142 const auto v3 = point(switch_vertex(switch_edge(index)).vertex);
143
144 const double b2 = i / (n_new_nodes + 2.0);
145 const double b3 = j / (n_new_nodes + 2.0);
146 const double b1 = 1 - b3 - b2;
147 assert(b3 < 1);
148 assert(b3 > 0);
149
150 return std::make_pair(b1 * v1 + b2 * v2 + b3 * v3, -1);
151 }
152
153 int NCMesh2D::find_vertex(Eigen::Vector2i v) const
154 {
155 std::sort(v.data(), v.data() + v.size());
156 auto search = midpointMap.find(v);
157 if (search != midpointMap.end())
158 return search->second;
159 else
160 return -1;
161 }
162
163 int NCMesh2D::get_vertex(Eigen::Vector2i v)
164 {
165 std::sort(v.data(), v.data() + v.size());
166 int id = find_vertex(v);
167 if (id < 0)
168 {
169 Eigen::VectorXd v_mid = (vertices[v[0]].pos + vertices[v[1]].pos) / 2.;
170 id = vertices.size();
171 vertices.emplace_back(v_mid);
172 midpointMap.emplace(v, id);
173 }
174 return id;
175 }
176
177 int NCMesh2D::find_edge(Eigen::Vector2i v) const
178 {
179 std::sort(v.data(), v.data() + v.size());
180 auto search = edgeMap.find(v);
181 if (search != edgeMap.end())
182 return search->second;
183 else
184 return -1;
185 }
186
187 int NCMesh2D::get_edge(Eigen::Vector2i v)
188 {
189 std::sort(v.data(), v.data() + v.size());
190 int id = find_edge(v);
191 if (id < 0)
192 {
193 edges.emplace_back(v);
194 id = edges.size() - 1;
195 edgeMap.emplace(v, id);
196 }
197 return id;
198 }
199
200 int NCMesh2D::add_element(Eigen::Vector3i v, int parent)
201 {
202 const int id = elements.size();
203 const int level = (parent < 0) ? 0 : elements[parent].level + 1;
204 elements.emplace_back(2, v, level, parent);
205
206 if (parent >= 0)
207 elements[id].body_id = elements[parent].body_id;
208
209 for (int i = 0; i < v.size(); i++)
210 vertices[v(i)].n_elem++;
211
212 // add edges if not exist
213 int edge01 = get_edge(Eigen::Vector2i(v[0], v[1]));
214 int edge12 = get_edge(Eigen::Vector2i(v[2], v[1]));
215 int edge20 = get_edge(Eigen::Vector2i(v[0], v[2]));
216
217 elements[id].edges << edge01, edge12, edge20;
218
219 edges[edge01].add_element(id);
220 edges[edge12].add_element(id);
221 edges[edge20].add_element(id);
222
223 n_elements++;
224 index_prepared = false;
225 adj_prepared = false;
226
227 return id;
228 }
229
230 void NCMesh2D::refine_element(int id_full)
231 {
232 auto &elem = elements[id_full];
233 if (elem.is_not_valid())
234 throw std::runtime_error("Cannot refine an invalid element!");
235
236 const auto v = elem.vertices;
237 elem.is_refined = true;
238 n_elements--;
239
240 // remove the old element from edge reference
241 for (int e = 0; e < 3; e++)
242 edges[elem.edges(e)].remove_element(id_full);
243
244 for (int i = 0; i < v.size(); i++)
245 vertices[v(i)].n_elem--;
246
247 if (elem.children(0) >= 0)
248 {
249 for (int c = 0; c < elem.children.size(); c++)
250 {
251 auto &child = elements[elem.children(c)];
252 child.is_ghost = false;
253 n_elements++;
254 for (int le = 0; le < child.edges.size(); le++)
255 edges[child.edges(le)].add_element(child.children(c));
256 for (int i = 0; i < child.vertices.size(); i++)
257 vertices[child.vertices(i)].n_elem++;
258 }
259 }
260 else
261 {
262 // create mid-points if not exist
263 const int v01 = get_vertex(Eigen::Vector2i(v[0], v[1]));
264 const int v12 = get_vertex(Eigen::Vector2i(v[2], v[1]));
265 const int v20 = get_vertex(Eigen::Vector2i(v[0], v[2]));
266
267 // inherite line singularity flag from parent edge
268 for (int i = 0; i < v.size(); i++)
269 for (int j = 0; j < i; j++)
270 {
271 int mid_id = find_vertex(v[i], v[j]);
272 int edge_id = find_edge(v[i], v[j]);
273 int edge1 = get_edge(v[i], mid_id);
274 int edge2 = get_edge(v[j], mid_id);
275 edges[edge1].boundary_id = edges[edge_id].boundary_id;
276 edges[edge2].boundary_id = edges[edge_id].boundary_id;
277 }
278
279 // create and insert child elements
280 elements[id_full].children(0) = elements.size();
281 add_element(Eigen::Vector3i(v[0], v01, v20), id_full);
282 elements[id_full].children(1) = elements.size();
283 add_element(Eigen::Vector3i(v[1], v12, v01), id_full);
284 elements[id_full].children(2) = elements.size();
285 add_element(Eigen::Vector3i(v[2], v20, v12), id_full);
286 elements[id_full].children(3) = elements.size();
287 add_element(Eigen::Vector3i(v12, v20, v01), id_full);
288 }
289
290 refineHistory.push_back(id_full);
291
292 index_prepared = false;
293 adj_prepared = false;
294 }
295
296 void NCMesh2D::refine_elements(const std::vector<int> &ids)
297 {
298 std::vector<int> full_ids(ids.size());
299 for (int i = 0; i < ids.size(); i++)
300 full_ids[i] = valid_to_all_elem(ids[i]);
301
302 for (int i : full_ids)
304 }
305
307 {
308 const int parent_id = elements[id_full].parent;
309 auto &parent = elements[parent_id];
310
311 for (int i = 0; i < parent.children.size(); i++)
312 if (elements[parent.children(i)].is_not_valid())
313 throw std::runtime_error("Coarsen operation invalid!");
314
315 // remove elements
316 for (int i = 0; i < parent.children.size(); i++)
317 {
318 auto &elem = elements[parent.children(i)];
319 elem.is_ghost = true;
320 n_elements--;
321 for (int le = 0; le < elem.edges.size(); le++)
322 edges[elem.edges(le)].remove_element(parent.children(i));
323 for (int v = 0; v < elem.vertices.size(); v++)
324 vertices[elem.vertices(v)].n_elem--;
325 }
326
327 // add element
328 parent.is_refined = false;
329 n_elements++;
330 for (int le = 0; le < parent.edges.size(); le++)
331 edges[parent.edges(le)].add_element(parent_id);
332 for (int v = 0; v < parent.vertices.size(); v++)
333 vertices[parent.vertices(v)].n_elem++;
334
335 refineHistory.push_back(parent_id);
336
337 index_prepared = false;
338 adj_prepared = false;
339 }
340
341 int find(const Eigen::VectorXi &vec, int x)
342 {
343 for (int i = 0; i < vec.size(); i++)
344 {
345 if (x == vec[i])
346 return i;
347 }
348 return -1;
349 }
350
352 {
353 for (auto &edge : edges)
354 {
355 edge.leader = -1;
356 edge.followers.clear();
357 edge.weights.setConstant(-1);
358 }
359
360 Eigen::Vector2i v;
361 std::vector<follower_edge> followers;
362 for (int e_id = 0; e_id < elements.size(); e_id++)
363 {
364 const auto &element = elements[e_id];
365 if (element.is_not_valid())
366 continue;
367 for (int edge_local = 0; edge_local < 3; edge_local++)
368 {
369 v << element.vertices[edge_local], element.vertices[(edge_local + 1) % 3]; // order is important here!
370 int edge_global = element.edges[edge_local];
371 assert(edge_global >= 0);
372 traverse_edge(v, 0, 1, 0, followers);
373 for (auto &s : followers)
374 {
375 edges[s.id].leader = edge_global;
376 edges[edge_global].followers.push_back(s.id);
377 edges[s.id].weights << s.p1, s.p2;
378 }
379 followers.clear();
380 }
381 }
382 }
383
385 {
386 for (auto &edge : edges)
387 {
388 if (edge.n_elem() == 1)
389 edge.isboundary = true;
390 else
391 edge.isboundary = false;
392 }
393
394 for (auto &edge : edges)
395 {
396 if (edge.leader >= 0 && edge.n_elem() > 0 && edges[edge.leader].n_elem() > 0)
397 {
398 edge.isboundary = false;
399 edges[edge.leader].isboundary = false;
400 }
401 }
402
403 for (auto &vert : vertices)
404 vert.isboundary = false;
405
406 for (auto &edge : edges)
407 {
408 if (edge.isboundary && edge.n_elem())
409 {
410 for (int j = 0; j < 2; j++)
411 vertices[edge.vertices(j)].isboundary = true;
412 }
413 }
414 }
415
416 double line_weight(Eigen::Matrix<double, 2, 2> &e, Eigen::VectorXd &v)
417 {
418 assert(v.size() == 2);
419 double w1 = (v(0) - e(0, 0)) / (e(1, 0) - e(0, 0));
420 double w2 = (v(1) - e(0, 1)) / (e(1, 1) - e(0, 1));
421 if (0 <= w1 && w1 <= 1)
422 return w1;
423 else
424 return w2;
425 }
426
428 {
429 for (auto &vert : vertices)
430 {
431 vert.edge = -1;
432 vert.weight = -1;
433 }
434
435 Eigen::VectorXi vertexEdgeAdjacency;
436 vertexEdgeAdjacency.setConstant(vertices.size(), 1, -1);
437
438 for (int small_edge = 0; small_edge < edges.size(); small_edge++)
439 {
440 if (edges[small_edge].n_elem() == 0)
441 continue;
442
443 int large_edge = edges[small_edge].leader;
444 if (large_edge < 0)
445 continue;
446
447 int large_elem = edges[large_edge].get_element();
448 for (int j = 0; j < 2; j++)
449 {
450 int v_id = edges[small_edge].vertices(j);
451 if (find(elements[large_elem].vertices, v_id) < 0) // or maybe 0 < weights(large_edge, v_id) < 1
452 vertexEdgeAdjacency[v_id] = large_edge;
453 }
454 }
455
456 for (auto &element : elements)
457 {
458 if (element.is_not_valid())
459 continue;
460 for (int v_local = 0; v_local < 3; v_local++)
461 {
462 int v_global = element.vertices[v_local];
463 if (vertexEdgeAdjacency[v_global] < 0)
464 continue;
465
466 auto &large_edge = edges[vertexEdgeAdjacency[v_global]];
467 auto &large_element = elements[large_edge.get_element()];
468 vertices[v_global].edge = vertexEdgeAdjacency[v_global];
469
470 int e_local = find(large_element.edges, vertices[v_global].edge);
471 Eigen::Matrix<double, 2, 2> edge;
472 edge.row(0) = vertices[large_element.vertices[e_local]].pos;
473 edge.row(1) = vertices[large_element.vertices[(e_local + 1) % 3]].pos;
474 vertices[v_global].weight = line_weight(edge, vertices[v_global].pos);
475 }
476 }
477 }
478
479 double NCMesh2D::element_weight_to_edge_weight(const int l, const Eigen::Vector2d &pos)
480 {
481 double w = -1;
482 switch (l)
483 {
484 case 0:
485 w = pos(0);
486 assert(fabs(pos(1)) < 1e-12);
487 break;
488 case 1:
489 w = pos(1);
490 assert(fabs(pos(0) + pos(1) - 1) < 1e-12);
491 break;
492 case 2:
493 w = 1 - pos(1);
494 assert(fabs(pos(0)) < 1e-12);
495 break;
496 default:
497 assert(false);
498 }
499 return w;
500 }
501
503 {
504 all_to_valid_elemMap.assign(elements.size(), -1);
506
507 for (int i = 0, e = 0; i < elements.size(); i++)
508 {
509 if (elements[i].is_not_valid())
510 continue;
513 e++;
514 }
515
516 const int n_verts = n_vertices();
517
518 all_to_valid_vertexMap.assign(vertices.size(), -1);
519 valid_to_all_vertexMap.resize(n_verts);
520
521 for (int i = 0, j = 0; i < vertices.size(); i++)
522 {
523 if (vertices[i].n_elem == 0)
524 continue;
527 j++;
528 }
529
530 all_to_valid_edgeMap.assign(edges.size(), -1);
532
533 for (int i = 0, j = 0; i < edges.size(); i++)
534 {
535 if (edges[i].n_elem() == 0)
536 continue;
539 j++;
540 }
541 index_prepared = true;
542 }
543
544 void NCMesh2D::append(const Mesh &mesh)
545 {
546 assert(typeid(mesh) == typeid(NCMesh2D));
547 Mesh::append(mesh);
548
549 const NCMesh2D &mesh2d = dynamic_cast<const NCMesh2D &>(mesh);
550
551 const int n_v = n_vertices();
552 const int n_f = n_faces();
553
554 vertices.reserve(n_v + mesh2d.n_vertices());
555 for (int i = 0; i < mesh2d.n_vertices(); i++)
556 {
557 vertices.emplace_back(mesh2d.vertices[i].pos);
558 }
559 for (int i = 0; i < mesh2d.n_faces(); i++)
560 {
561 Eigen::Vector3i face = mesh2d.elements[i].vertices;
562 face = face.array() + n_v;
563 add_element(face, -1);
564 }
565
566 prepare_mesh();
567 }
568
569 std::unique_ptr<Mesh> NCMesh2D::copy() const
570 {
571 return std::make_unique<NCMesh2D>(*this);
572 }
573
574 void NCMesh2D::traverse_edge(Eigen::Vector2i v, double p1, double p2, int depth, std::vector<follower_edge> &list) const
575 {
576 int v_mid = find_vertex(v);
577 std::vector<follower_edge> list1, list2;
578 if (v_mid >= 0)
579 {
580 double p_mid = (p1 + p2) / 2;
581 traverse_edge(Eigen::Vector2i(v[0], v_mid), p1, p_mid, depth + 1, list1);
582 list.insert(
583 list.end(),
584 std::make_move_iterator(list1.begin()),
585 std::make_move_iterator(list1.end()));
586 traverse_edge(Eigen::Vector2i(v_mid, v[1]), p_mid, p2, depth + 1, list2);
587 list.insert(
588 list.end(),
589 std::make_move_iterator(list2.begin()),
590 std::make_move_iterator(list2.end()));
591 }
592 if (depth > 0)
593 {
594 int follower_id = find_edge(v);
595 if (follower_id >= 0 && edges[follower_id].n_elem() > 0)
596 list.emplace_back(follower_id, p1, p2);
597 }
598 }
599
601 {
602 min = vertices[0].pos;
603 max = vertices[0].pos;
604
605 for (const auto &v : vertices)
606 {
607 for (int d = 0; d < 2; d++)
608 {
609 if (v.pos[d] > max[d])
610 max[d] = v.pos[d];
611 if (v.pos[d] < min[d])
612 min[d] = v.pos[d];
613 }
614 }
615 }
616
618 {
619 const auto &elem = elements[valid_to_all_elem(f)];
620
622 idx2.face = f;
623 idx2.vertex = all_to_valid_vertex(elem.vertices(lv));
624 idx2.edge = all_to_valid_edge(elem.edges(lv));
625 idx2.face_corner = -1;
626
627 return idx2;
628 }
629
631 {
632 const auto &elem = elements[valid_to_all_elem(idx.face)];
633 const auto &edge = edges[valid_to_all_edge(idx.edge)];
634
636 idx2.face = idx.face;
637 idx2.edge = idx.edge;
638
639 int v1 = valid_to_all_vertex(idx.vertex);
640 int v2 = -1;
641 for (int i = 0; i < edge.vertices.size(); i++)
642 if (edge.vertices(i) != v1)
643 {
644 v2 = edge.vertices(i);
645 break;
646 }
647
648 idx2.vertex = all_to_valid_vertex(v2);
649 idx2.face_corner = -1;
650
651 return idx2;
652 }
653
655 {
656 const auto &elem = elements[valid_to_all_elem(idx.face)];
657
659 idx2.face = idx.face;
660 idx2.vertex = idx.vertex;
661 idx2.face_corner = -1;
662 const int full_vertex_id = valid_to_all_vertex(idx.vertex);
663
664 for (int i = 0; i < elem.edges.size(); i++)
665 {
666 const auto &edge = edges[elem.edges(i)];
667 const int valid_edge_id = all_to_valid_edge(elem.edges(i));
668 if (valid_edge_id != idx.edge && find(edge.vertices, full_vertex_id) >= 0)
669 {
670 idx2.edge = valid_edge_id;
671 break;
672 }
673 }
674
675 return idx2;
676 }
677
679 {
681 idx2.edge = idx.edge;
682 idx2.vertex = idx.vertex;
683 idx2.face_corner = -1;
684
685 const auto &edge = edges[valid_to_all_edge(idx.edge)];
686 if (edge.n_elem() == 2)
687 idx2.face = (edge.find_opposite_element(valid_to_all_elem(idx.face)));
688 else
689 idx2.face = -1;
690
691 return idx2;
692 }
693
695 {
696 polyfem::RowVectorNd min, max;
697 bounding_box(min, max);
698
699 auto extent = max - min;
700 double scale = std::max(extent(0), extent(1));
701
702 for (auto &v : vertices)
703 v.pos = (v.pos - min.transpose()) / scale;
704 }
705
706 double NCMesh2D::edge_length(const int gid) const
707 {
708 const int v1 = edge_vertex(gid, 0);
709 const int v2 = edge_vertex(gid, 1);
710
711 return (point(v1) - point(v2)).norm();
712 }
713
722
723 void NCMesh2D::set_point(const int global_index, const RowVectorNd &p)
724 {
725 vertices[valid_to_all_vertex(global_index)].pos = p;
726 }
727
729 {
730 const int v1 = edge_vertex(index, 0);
731 const int v2 = edge_vertex(index, 1);
732
733 return 0.5 * (point(v1) + point(v2));
734 }
735
736 // void NCMesh2D::triangulate_faces(Eigen::MatrixXi &tris, Eigen::MatrixXd &pts, std::vector<int> &ranges) const
737 // {
738 // ranges.clear();
739
740 // std::vector<Eigen::MatrixXi> local_tris(n_faces());
741 // std::vector<Eigen::MatrixXd> local_pts(n_faces());
742
743 // int total_tris = 0;
744 // int total_pts = 0;
745
746 // ranges.push_back(0);
747
748 // for (int f = 0; f < n_faces(); ++f)
749 // {
750 // const int n_vertices = n_face_vertices(f);
751
752 // Eigen::MatrixXd face_pts(n_vertices, 2);
753 // local_tris[f].resize(n_vertices - 2, 3);
754
755 // for (int i = 0; i < n_vertices; ++i)
756 // {
757 // const int vertex = face_vertex(f, i);
758 // auto pt = point(vertex);
759 // face_pts(i, 0) = pt[0];
760 // face_pts(i, 1) = pt[1];
761 // }
762
763 // for (int i = 1; i < n_vertices - 1; ++i)
764 // {
765 // local_tris[f].row(i - 1) << 0, i, i + 1;
766 // }
767
768 // local_pts[f] = face_pts;
769
770 // total_tris += local_tris[f].rows();
771 // total_pts += local_pts[f].rows();
772
773 // ranges.push_back(total_tris);
774
775 // assert(local_pts[f].rows() == face_pts.rows());
776 // }
777
778 // tris.resize(total_tris, 3);
779 // pts.resize(total_pts, 2);
780
781 // int tri_index = 0;
782 // int pts_index = 0;
783 // for (std::size_t i = 0; i < local_tris.size(); ++i)
784 // {
785 // tris.block(tri_index, 0, local_tris[i].rows(), local_tris[i].cols()) = local_tris[i].array() + pts_index;
786 // tri_index += local_tris[i].rows();
787
788 // pts.block(pts_index, 0, local_pts[i].rows(), local_pts[i].cols()) = local_pts[i];
789 // pts_index += local_pts[i].rows();
790 // }
791 // }
792
793 void NCMesh2D::set_body_ids(const std::vector<int> &body_ids)
794 {
795 assert(body_ids.size() == n_faces());
796 Mesh::set_body_ids(body_ids);
797 for (int i = 0; i < body_ids.size(); i++)
798 {
799 elements[valid_to_all_elem(i)].body_id = body_ids[i];
800 }
801 }
802
803 void NCMesh2D::set_boundary_ids(const std::vector<int> &boundary_ids)
804 {
805 assert(boundary_ids.size() == n_edges());
806 Mesh::set_boundary_ids(boundary_ids);
807 for (int i = 0; i < boundary_ids.size(); i++)
808 {
809 edges[valid_to_all_edge(i)].boundary_id = boundary_ids[i];
810 }
811 }
812
813 void NCMesh2D::compute_body_ids(const std::function<int(const size_t, const std::vector<int> &, const RowVectorNd &)> &marker)
814 {
815 body_ids_.resize(n_faces());
816 std::fill(body_ids_.begin(), body_ids_.end(), -1);
817
818 for (int e = 0; e < n_faces(); ++e)
819 {
820 const auto bary = face_barycenter(e);
821 body_ids_[e] = marker(e, element_vertices(e), bary);
822 elements[valid_to_all_elem(e)].body_id = body_ids_[e];
823 }
824 }
825
826 void NCMesh2D::compute_boundary_ids(const std::function<int(const size_t, const std::vector<int> &, const RowVectorNd &, bool)> &marker)
827 {
828 boundary_ids_.resize(n_edges());
829
830 for (int e = 0; e < n_edges(); ++e)
831 {
832 bool is_boundary = is_boundary_edge(e);
833 const auto p = edge_barycenter(e);
834
835 std::vector<int> vs = {edge_vertex(e, 0), edge_vertex(e, 1)};
836 std::sort(vs.begin(), vs.end());
837 boundary_ids_[e] = marker(e, vs, p, is_boundary);
838 edges[valid_to_all_edge(e)].boundary_id = boundary_ids_[e];
839 }
840 }
841
842 } // namespace mesh
843} // namespace polyfem
int V
Eigen::MatrixXd vec
Definition Assembler.cpp:76
Eigen::RowVectorXd point
int edge_id
int x
RowVectorNd face_barycenter(const int index) const override
face barycenter
Definition Mesh2D.cpp:69
Format-independent input used to construct a runtime Mesh.
Definition MeshData.hpp:12
Eigen::MatrixXd vertices
Definition MeshData.hpp:21
Eigen::MatrixXi elements
Definition MeshData.hpp:22
Abstract mesh class to capture 2d/3d conforming and non-conforming meshes.
Definition Mesh.hpp:50
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
bool has_node_ids() const
checks if points selections are available
Definition Mesh.hpp:524
virtual void set_body_ids(const std::vector< int > &body_ids)
Set the volume sections.
Definition Mesh.hpp:444
std::vector< int > boundary_ids_
list of surface labels
Definition Mesh.hpp:690
void clear_higher_order_data()
Definition Mesh.cpp:685
std::vector< int > node_ids_
list of node labels
Definition Mesh.hpp:688
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 filter_element_data(const std::vector< bool > &keep)
Definition Mesh.cpp:46
virtual void append(const Mesh &mesh)
appends a new mesh to the end of this
Definition Mesh.cpp:456
virtual void set_boundary_ids(const std::vector< int > &boundary_ids)
Set the boundary selection from a vector.
Definition Mesh.hpp:436
int find_edge(Eigen::Vector2i v) const
Definition NCMesh2D.cpp:177
bool is_boundary_element(const int element_global_id) const override
is cell boundary
Definition NCMesh2D.cpp:60
void traverse_edge(Eigen::Vector2i v, double p1, double p2, int depth, std::vector< follower_edge > &list) const
Definition NCMesh2D.cpp:574
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 NCMesh2D.cpp:813
Navigation::Index switch_face(Navigation::Index idx) const override
Definition NCMesh2D.cpp:678
std::vector< int > valid_to_all_edgeMap
Definition NCMesh2D.hpp:390
Navigation::Index switch_vertex(Navigation::Index idx) const override
Definition NCMesh2D.cpp:630
std::unique_ptr< Mesh > copy() const override
Create a copy of the mesh.
Definition NCMesh2D.cpp:569
void attach_higher_order_nodes(const Eigen::MatrixXd &V, const std::vector< std::vector< int > > &nodes) override
attach high order nodes
Definition NCMesh2D.cpp:123
int face_edge(const int f_id, const int le_id) const
Definition NCMesh2D.hpp:195
bool build_topology(const MeshData &data) override
Construct only the dimension-specific topology.
Definition NCMesh2D.cpp:87
void refine_elements(const std::vector< int > &ids)
Definition NCMesh2D.cpp:296
void prepare_mesh() override
method used to finalize the mesh.
Definition NCMesh2D.hpp:282
std::vector< ncVert > vertices
Definition NCMesh2D.hpp:382
std::vector< int > all_to_valid_elemMap
Definition NCMesh2D.hpp:388
static double element_weight_to_edge_weight(const int l, const Eigen::Vector2d &pos)
Definition NCMesh2D.cpp:479
void refine_element(int id_full)
Definition NCMesh2D.cpp:230
void set_boundary_ids(const std::vector< int > &boundary_ids) override
Set the boundary selection from a vector.
Definition NCMesh2D.cpp:803
int n_faces() const override
number of faces
Definition NCMesh2D.hpp:168
void set_point(const int global_index, const RowVectorNd &p) override
Set the point.
Definition NCMesh2D.cpp:723
int all_to_valid_vertex(const int id) const
Definition NCMesh2D.hpp:311
std::vector< ncElem > elements
Definition NCMesh2D.hpp:381
void set_body_ids(const std::vector< int > &body_ids) override
Set the volume sections.
Definition NCMesh2D.cpp:793
Navigation::Index switch_edge(Navigation::Index idx) const override
Definition NCMesh2D.cpp:654
int get_edge(Eigen::Vector2i v)
Definition NCMesh2D.cpp:187
int add_element(Eigen::Vector3i v, int parent=-1)
Definition NCMesh2D.cpp:200
void coarsen_element(int id_full)
Definition NCMesh2D.cpp:306
int get_vertex(Eigen::Vector2i v)
Definition NCMesh2D.cpp:163
Navigation::Index get_index_from_face(int f, int lv=0) const override
Definition NCMesh2D.cpp:617
double edge_length(const int gid) const override
edge length
Definition NCMesh2D.cpp:706
int valid_to_all_edge(const int id) const
Definition NCMesh2D.hpp:329
int n_vertices() const override
number of vertices
Definition NCMesh2D.hpp:177
bool is_boundary_edge(const int edge_global_id) const override
is edge boundary
Definition NCMesh2D.hpp:219
void refine(const int n_refinement, const double t) override
refine the mesh
Definition NCMesh2D.cpp:70
std::pair< RowVectorNd, int > face_node(const Navigation::Index &index, const int n_new_nodes, const int i, const int j) const override
Definition NCMesh2D.cpp:138
void normalize() override
normalize the mesh
Definition NCMesh2D.cpp:694
std::vector< int > refineHistory
Definition NCMesh2D.hpp:392
int valid_to_all_elem(const int id) const
Definition NCMesh2D.hpp:342
std::vector< int > valid_to_all_elemMap
Definition NCMesh2D.hpp:388
int edge_vertex(const int e_id, const int lv_id) const override
id of the edge vertex
Definition NCMesh2D.hpp:192
std::vector< int > all_to_valid_edgeMap
Definition NCMesh2D.hpp:390
std::vector< int > all_to_valid_vertexMap
Definition NCMesh2D.hpp:389
std::unordered_map< Eigen::Vector2i, int, ArrayHasher2D > midpointMap
Definition NCMesh2D.hpp:385
std::vector< ncBoundary > edges
Definition NCMesh2D.hpp:383
void compute_elements_tag() override
compute element types, see ElementType
Definition NCMesh2D.cpp:714
RowVectorNd edge_barycenter(const int index) const override
edge barycenter
Definition NCMesh2D.cpp:728
int all_to_valid_edge(const int id) const
Definition NCMesh2D.hpp:323
std::unordered_map< Eigen::Vector2i, int, ArrayHasher2D > edgeMap
Definition NCMesh2D.hpp:386
int find_vertex(Eigen::Vector2i v) const
Definition NCMesh2D.cpp:153
void bounding_box(RowVectorNd &min, RowVectorNd &max) const override
computes the bbox of the mesh
Definition NCMesh2D.cpp:600
int n_face_vertices(const int f_id) const override
number of vertices of a face
Definition NCMesh2D.hpp:187
int valid_to_all_vertex(const int id) const
Definition NCMesh2D.hpp:316
void build_element_vertex_adjacency()
Definition NCMesh2D.cpp:427
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 NCMesh2D.cpp:826
int n_edges() const override
number of edges
Definition NCMesh2D.hpp:169
std::vector< int > valid_to_all_vertexMap
Definition NCMesh2D.hpp:389
std::pair< RowVectorNd, int > edge_node(const Navigation::Index &index, const int n_new_nodes, const int i) const override
Definition NCMesh2D.cpp:129
void update_elements_tag() override
Update elements types.
Definition NCMesh2D.cpp:718
void append(const Mesh &mesh) override
appends a new mesh to the end of this
Definition NCMesh2D.cpp:544
void remove_elements(const std::vector< bool > &keep) override
Remove all top-dimensional elements whose mask entry is false.
Definition NCMesh2D.cpp:13
int find(const Eigen::VectorXi &vec, int x)
Definition NCMesh2D.cpp:341
void orient_normals_2d(GEO::Mesh &M)
Orient facets of a 2D mesh so that each connected component has positive volume.
void to_geogram_mesh(const Eigen::MatrixXd &V, const Eigen::MatrixXi &F, GEO::Mesh &M)
Converts a triangle mesh to a Geogram mesh.
double line_weight(Eigen::Matrix< double, 2, 2 > &e, Eigen::VectorXd &v)
Definition NCMesh2D.cpp:416
std::tuple< bool, int, Tree > is_valid(const int dim, const std::vector< basis::ElementBases > &bases, const std::vector< basis::ElementBases > &gbases, const Eigen::VectorXd &u, const double threshold, const unsigned max_iter)
Definition Jacobian.cpp:201
Eigen::Matrix< double, 1, Eigen::Dynamic, Eigen::RowMajor, 1, 3 > RowVectorNd
Definition Types.hpp:13