17#include <unordered_map>
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/mesh_cleanup/remove_duplicate_facets.h>
26#include <lagrange/mesh_cleanup/remove_isolated_vertices.h>
27#include <lagrange/mesh_cleanup/remove_topologically_degenerate_triangles.h>
28#include <lagrange/mesh_cleanup/resolve_vertex_nonmanifoldness.h>
45template <
typename MeshType>
48 if (!mesh.is_connectivity_initialized()) {
49 mesh.initialize_connectivity();
52 mesh.initialize_edge_data();
54 using Index =
typename MeshType::Index;
55 using VertexArray =
typename MeshType::VertexArray;
56 using FacetArray =
typename MeshType::FacetArray;
58 const Index num_vertices = mesh.get_num_vertices();
59 const Index num_facets = mesh.get_num_facets();
60 const Index vertex_per_facet = mesh.get_vertex_per_facet();
61 const auto& vertices = mesh.get_vertices();
62 const auto& facets = mesh.get_facets();
71 auto get_orientation = [&facets](
const Index v0,
const Index v1,
const Index fid) ->
bool {
72 const auto& f = facets.row(fid);
73 if (f[0] == v0 && f[1] == v1)
75 else if (f[1] == v0 && f[2] == v1)
77 else if (f[2] == v0 && f[0] == v1)
91 auto is_inconsistently_oriented = [&mesh, &get_orientation](
const Index ei) ->
bool {
92 const auto e = mesh.get_edge_vertices(ei);
93 std::array<bool, 2> orientations{
false,
false};
95 mesh.foreach_facets_around_edge(ei, [&](Index fid) {
96 orientations[count] = get_orientation(e[0], e[1], fid);
99 return orientations[0] == orientations[1];
108 auto is_inconsistently_oriented_wrt_facets =
109 [&mesh, &get_orientation](
const Index ei,
const Index f0,
const Index f1) {
110 const auto e = mesh.get_edge_vertices(ei);
111 return get_orientation(e[0], e[1], f0) == get_orientation(e[0], e[1], f1);
118 auto is_nonmanifold_edge = [&mesh, &is_inconsistently_oriented](
const Index ei) {
119 auto edge_valence = mesh.get_num_facets_around_edge(ei);
120 if (edge_valence > 2)
return true;
121 if (edge_valence <= 1)
return false;
122 return is_inconsistently_oriented(ei);
128 constexpr Index BLANK = 0;
129 std::vector<Index> colors(num_facets, BLANK);
130 Index curr_color = 1;
131 for (Index i = 0; i < num_facets; i++) {
132 if (colors[i] != BLANK)
continue;
135 colors[i] = curr_color;
137 Index curr_fid = Q.front();
139 for (Index j = 0; j < vertex_per_facet; j++) {
140 Index ei = mesh.get_edge(curr_fid, j);
141 if (is_nonmanifold_edge(ei))
continue;
143 mesh.foreach_facets_around_edge(ei, [&](Index adj_fid) {
144 if (colors[adj_fid] == BLANK) {
145 colors[adj_fid] = curr_color;
154 Index vertex_count = num_vertices;
164 std::unordered_map<Index, std::unordered_map<Index, Index>> vertex_map;
166 for (Index i = 0; i < mesh.get_num_edges(); ++i) {
167 const auto e = mesh.get_edge_vertices(i);
169 if (!is_nonmanifold_edge(i))
continue;
170 auto itr0 = vertex_map.find(e[0]);
171 auto itr1 = vertex_map.find(e[1]);
173 if (itr0 == vertex_map.end()) {
174 itr0 = vertex_map.insert({e[0], std::unordered_map<Index, Index>()}).first;
176 if (itr1 == vertex_map.end()) {
177 itr1 = vertex_map.insert({e[1], std::unordered_map<Index, Index>()}).first;
180 auto& color_map_0 = itr0->second;
181 auto& color_map_1 = itr1->second;
183 std::unordered_map<Index, std::list<Index>> color_count;
184 mesh.foreach_facets_around_edge(i, [&](Index fid) {
185 const auto c = colors[fid];
187 auto c_itr = color_count.find(c);
188 if (c_itr == color_count.end()) {
189 color_count.insert({c, {fid}});
191 c_itr->second.push_back(fid);
194 auto c_itr0 = color_map_0.find(c);
195 if (c_itr0 == color_map_0.end()) {
196 if (color_map_0.size() == 0) {
197 color_map_0.insert({c, e[0]});
199 color_map_0.insert({c, vertex_count});
204 auto c_itr1 = color_map_1.find(c);
205 if (c_itr1 == color_map_1.end()) {
206 if (color_map_1.size() == 0) {
207 color_map_1.insert({c, e[1]});
209 color_map_1.insert({c, vertex_count});
215 for (
const auto& entry : color_count) {
220 const bool inconsistent_edge =
221 (entry.second.size() == 2) &&
222 is_inconsistently_oriented_wrt_facets(i, entry.second.front(), entry.second.back());
229 const bool single_comp_nonmanifoldness = entry.second.size() > 2;
231 if (single_comp_nonmanifoldness || inconsistent_edge) {
234 for (
const auto fid : entry.second) {
235 colors[fid] = curr_color;
236 color_map_0.insert({curr_color, vertex_count});
238 color_map_1.insert({curr_color, vertex_count});
247 for (Index i = 0; i < num_vertices; i++) {
248 const auto& adj_facets = mesh.get_facets_adjacent_to_vertex(i);
249 std::set<Index> adj_colors;
250 for (
auto adj_f : adj_facets) {
251 adj_colors.insert(colors[adj_f]);
253 if (adj_colors.size() <= 1)
continue;
255 auto itr = vertex_map.find(i);
256 if (itr == vertex_map.end()) {
257 vertex_map.insert({i, {}});
260 auto& vi_map = vertex_map[i];
261 for (
auto c : adj_colors) {
262 auto c_itr = vi_map.find(c);
263 if (c_itr == vi_map.end()) {
264 if (vi_map.size() == 0) {
265 vi_map.insert({c, i});
267 vi_map.insert({c, vertex_count});
274 VertexArray manifold_vertices(vertex_count, vertices.cols());
275 manifold_vertices.topRows(num_vertices) = vertices;
277 std::vector<Index> backward_vertex_map(vertex_count, 0);
278 std::iota(backward_vertex_map.begin(), backward_vertex_map.begin() + num_vertices, 0);
280 for (
const auto& itr : vertex_map) {
281 Index vid = itr.first;
282 for (
const auto& itr2 : itr.second) {
283 manifold_vertices.row(itr2.second) = vertices.row(vid);
284 backward_vertex_map[itr2.second] = vid;
288 FacetArray manifold_facets = facets;
289 for (Index i = 0; i < num_facets; i++) {
290 const Index c = colors[i];
291 for (Index j = 0; j < vertex_per_facet; j++) {
292 const auto& itr = vertex_map.find(manifold_facets(i, j));
293 if (itr != vertex_map.end()) {
294 manifold_facets(i, j) = itr->second[c];
299 auto out_mesh =
create_mesh(std::move(manifold_vertices), std::move(manifold_facets));
303 out_mesh->initialize_connectivity();
304 out_mesh->initialize_edge_data();
307 out_mesh = remove_topologically_degenerate_triangles(*out_mesh);
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 remove_duplicate_facets(SurfaceMesh< Scalar, Index > &mesh, const RemoveDuplicateFacetOptions &opts={})
Remove duplicate facets in the mesh.
Definition: remove_duplicate_facets.cpp:235
void resolve_vertex_nonmanifoldness(SurfaceMesh< Scalar, Index > &mesh)
Resolve nonmanifold vertices by pulling disconnected 1-ring neighborhood apart.
Definition: resolve_vertex_nonmanifoldness.cpp:35
void remove_isolated_vertices(SurfaceMesh< Scalar, Index > &mesh)
Removes isolated vertices of a mesh.
Definition: remove_isolated_vertices.cpp:20
void resolve_nonmanifoldness(SurfaceMesh< Scalar, Index > &mesh)
Resolve both non-manifold vertices and non-manifold edges in the input mesh.
Definition: resolve_nonmanifoldness.cpp:35