17#include <lagrange/Logger.h>
18#include <lagrange/Mesh.h>
19#include <lagrange/MeshTrait.h>
20#include <lagrange/common.h>
21#include <lagrange/create_mesh.h>
22#include <lagrange/legacy/inline.h>
23#include <lagrange/utils/range.h>
29namespace combine_mesh_list_internal {
31template <
typename MeshTypePtr,
typename MeshType2>
32void combine_all_vertex_attributes(
33 const std::vector<MeshTypePtr>& mesh_list,
34 MeshType2& combined_mesh);
36template <
typename MeshTypePtr,
typename MeshType2>
37void combine_all_facet_attributes(
38 const std::vector<MeshTypePtr>& mesh_list,
39 MeshType2& combined_mesh);
41template <
typename MeshTypePtr,
typename MeshType2>
42void combine_all_corner_attributes(
43 const std::vector<MeshTypePtr>& mesh_list,
44 MeshType2& combined_mesh);
46template <
typename MeshTypePtr,
typename MeshType2>
47void combine_all_edge_attributes(
48 const std::vector<MeshTypePtr>& mesh_list,
49 MeshType2& combined_mesh);
51template <
typename MeshTypePtr,
typename MeshType2>
52void combine_all_edge_attributes(
53 const std::vector<MeshTypePtr>& mesh_list,
54 MeshType2& combined_mesh);
56template <
typename MeshTypePtr,
typename MeshType2>
57void combine_all_indexed_attributes(
58 const std::vector<MeshTypePtr>& mesh_list,
59 MeshType2& combined_mesh);
71template <
typename MeshTypePtr>
72auto combine_mesh_list(
const std::vector<MeshTypePtr>& mesh_list,
bool preserve_attributes =
false)
73 -> std::unique_ptr<std::decay_t<typename std::pointer_traits<MeshTypePtr>::element_type>>
75 static_assert(MeshTrait<MeshTypePtr>::is_mesh_ptr(),
"Input type is not Mesh smart ptr");
76 using MeshType =
typename std::decay_t<typename std::pointer_traits<MeshTypePtr>::element_type>;
77 using Index =
typename MeshType::Index;
78 using Vtype =
typename MeshType::VertexArray;
79 using Ftype =
typename MeshType::FacetArray;
81 if (mesh_list.size() == 0)
return nullptr;
85 auto is_valid = [](
const MeshTypePtr& ptr) {
return ptr !=
nullptr; };
86 if (!std::all_of(mesh_list.begin(), mesh_list.end(), is_valid)) {
87 std::vector<const MeshType*> valid_mesh_list;
88 valid_mesh_list.reserve(mesh_list.size());
89 for (
auto& ptr : mesh_list) {
90 if (ptr ==
nullptr)
continue;
91 valid_mesh_list.push_back(&*ptr);
93 return combine_mesh_list(valid_mesh_list, preserve_attributes);
97 const auto& front_mesh = mesh_list.front();
98 const Index dim = front_mesh->get_dim();
99 const Index vertex_per_facet = front_mesh->get_vertex_per_facet();
100 Index total_vertices(0), total_facets(0);
102 for (
const auto& mesh : mesh_list) {
103 total_vertices += mesh->get_num_vertices();
104 total_facets += mesh->get_num_facets();
107 Vtype V(total_vertices, dim);
108 Ftype F(total_facets, vertex_per_facet);
109 Index curr_v_index(0), curr_f_index(0);
111 for (
const auto& mesh : mesh_list) {
112 assert(mesh->get_dim() == dim);
113 assert(mesh->get_vertex_per_facet() == vertex_per_facet);
115 V.middleRows(curr_v_index, mesh->get_num_vertices()) = mesh->get_vertices();
116 F.middleRows(curr_f_index, mesh->get_num_facets()) =
117 mesh->get_facets().array() + curr_v_index;
119 curr_v_index += mesh->get_num_vertices();
120 curr_f_index += mesh->get_num_facets();
125 if (preserve_attributes) {
126 using namespace combine_mesh_list_internal;
127 combine_all_vertex_attributes(mesh_list, *combined_mesh);
128 combine_all_facet_attributes(mesh_list, *combined_mesh);
129 combine_all_corner_attributes(mesh_list, *combined_mesh);
130 combine_all_edge_attributes(mesh_list, *combined_mesh);
131 combine_all_indexed_attributes(mesh_list, *combined_mesh);
134 return combined_mesh;
137namespace combine_mesh_list_internal {
139template <
typename MeshTypePtr,
typename MeshType2>
140void combine_all_vertex_attributes(
141 const std::vector<MeshTypePtr>& mesh_list,
142 MeshType2& combined_mesh)
144 using MeshType =
typename std::pointer_traits<MeshTypePtr>::element_type;
145 using Index =
typename MeshType::Index;
146 using AttributeArray =
typename MeshType::AttributeArray;
148 const auto& front_mesh = mesh_list.front();
149 const auto total_num_vertices = combined_mesh.get_num_vertices();
151 for (
const auto& attr_name : front_mesh->get_vertex_attribute_names()) {
152 bool can_merge =
true;
153 for (
const auto& mesh : mesh_list) {
154 if (!mesh->has_vertex_attribute(attr_name)) {
155 logger().warn(
"Cannot combine attribute \"{}\"", attr_name);
160 if (!can_merge)
continue;
162 const auto attribute_dim = front_mesh->get_vertex_attribute(attr_name).cols();
163 AttributeArray attr(total_num_vertices, attribute_dim);
166 for (
const auto& mesh : mesh_list) {
167 attr.block(curr_row, 0, mesh->get_num_vertices(), attribute_dim) =
168 mesh->get_vertex_attribute(attr_name);
169 curr_row += mesh->get_num_vertices();
172 combined_mesh.add_vertex_attribute(attr_name);
173 combined_mesh.import_vertex_attribute(attr_name, attr);
177template <
typename MeshTypePtr,
typename MeshType2>
178void combine_all_facet_attributes(
179 const std::vector<MeshTypePtr>& mesh_list,
180 MeshType2& combined_mesh)
182 using MeshType =
typename std::pointer_traits<MeshTypePtr>::element_type;
183 using Index =
typename MeshType::Index;
184 using AttributeArray =
typename MeshType::AttributeArray;
186 const auto& front_mesh = mesh_list.front();
187 const auto total_num_facets = combined_mesh.get_num_facets();
189 for (
const auto& attr_name : front_mesh->get_facet_attribute_names()) {
190 bool can_merge =
true;
191 for (
const auto& mesh : mesh_list) {
192 if (!mesh->has_facet_attribute(attr_name)) {
194 logger().warn(
"Cannot combine facet attribute \"{}\"", attr_name);
198 if (!can_merge)
continue;
200 const auto attribute_dim = front_mesh->get_facet_attribute(attr_name).cols();
201 AttributeArray attr(total_num_facets, attribute_dim);
204 for (
const auto& mesh : mesh_list) {
205 attr.block(curr_row, 0, mesh->get_num_facets(), attribute_dim) =
206 mesh->get_facet_attribute(attr_name);
207 curr_row += mesh->get_num_facets();
210 combined_mesh.add_facet_attribute(attr_name);
211 combined_mesh.import_facet_attribute(attr_name, attr);
215template <
typename MeshTypePtr,
typename MeshType2>
216void combine_all_corner_attributes(
217 const std::vector<MeshTypePtr>& mesh_list,
218 MeshType2& combined_mesh)
220 using MeshType =
typename std::pointer_traits<MeshTypePtr>::element_type;
221 using Index =
typename MeshType::Index;
222 using AttributeArray =
typename MeshType::AttributeArray;
224 const auto& front_mesh = mesh_list.front();
225 const auto total_num_facets = combined_mesh.get_num_facets();
226 const auto vertex_per_facet = combined_mesh.get_vertex_per_facet();
228 for (
const auto& attr_name : front_mesh->get_corner_attribute_names()) {
229 bool can_merge =
true;
230 for (
const auto& mesh : mesh_list) {
231 if (!mesh->has_corner_attribute(attr_name)) {
232 logger().warn(
"Cannot combine corner attribute \"{}\"", attr_name);
237 if (!can_merge)
continue;
239 const auto attribute_dim = front_mesh->get_corner_attribute(attr_name).cols();
240 AttributeArray attr(total_num_facets * vertex_per_facet, attribute_dim);
243 for (
const auto& mesh : mesh_list) {
244 const auto num_facets = mesh->get_num_facets();
245 attr.block(curr_row, 0, num_facets * vertex_per_facet, attribute_dim) =
246 mesh->get_corner_attribute(attr_name);
247 curr_row += num_facets * vertex_per_facet;
250 combined_mesh.add_corner_attribute(attr_name);
251 combined_mesh.import_corner_attribute(attr_name, attr);
255template <
typename MeshTypePtr,
typename MeshType2>
256void combine_all_edge_attributes(
257 const std::vector<MeshTypePtr>& mesh_list,
258 MeshType2& combined_mesh)
260 using MeshType =
typename std::pointer_traits<MeshTypePtr>::element_type;
261 using Index =
typename MeshType::Index;
262 using AttributeArray =
typename MeshType::AttributeArray;
264 const auto& front_mesh = mesh_list.front();
267 for (
const auto& mesh : mesh_list) {
268 if (!mesh->is_edge_data_initialized())
return;
273 const auto total_num_edges = combined_mesh.get_num_edges();
275 for (
const auto& attr_name : front_mesh->get_edge_attribute_names()) {
276 bool can_merge =
true;
277 for (
const auto& mesh : mesh_list) {
278 if (!mesh->has_edge_attribute(attr_name)) {
280 logger().warn(
"Cannot combine edge attribute \"{}\"", attr_name);
284 if (!can_merge)
continue;
286 const auto attribute_dim = front_mesh->get_edge_attribute(attr_name).cols();
287 AttributeArray attr(total_num_edges, attribute_dim);
289 Index vertex_offset = 0;
290 Index facet_offset = 0;
291 Index edge_offset = 0;
292 for (
const auto& mesh : mesh_list) {
293 const auto& per_mesh_attr = mesh->get_edge_attribute(attr_name);
294 for (
auto old_e :
range(mesh->get_num_edges())) {
295 const auto& c = mesh->get_one_corner_around_edge(old_e);
296 const Index f = c / mesh->get_vertex_per_facet();
297 const Index lv = c % mesh->get_vertex_per_facet();
299 const auto new_e = combined_mesh.get_edge(f + facet_offset, lv);
300 attr.row(new_e) = per_mesh_attr.row(old_e);
303 auto old_v = mesh->get_edge_vertices(old_e);
304 auto new_v = combined_mesh.get_edge_vertices(new_e);
305 std::sort(old_v.begin(), old_v.end());
306 std::sort(new_v.begin(), new_v.end());
310 vertex_offset += mesh->get_num_vertices();
311 facet_offset += mesh->get_num_facets();
312 edge_offset += mesh->get_num_edges();
315 combined_mesh.add_edge_attribute(attr_name);
316 combined_mesh.import_edge_attribute(attr_name, attr);
320template <
typename MeshTypePtr,
typename MeshType2>
321void combine_all_indexed_attributes(
322 const std::vector<MeshTypePtr>& mesh_list,
323 MeshType2& combined_mesh)
325 using MeshType =
typename std::pointer_traits<MeshTypePtr>::element_type;
326 using Scalar =
typename MeshType::Scalar;
327 using Index =
typename MeshType::Index;
328 using AttributeArray =
typename MeshType::AttributeArray;
329 using IndexArray =
typename MeshType::IndexArray;
331 const auto& front_mesh = mesh_list.front();
333 for (
const auto& attr_name : front_mesh->get_indexed_attribute_names()) {
334 bool can_merge =
true;
335 auto ref_attr = front_mesh->get_indexed_attribute_array(attr_name);
336 const auto& ref_values = *std::get<0>(ref_attr);
337 const auto& ref_indices = *std::get<1>(ref_attr);
339 if (ref_values.get_scalar_type() != experimental::ScalarToEnum_v<Scalar>) {
340 std::string expected_type = experimental::ScalarToEnum<Scalar>::name;
341 std::string current_type = experimental::enum_to_name(ref_values.get_scalar_type());
343 "Cannot combined indexed attribute ({}) with custom Scalar type \"{}\". "
350 if (ref_indices.get_scalar_type() != experimental::ScalarToEnum_v<Index>) {
351 std::string expected_type = experimental::ScalarToEnum<Index>::name;
352 std::string current_type = experimental::enum_to_name(ref_indices.get_scalar_type());
354 "Cannot combined indexed attribute ({}) with custom Index type \"{}\". "
362 Index combined_num_values = 0;
363 Index combined_num_indices = 0;
365 for (
const auto& mesh : mesh_list) {
366 if (!mesh->has_indexed_attribute(attr_name)) {
368 logger().warn(
"Cannot combine indexed attribute \"{}\"", attr_name);
371 auto attr = mesh->get_indexed_attribute_array(attr_name);
372 const auto& values = *std::get<0>(attr);
373 const auto& indices = *std::get<1>(attr);
375 if (values.get_scalar_type() != ref_values.get_scalar_type()) {
377 logger().warn(
"Cannot combine indexed attribute because value type mismatch.");
380 if (indices.get_scalar_type() != ref_indices.get_scalar_type()) {
382 logger().warn(
"Cannot combine indexed attribute because index type mismatch.");
386 combined_num_values += safe_cast<Index>(values.rows());
387 combined_num_indices += safe_cast<Index>(indices.rows());
389 if (!can_merge)
continue;
391 AttributeArray combined_values(combined_num_values, ref_values.cols());
392 IndexArray combined_indices(combined_num_indices, ref_indices.cols());
394 Index curr_value_row = 0;
395 Index curr_index_row = 0;
396 for (
const auto& mesh : mesh_list) {
397 auto attr = mesh->get_indexed_attribute_array(attr_name);
398 const auto& values = *std::get<0>(attr);
399 const auto& indices = *std::get<1>(attr);
401 combined_values.block(curr_value_row, 0, values.rows(), values.cols()) =
402 values.template view<AttributeArray>();
403 combined_indices.block(curr_index_row, 0, indices.rows(), indices.cols()) =
404 indices.template view<IndexArray>().array() + curr_value_row;
406 curr_value_row += safe_cast<Index>(values.rows());
407 curr_index_row += safe_cast<Index>(indices.rows());
410 combined_mesh.add_indexed_attribute(attr_name);
411 combined_mesh.import_indexed_attribute(
413 std::move(combined_values),
414 std::move(combined_indices));
void initialize_edge_data()
Edge data initialization.
Definition: Mesh.h:633
LA_CORE_API spdlog::logger & logger()
Retrieves the current logger.
Definition: Logger.cpp:40
#define la_debug_assert(...)
Debug assertion check.
Definition: assert.h:189
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