14#include <lagrange/Logger.h>
15#include <lagrange/Mesh.h>
16#include <lagrange/attributes/map_corner_attributes.h>
17#include <lagrange/attributes/map_facet_attributes.h>
18#include <lagrange/attributes/map_vertex_attributes.h>
19#include <lagrange/common.h>
20#include <lagrange/create_mesh.h>
21#include <lagrange/legacy/inline.h>
23#include <tbb/parallel_for.h>
24#include <tbb/parallel_sort.h>
37template <
typename MeshType>
40 const std::vector<std::string>& indexed_attribute_names)
42 using VertexArray =
typename MeshType::VertexArray;
43 using AttributeArray =
typename MeshType::AttributeArray;
44 using Index =
typename MeshType::Index;
45 using IndexArray =
typename MeshType::IndexArray;
47 const Index num_attrs = safe_cast<Index>(indexed_attribute_names.size());
48 std::vector<std::tuple<const AttributeArray&, const IndexArray&>> attrs;
49 attrs.reserve(num_attrs);
50 for (
const auto& attr_name : indexed_attribute_names) {
51 attrs.emplace_back(mesh.get_indexed_attribute(attr_name));
54 const Index num_vertices = mesh.get_num_vertices();
55 const Index num_facets = mesh.get_num_facets();
56 const Index vertex_per_facet = mesh.get_vertex_per_facet();
57 const auto& vertices = mesh.get_vertices();
58 const auto& facets = mesh.get_facets();
59 const Index num_corners = num_facets * vertex_per_facet;
60 std::vector<Index> corner_indices(num_corners);
61 std::iota(corner_indices.begin(), corner_indices.end(), 0);
64 auto corner_index_comp = [&](Index i, Index j) ->
bool {
65 const Index fi = i / vertex_per_facet;
66 const Index ci = i % vertex_per_facet;
67 const Index fj = j / vertex_per_facet;
68 const Index cj = j % vertex_per_facet;
70 if (facets(fi, ci) == facets(fj, cj)) {
71 for (
auto k :
range(num_attrs)) {
72 const auto& indices = std::get<1>(attrs[k]);
73 if (indices(fi, ci) != indices(fj, cj)) {
74 return indices(fi, ci) < indices(fj, cj);
78 return facets(fi, ci) < facets(fj, cj);
83 auto corner_index_eq = [&](Index i, Index j) ->
bool {
84 const Index fi = i / vertex_per_facet;
85 const Index ci = i % vertex_per_facet;
86 const Index fj = j / vertex_per_facet;
87 const Index cj = j % vertex_per_facet;
89 if (facets(fi, ci) == facets(fj, cj)) {
90 for (
auto k :
range(num_attrs)) {
91 const auto& indices = std::get<1>(attrs[k]);
92 if (indices(fi, ci) != indices(fj, cj)) {
102 tbb::parallel_sort(corner_indices.begin(), corner_indices.end(), corner_index_comp);
104 std::vector<bool> visited(num_vertices,
false);
105 std::vector<Index> new_vertices;
106 new_vertices.reserve(num_vertices);
107 auto unified_facets = facets;
109 for (Index i = 0; i < num_corners;) {
110 const Index fi = corner_indices[i] / vertex_per_facet;
111 const Index ci = corner_indices[i] % vertex_per_facet;
113 Index vi = facets(fi, ci);
117 new_vertices.push_back(vi);
118 vi = (Index)(new_vertices.size() + num_vertices - 1);
122 while (j < num_corners && corner_index_eq(corner_indices[i], corner_indices[j])) {
123 const Index fj = corner_indices[j] / vertex_per_facet;
124 const Index cj = corner_indices[j] % vertex_per_facet;
125 unified_facets(fj, cj) = vi;
131 const Index num_added_vertices = safe_cast<Index>(new_vertices.size());
132 VertexArray unified_vertices(num_vertices + num_added_vertices, mesh.get_dim());
133 unified_vertices.topRows(num_vertices) = vertices;
134 tbb::parallel_for(Index(0), num_added_vertices, [&](Index i) {
135 unified_vertices.row(i + num_vertices) = vertices.row(new_vertices[i]);
138 auto unified_mesh =
create_mesh(std::move(unified_vertices), std::move(unified_facets));
139 const auto& new_facets = unified_mesh->get_facets();
141 for (
auto i :
range(num_attrs)) {
142 const auto& attr_name = indexed_attribute_names[i];
143 unified_mesh->add_vertex_attribute(attr_name);
144 const auto& values = std::get<0>(attrs[i]);
145 const auto& indices = std::get<1>(attrs[i]);
147 AttributeArray unified_attr(num_vertices + num_added_vertices, values.cols());
148 unified_attr.setZero();
149 for (Index fi = 0; fi < num_facets; ++fi) {
150 for (
auto ci :
range(vertex_per_facet)) {
151 unified_attr.row(new_facets(fi, ci)) = values.row(indices(fi, ci));
154 unified_mesh->import_vertex_attribute(attr_name, unified_attr);
159 std::vector<Index> vertex_map(num_vertices + num_added_vertices);
160 tbb::parallel_for(Index(0), num_vertices, [&](Index i) { vertex_map[i] = i; });
161 tbb::parallel_for(Index(0), num_added_vertices, [&](Index i) {
162 vertex_map[num_vertices + i] = new_vertices[i];
164 map_vertex_attributes(mesh, *unified_mesh, vertex_map);
166 map_facet_attributes(mesh, *unified_mesh);
167 map_corner_attributes(mesh, *unified_mesh);
SurfaceMesh< Scalar, Index > unify_index_buffer(const SurfaceMesh< Scalar, Index > &mesh, const std::vector< AttributeId > &attribute_ids={})
Unify index buffers of the input mesh for all attributes specified in attribute_ids.
Definition: unify_index_buffer.cpp:34
internal::Range< Index > range(Index end)
Returns an iterable object representing the range [0, end).
Definition: range.h:176
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