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