Lagrange
remove_duplicate_vertices.h
1/*
2 * Copyright 2016 Adobe. All rights reserved.
3 * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License. You may obtain a copy
5 * of the License at http://www.apache.org/licenses/LICENSE-2.0
6 *
7 * Unless required by applicable law or agreed to in writing, software distributed under
8 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9 * OF ANY KIND, either express or implied. See the License for the specific language
10 * governing permissions and limitations under the License.
11 */
12#pragma once
13
14#include <lagrange/Mesh.h>
15#include <lagrange/MeshTrait.h>
16#include <lagrange/attributes/map_attributes.h>
17#include <lagrange/common.h>
18#include <lagrange/create_mesh.h>
19#include <lagrange/internal/sortrows.h>
20#include <lagrange/legacy/inline.h>
21#include <lagrange/mesh_cleanup/remove_topologically_degenerate_triangles.h>
22#include <lagrange/reorder_mesh_vertices.h>
23#include <lagrange/utils/range.h>
24
25#include <vector>
26
27namespace lagrange {
28LAGRANGE_LEGACY_INLINE
29namespace legacy {
30
31namespace legacy_internal {
32// A much lighter version of igl::unique_rows()
33template <typename DerivedA, typename Index>
34void unique_rows(
35 const Eigen::DenseBase<DerivedA>& A,
36 Index& num_unique_vertices,
37 std::vector<Index>& forward_mapping)
38{
39 // Sort the rows
40 Eigen::VectorXi IM;
41 {
42 DerivedA __; // sorted A
43 constexpr bool is_ascending = true; // does not matter really
44 lagrange::internal::sortrows(A, is_ascending, __, IM);
45 }
46
47 // Build the forward mapping and the number of unique rows
48 const Index num_rows = safe_cast<Index>(A.rows());
49 forward_mapping.resize(num_rows);
50 num_unique_vertices = 0;
51 forward_mapping[IM(0)] = num_unique_vertices;
52 for (auto i : range<Index>(1, num_rows)) {
53 if ((A.row(IM(i)) != A.row(IM(i - 1)))) {
54 ++num_unique_vertices;
55 }
56 forward_mapping[IM(i)] = static_cast<Index>(num_unique_vertices);
57 }
58 ++num_unique_vertices; // num_of_xx = last index + 1
59}
60} // namespace legacy_internal
61
62
75template <typename MeshType>
76std::unique_ptr<MeshType> remove_duplicate_vertices(
77 const MeshType& mesh,
78 const std::vector<std::string>& vertex_attribute_names,
79 const std::vector<std::string>& indexed_attribute_names = {})
80{
81 static_assert(MeshTrait<MeshType>::is_mesh(), "Input type is not Mesh");
83 mesh.get_vertex_per_facet() == 3,
84 std::string("vertex per facet is ") + std::to_string(mesh.get_vertex_per_facet()));
85
86 using Scalar = typename MeshType::Scalar;
87 using Index = typename MeshType::Index;
88 using Entries = Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>;
89
90 const auto& vertices = mesh.get_vertices();
91 const auto& facets = mesh.get_facets();
92 const Index num_vertices = mesh.get_num_vertices();
93 const Index num_facets = mesh.get_num_facets();
94
95 const Index dim = mesh.get_dim();
96 Index num_cols = dim;
97 for (const auto& attr_name : vertex_attribute_names) {
98 la_runtime_assert(mesh.has_vertex_attribute(attr_name));
99 num_cols += static_cast<Index>(mesh.get_vertex_attribute(attr_name).cols());
100 }
101 for (const auto& attr_name : indexed_attribute_names) {
102 la_runtime_assert(mesh.has_indexed_attribute(attr_name));
103 auto attr = mesh.get_indexed_attribute(attr_name);
104 num_cols += static_cast<Index>(std::get<0>(attr).cols());
105 }
106
107 Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> vertices_and_keys;
108 vertices_and_keys.resize(num_vertices, num_cols);
109 vertices_and_keys.leftCols(dim) = vertices;
110 Index col_count = dim;
111
112 for (const auto& attr_name : vertex_attribute_names) {
113 const auto& attr = mesh.get_vertex_attribute(attr_name);
114 vertices_and_keys.block(0, col_count, num_vertices, attr.cols()) = attr;
115 col_count += static_cast<Index>(attr.cols());
116 }
117 for (const auto& attr_name : indexed_attribute_names) {
118 const auto attr = mesh.get_indexed_attribute(attr_name);
119 const auto& attr_values = std::get<0>(attr);
120 const auto& attr_indices = std::get<1>(attr);
121 for (auto i : range(num_facets)) {
122 vertices_and_keys.row(facets(i, 0)).segment(col_count, attr_values.cols()) =
123 attr_values.row(attr_indices(i, 0));
124 vertices_and_keys.row(facets(i, 1)).segment(col_count, attr_values.cols()) =
125 attr_values.row(attr_indices(i, 1));
126 vertices_and_keys.row(facets(i, 2)).segment(col_count, attr_values.cols()) =
127 attr_values.row(attr_indices(i, 2));
128 }
129 col_count += static_cast<Index>(attr_values.cols());
130 }
131
132 Entries unique_vertices_and_keys;
133 std::vector<Index> forward_mapping;
134 Index num_unique_vertices;
135 legacy_internal::unique_rows(vertices_and_keys, num_unique_vertices, forward_mapping);
136
137 la_runtime_assert(safe_cast<Eigen::Index>(forward_mapping.size()) == vertices.rows());
138
139 if (num_unique_vertices < mesh.get_num_vertices()) {
140 auto mesh2 = reorder_mesh_vertices(mesh, forward_mapping);
141 mesh2 = remove_topologically_degenerate_triangles(*mesh2);
142 return mesh2;
143 } else {
144 la_runtime_assert(num_unique_vertices == mesh.get_num_vertices());
145 auto mesh2 = create_mesh(mesh.get_vertices(), mesh.get_facets());
146 map_attributes(mesh, *mesh2);
147 return mesh2;
148 }
149}
150
168template <typename MeshType>
169std::unique_ptr<MeshType> remove_duplicate_vertices(
170 const MeshType& mesh,
171 const std::string& key_name = "",
172 bool with_uv = true)
173{
174 std::vector<std::string> vertex_attributes, indexed_attributes;
175 if (key_name != "") {
176 vertex_attributes.push_back(key_name);
177 }
178 if (with_uv && mesh.is_uv_initialized()) {
179 indexed_attributes.push_back("uv");
180 }
181 return remove_duplicate_vertices(mesh, vertex_attributes, indexed_attributes);
182}
183
184} // namespace legacy
185} // namespace lagrange
Definition: Mesh.h:48
#define la_runtime_assert(...)
Runtime assertion check.
Definition: assert.h:169
internal::Range< Index > range(Index end)
Returns an iterable object representing the range [0, end).
Definition: range.h:176
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_vertices(SurfaceMesh< Scalar, Index > &mesh, const RemoveDuplicateVerticesOptions &options={})
Removes duplicate vertices from a mesh.
Definition: remove_duplicate_vertices.cpp:33