17#include <unordered_map>
19#include <lagrange/Edge.h>
20#include <lagrange/Mesh.h>
21#include <lagrange/attributes/map_attributes.h>
22#include <lagrange/common.h>
23#include <lagrange/create_mesh.h>
24#include <lagrange/legacy/inline.h>
25#include <lagrange/utils/Error.h>
26#include <lagrange/utils/chain_edges.h>
40template <
typename MeshType>
43 if (!mesh.is_connectivity_initialized()) {
44 mesh.initialize_connectivity();
46 if (mesh.get_vertex_per_facet() != 3) {
47 throw std::runtime_error(
48 "Resolve vertex nonmanifoldness is only implemented for triangle mesh");
51 using Index =
typename MeshType::Index;
53 using VertexArray =
typename MeshType::VertexArray;
54 using FacetArray =
typename MeshType::FacetArray;
56 const auto dim = mesh.get_dim();
57 const Index num_vertices = mesh.get_num_vertices();
58 const auto& vertices = mesh.get_vertices();
59 const auto& facets = mesh.get_facets();
61 auto get_opposite_edge = [&](Index fid, Index vid) {
62 const auto& f = facets.row(fid);
64 return Edge(f[1], f[2]);
65 }
else if (f[1] == vid) {
66 return Edge(f[2], f[0]);
67 }
else if (f[2] == vid) {
68 return Edge(f[0], f[1]);
71 "Facet " + std::to_string(fid) +
" does not contain vertex " + std::to_string(vid));
75 FacetArray out_facets(facets);
76 Index vertex_count = mesh.get_num_vertices();
83 std::vector<Index> backward_vertex_map(vertex_count);
84 std::iota(backward_vertex_map.begin(), backward_vertex_map.end(), 0);
86 for (Index i = 0; i < num_vertices; i++) {
87 const auto& adj_facets = mesh.get_facets_adjacent_to_vertex(i);
88 std::vector<Index> rim_edges;
89 rim_edges.reserve(adj_facets.size() * 2);
90 for (Index fid : adj_facets) {
91 const auto e = get_opposite_edge(fid, i);
92 rim_edges.push_back(e[0]);
93 rim_edges.push_back(e[1]);
95 auto [loops, chains] = chain_directed_edges<Index>({rim_edges.data(), rim_edges.size()});
96 if (loops.size() + chains.size() > 1) {
97 std::unordered_map<Index, Index> comp_map;
99 for (
const auto& loop : loops) {
100 for (
const auto vid : loop) {
101 comp_map[vid] = comp_count;
105 for (
const auto& chain : chains) {
106 for (
const auto vid : chain) {
107 comp_map[vid] = comp_count;
113 for (Index fid : adj_facets) {
114 auto& f = facets.row(fid);
115 for (Index j = 0; j < 3; j++) {
117 const Index next = (j + 1) % 3;
118 const Index prev = (j + 2) % 3;
119 assert(comp_map.find(f[next]) != comp_map.end());
120 assert(comp_map.find(f[prev]) != comp_map.end());
121 if (comp_map[f[next]] != comp_map[f[prev]]) {
122 throw std::runtime_error(
123 "Complex edge loop detected. Vertex " + std::to_string(i) +
124 "'s one ring neighborhood must contain nonmanifold_edges!");
126 assert(comp_map[f[next]] == comp_map[f[prev]]);
127 const Index comp_id = comp_map[f[next]];
129 const Index new_vertex_index = vertex_count + comp_id - 1;
130 out_facets(fid, j) = new_vertex_index;
131 if (safe_cast<Index>(backward_vertex_map.size()) <= new_vertex_index) {
132 backward_vertex_map.resize(new_vertex_index + 1, invalid<Index>());
134 backward_vertex_map[new_vertex_index] = i;
140 vertex_count += safe_cast<Index>(loops.size() + chains.size()) - 1;
143 assert(out_facets.rows() == 0 || out_facets.maxCoeff() == vertex_count - 1);
146 VertexArray out_vertices(vertex_count, dim);
147 out_vertices.block(0, 0, num_vertices, dim) = vertices;
148 for (Index i = num_vertices; i < vertex_count; i++) {
149 out_vertices.row(i) = vertices.row(backward_vertex_map[i]);
152 auto out_mesh =
create_mesh(std::move(out_vertices), std::move(out_facets));
@ Edge
Per-edge mesh attributes.
Definition: AttributeFwd.h:34
void map_attributes(const SurfaceMesh< Scalar, Index > &source_mesh, SurfaceMesh< Scalar, Index > &target_mesh, span< const Index > mapping_data, span< const Index > mapping_offsets={}, const MapAttributesOptions &options={})
Map attributes from the source mesh to the target mesh.
Definition: map_attributes.cpp:26
Main namespace for Lagrange.
Definition: AABBIGL.h:30
auto create_mesh(const Eigen::MatrixBase< DerivedV > &vertices, const Eigen::MatrixBase< DerivedF > &facets)
This function create a new mesh given the vertex and facet arrays by copying data into the Mesh objec...
Definition: create_mesh.h:39
void resolve_vertex_nonmanifoldness(SurfaceMesh< Scalar, Index > &mesh)
Resolve nonmanifold vertices by pulling disconnected 1-ring neighborhood apart.
Definition: resolve_vertex_nonmanifoldness.cpp:35
@ Error
Throw an error if collision is detected.