20#include <lagrange/utils/warnoff.h>
21#include <tbb/blocked_range.h>
22#include <tbb/parallel_for.h>
23#include <tbb/parallel_sort.h>
24#include <lagrange/utils/warnon.h>
27#include <lagrange/Mesh.h>
28#include <lagrange/MeshTrait.h>
29#include <lagrange/legacy/inline.h>
30#include <lagrange/utils/assert.h>
31#include <lagrange/utils/range.h>
41template <
typename MeshType>
42void condense_indexed_attribute(
44 const std::string& attr_name,
45 const std::string& new_attr_name =
"")
47 static_assert(MeshTrait<MeshType>::is_mesh(),
"MeshType is not a mesh");
49 mesh.has_indexed_attribute(attr_name),
50 fmt::format(
"Missing attribute '{}'", attr_name));
52 using Index =
typename MeshType::Index;
53 using AttributeArray =
typename MeshType::AttributeArray;
54 using IndexArray =
typename MeshType::IndexArray;
55 static_assert(AttributeArray::IsRowMajor,
"Attribute array must be row major");
57 const auto num_vertices = mesh.get_num_vertices();
58 const auto num_facets = mesh.get_num_facets();
59 const auto& facets = mesh.get_facets();
60 const auto vertex_per_facet = mesh.get_vertex_per_facet();
62 const auto attr = mesh.get_indexed_attribute(attr_name);
63 const auto& attr_values = std::get<0>(attr);
64 const auto& attr_indices = std::get<1>(attr);
65 const Index num_cols = safe_cast<Index>(attr_values.cols());
67 using IndexEntry = std::array<Index, 2>;
74 auto index_pair_comp = [&](
const IndexEntry& id0,
const IndexEntry& id1) {
75 const Index offset_0 = attr_indices(id0[0], id0[1]) * num_cols;
76 const Index offset_1 = attr_indices(id1[0], id1[1]) * num_cols;
77 const auto base_ptr = attr_values.data();
78 return std::lexicographical_compare(
80 base_ptr + offset_0 + num_cols,
82 base_ptr + offset_1 + num_cols);
88 auto index_pair_eq = [&](
const IndexEntry& id0,
const IndexEntry& id1) ->
bool {
89 return attr_values.row(attr_indices(id0[0], id0[1])) ==
90 attr_values.row(attr_indices(id1[0], id1[1]));
94 std::vector<Index> condensed_attr_values_index;
95 condensed_attr_values_index.reserve(attr_values.rows());
96 AttributeArray condensed_attr_values;
97 IndexArray condensed_attr_indices(num_facets, vertex_per_facet);
98 std::vector<IndexEntry> indices(num_facets * vertex_per_facet);
99 std::vector<Index> offsets(num_vertices + 2, 0);
101 for (
auto fi :
range(num_facets)) {
102 for (
auto ci :
range(vertex_per_facet)) {
103 offsets[facets(fi, ci) + 2]++;
106 std::partial_sum(offsets.begin(), offsets.end(), offsets.begin());
108 for (
auto fi :
range(num_facets)) {
109 for (
auto ci :
range(vertex_per_facet)) {
110 auto vi = facets(fi, ci);
111 indices[offsets[vi + 1]++] = {fi, ci};
116 tbb::blocked_range<Index>(0, num_vertices),
117 [&](
const tbb::blocked_range<Index>& tbb_range) {
118 for (
auto vi = tbb_range.begin(); vi != tbb_range.end(); vi++) {
120 indices.data() + offsets[vi],
121 indices.data() + offsets[vi + 1],
126 for (
auto vi :
range(num_vertices)) {
127 const IndexEntry* local_indices = indices.data() + offsets[vi];
128 const Index num_adj_facets = safe_cast<Index>(offsets[vi + 1] - offsets[vi]);
129 for (Index i = 0; i < num_adj_facets; i++) {
130 const auto& curr_entry = local_indices[i];
131 condensed_attr_indices(curr_entry[0], curr_entry[1]) = count;
133 for (Index j = i; j < num_adj_facets; j++) {
134 const auto& next_entry = local_indices[j];
135 if (index_pair_eq(curr_entry, next_entry)) {
136 condensed_attr_indices(next_entry[0], next_entry[1]) = count;
142 condensed_attr_values_index.push_back(attr_indices(curr_entry[0], curr_entry[1]));
147 assert(safe_cast<Index>(condensed_attr_values_index.size()) == count);
149 condensed_attr_values.resize(count, num_cols);
150 for (
auto i :
range(count)) {
151 condensed_attr_values.row(i) = attr_values.row(condensed_attr_values_index[i]);
154 if (new_attr_name ==
"" || new_attr_name == attr_name) {
155 mesh.import_indexed_attribute(attr_name, condensed_attr_values, condensed_attr_indices);
157 mesh.add_indexed_attribute(new_attr_name);
158 mesh.import_indexed_attribute(new_attr_name, condensed_attr_values, condensed_attr_indices);
#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
Main namespace for Lagrange.
Definition: AABBIGL.h:30