14#include <lagrange/mesh_convert.h>
16#include <lagrange/IndexedAttribute.h>
17#include <lagrange/MeshTrait.h>
18#include <lagrange/SurfaceMeshTypes.h>
19#include <lagrange/attribute_names.h>
20#include <lagrange/create_mesh.h>
21#include <lagrange/foreach_attribute.h>
22#include <lagrange/internal/fast_edge_sort.h>
23#include <lagrange/utils/Error.h>
24#include <lagrange/utils/assert.h>
25#include <lagrange/utils/strings.h>
26#include <lagrange/views.h>
32namespace mesh_convert_detail {
45template <Policy policy,
typename Scalar,
typename Index,
typename InputMeshType>
46SurfaceMesh<Scalar, Index> to_surface_mesh_internal(InputMeshType&& mesh)
48 using CMeshType = std::remove_reference_t<InputMeshType>;
49 using MeshType = std::decay_t<InputMeshType>;
50 static_assert(MeshTrait<MeshType>::is_mesh(),
"Input type is not Mesh");
51 using AttributeArray =
typename MeshType::AttributeArray;
52 using IndexArray =
typename MeshType::IndexArray;
53 using MeshScalar =
typename MeshType::Scalar;
54 using MeshIndex =
typename MeshType::Index;
56 if constexpr (policy == Policy::Wrap) {
57 using VertexArray =
typename MeshType::VertexArray;
58 using FacetArray =
typename MeshType::FacetArray;
60 std::is_lvalue_reference_v<InputMeshType&&>,
61 "Input mesh type must be a lvalue reference when wrapping a mesh object.");
62 static_assert(VertexArray::IsRowMajor,
"Input vertex array must have row major storage");
63 static_assert(FacetArray::IsRowMajor,
"Input facet array must have row major storage");
66#define LA_X_to_surface_mesh_scalar(_, S) || std::is_same_v<Scalar, S>
69 "Scalar type should be float or double");
70#undef LA_X_to_surface_mesh_scalar
72#define LA_X_to_surface_mesh_index(_, I) || std::is_same_v<Index, I>
75 "Index type should be uint32_t or uint64_t");
76#undef LA_X_to_surface_mesh_index
79 SurfaceMesh<Scalar, Index> new_mesh(
static_cast<Index
>(mesh.get_dim()));
80 if constexpr (policy == Policy::Copy) {
83 new_mesh.add_polygons(
92 }
else if constexpr (policy == Policy::Wrap) {
94 static_assert(std::is_same_v<Scalar, MeshScalar>,
"Mesh scalar type mismatch");
95 static_assert(std::is_same_v<Index, MeshIndex>,
"Mesh index type mismatch");
96 if constexpr (std::is_const_v<CMeshType>) {
97 const auto& vertices = mesh.get_vertices();
98 const auto& facets = mesh.get_facets();
102 new_mesh.wrap_as_const_facets(
107 auto& vertices = mesh.ref_vertices();
108 auto& facets = mesh.ref_facets();
112 new_mesh.wrap_as_facets(
120 if (mesh.is_edge_data_initialized()) {
121 new_mesh.initialize_edges(
123 [&](Index e) -> std::array<Index, 2> {
124 auto v = mesh.get_edge_vertices(static_cast<typename MeshType::Index>(e));
125 return {static_cast<Index>(v[0]), static_cast<Index>(v[1])};
130 auto usage_from_name = [](std::string_view name) {
144 auto get_unique_name = [&](
auto name) -> std::string {
145 if (!new_mesh.has_attribute(name)) {
148 std::string new_name;
149 for (
int cnt = 0; cnt < 1000; ++cnt) {
150 new_name = fmt::format(
"{}.{}", name, cnt);
151 if (!new_mesh.has_attribute(new_name)) {
155 throw Error(fmt::format(
"Could not assign a unique attribute name for: {}", name));
159 auto transfer_attribute = [&](
auto&& name,
auto&& array,
AttributeElement elem) {
160 std::string new_name = get_unique_name(name);
161 decltype(
auto) attr = array->template get<AttributeArray>();
162 if constexpr (policy == Policy::Copy) {
163 new_mesh.template create_attribute<MeshScalar>(
166 usage_from_name(name),
169 }
else if constexpr (policy == Policy::Wrap) {
170 if constexpr (std::is_const_v<CMeshType>) {
171 new_mesh.template wrap_as_const_attribute<MeshScalar>(
174 usage_from_name(name),
176 {attr.data(), static_cast<size_t>(attr.size())});
179 new_mesh.template wrap_as_attribute<MeshScalar>(
182 usage_from_name(name),
184 {attr.data(), static_cast<size_t>(attr.size())});
190 for (
const auto& name : mesh.get_vertex_attribute_names()) {
195 for (
const auto& name : mesh.get_facet_attribute_names()) {
200 for (
const auto& name : mesh.get_corner_attribute_names()) {
205 for (
const auto& name : mesh.get_edge_attribute_names()) {
210 for (
const auto& name : mesh.get_indexed_attribute_names()) {
211 decltype(
auto) attr = mesh.get_indexed_attribute_array(name);
212 decltype(
auto) values = std::get<0>(attr)->template get<AttributeArray>();
213 decltype(
auto) indices = std::get<1>(attr)->template get<IndexArray>();
214 std::string new_name = get_unique_name(name);
216 if constexpr (policy == Policy::Wrap) {
217 static_assert(std::is_same_v<Index, MeshIndex>,
"Mesh attribute index type mismatch");
218 if (std::is_const_v<CMeshType>) {
219 new_mesh.template wrap_as_const_indexed_attribute<MeshScalar>(
221 usage_from_name(name),
224 {values.data(), static_cast<size_t>(values.size())},
225 {indices.data(), static_cast<size_t>(indices.size())});
227 new_mesh.template wrap_as_indexed_attribute<MeshScalar>(
229 usage_from_name(name),
232 {values.data(), static_cast<size_t>(values.size())},
233 {indices.data(), static_cast<size_t>(indices.size())});
235 }
else if constexpr (policy == Policy::Copy) {
236 auto id = new_mesh.template create_attribute<MeshScalar>(
239 usage_from_name(name),
241 auto& new_attr = new_mesh.template ref_indexed_attribute<MeshScalar>(
id);
242 new_attr.values().resize_elements(values.rows());
253template <
typename Scalar,
typename Index,
typename MeshType>
256 return mesh_convert_detail::
257 to_surface_mesh_internal<mesh_convert_detail::Policy::Copy, Scalar, Index>(mesh);
260template <
typename Scalar,
typename Index,
typename MeshType>
263 return mesh_convert_detail::
264 to_surface_mesh_internal<mesh_convert_detail::Policy::Wrap, Scalar, Index>(
265 std::forward<MeshType>(mesh));
268template <
typename MeshType,
typename Scalar,
typename Index>
271 static_assert(MeshTrait<MeshType>::is_mesh(),
"Input type is not Mesh");
272 using VertexArray =
typename MeshType::VertexArray;
273 using FacetArray =
typename MeshType::FacetArray;
274 using IndexArray =
typename MeshType::IndexArray;
275 using AttributeArray =
typename MeshType::AttributeArray;
276 using MeshScalar =
typename MeshType::Scalar;
277 using MeshIndex =
typename MeshType::Index;
279#define LA_X_to_legacy_mesh_scalar(_, S) || std::is_same_v<Scalar, S>
282 "Scalar type should be float or double");
283#undef LA_X_to_legacy_mesh_scalar
285#define LA_X_to_legacy_mesh_index(_, I) || std::is_same_v<Index, I>
288 "Index type should be uint32_t or uint64_t");
289#undef LA_X_to_legacy_mesh_index
294 auto new_mesh = [&] {
295 VertexArray vertices;
297 if (mesh.get_num_vertices() > 0) {
300 if (mesh.get_num_facets() > 0) {
307 std::vector<Index> old_edge_ids;
308 std::vector<MeshIndex> new_edge_ids;
309 if (mesh.has_edges()) {
310 logger().warn(
"Mesh contains edges information. A possible reordering may occur.");
311 new_mesh->initialize_edge_data();
313 mesh.get_num_edges() ==
static_cast<Index
>(new_mesh->get_num_edges()),
314 "Number of edges do not match");
315 const auto num_vertices =
static_cast<size_t>(mesh.get_num_vertices());
316 auto buffer = std::make_unique<uint8_t[]>(
317 (num_vertices + 1) * std::max(
sizeof(Index),
sizeof(MeshIndex)));
319 mesh.get_num_edges(),
320 mesh.get_num_vertices(),
321 [&](Index e) -> std::array<Index, 2> { return mesh.get_edge_vertices(e); },
322 {reinterpret_cast<Index*>(buffer.get()), num_vertices + 1});
324 new_mesh->get_num_edges(),
325 new_mesh->get_num_vertices(),
326 [&](MeshIndex e) -> std::array<MeshIndex, 2> { return new_mesh->get_edge_vertices(e); },
327 {reinterpret_cast<MeshIndex*>(buffer.get()), num_vertices + 1});
333 [&](std::string_view name_view,
auto&& attr) {
334 using AttributeType = std::decay_t<
decltype(attr)>;
335 using ValueType =
typename AttributeType::ValueType;
336 if (mesh.attr_name_is_reserved(name_view)) {
339 std::string name(name_view);
340 AttributeArray vals =
342 switch (attr.get_element_type()) {
344 new_mesh->add_vertex_attribute(name);
345 new_mesh->import_vertex_attribute(name, std::move(vals));
349 new_mesh->add_facet_attribute(name);
350 new_mesh->import_facet_attribute(name, std::move(vals));
354 new_mesh->add_corner_attribute(name);
355 new_mesh->import_corner_attribute(name, std::move(vals));
361 for (Index e = 0; e < mesh.get_num_edges(); ++e) {
362 vals.row(new_edge_ids[e]) =
365 new_mesh->add_edge_attribute(name);
366 new_mesh->import_edge_attribute(name, std::move(vals));
370 logger().warn(
"Cannot transfer value attribute: {}", name);
379 const auto nvpf =
static_cast<size_t>(new_mesh->get_vertex_per_facet());
382 [&](std::string_view name_view,
auto&& attr) {
383 if (mesh.attr_name_is_reserved(name_view)) {
386 std::string name(name_view);
389 new_mesh->add_indexed_attribute(name);
390 new_mesh->import_indexed_attribute(name, std::move(values), std::move(indices));
A general purpose polygonal mesh class.
Definition SurfaceMesh.h:66
Index get_num_vertices() const
Retrieves the number of vertices.
Definition SurfaceMesh.h:671
AttributeId wrap_as_const_vertices(span< const Scalar > vertices_view, Index num_vertices)
Wraps a read-only external buffer as mesh vertices coordinates.
Definition SurfaceMesh.cpp:831
Index get_num_edges() const
Retrieves the number of edges.
Definition SurfaceMesh.h:692
AttributeId wrap_as_vertices(span< Scalar > vertices_view, Index num_vertices)
Wraps a writable external buffer as mesh vertices coordinates.
Definition SurfaceMesh.cpp:807
Index get_num_facets() const
Retrieves the number of facets.
Definition SurfaceMesh.h:678
Index get_vertex_per_facet() const
Retrieves the number of vertex per facet in a regular mesh.
Definition SurfaceMesh.cpp:2130
LA_CORE_API spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:40
AttributeElement
Type of element to which the attribute is attached.
Definition AttributeFwd.h:26
@ Vector
Mesh attribute can have any number of channels (including 1 channel).
Definition AttributeFwd.h:55
@ Normal
Mesh attribute can have dim or dim + 1 channels.
Definition AttributeFwd.h:58
@ Color
Mesh attribute can have 1, 2, 3 or 4 channels.
Definition AttributeFwd.h:61
@ UV
Mesh attribute must have exactly 2 channels.
Definition AttributeFwd.h:62
@ Value
Values that are not attached to a specific element.
Definition AttributeFwd.h:42
@ Edge
Per-edge mesh attributes.
Definition AttributeFwd.h:34
@ Indexed
Indexed mesh attributes.
Definition AttributeFwd.h:45
@ Facet
Per-facet mesh attributes.
Definition AttributeFwd.h:31
@ Corner
Per-corner mesh attributes.
Definition AttributeFwd.h:37
@ Vertex
Per-vertex mesh attributes.
Definition AttributeFwd.h:28
void seq_foreach_named_attribute_read(const SurfaceMesh< Scalar, Index > &mesh, Visitor &&vis)
Applies a function to each attribute of a mesh.
Definition foreach_attribute.h:208
SurfaceMesh< Scalar, Index > to_surface_mesh_wrap(MeshType &&mesh)
Wrap a legacy mesh object as a surface mesh object.
Definition mesh_convert.impl.h:261
SurfaceMesh< ToScalar, ToIndex > cast(const SurfaceMesh< FromScalar, FromIndex > &source_mesh, const AttributeFilter &convertible_attributes={}, std::vector< std::string > *converted_attributes_names=nullptr)
Cast a mesh to a mesh of different scalar and/or index type.
SurfaceMesh< Scalar, Index > to_surface_mesh_copy(const MeshType &mesh)
Convert a legacy mesh object to a surface mesh object.
Definition mesh_convert.impl.h:254
std::unique_ptr< MeshType > to_legacy_mesh(const SurfaceMesh< Scalar, Index > &mesh)
Convert a surface mesh object to a legacy mesh object.
Definition mesh_convert.impl.h:269
ConstRowMatrixView< ValueType > matrix_view(const Attribute< ValueType > &attribute)
Returns a read-only view of a given attribute in the form of an Eigen matrix.
Definition views.cpp:35
ConstRowMatrixView< ValueType > attribute_matrix_view(const SurfaceMesh< Scalar, Index > &mesh, std::string_view name)
Returns a read-only view of a mesh attribute in the form of an Eigen matrix.
Definition views.cpp:96
ConstRowMatrixView< Scalar > vertex_view(const SurfaceMesh< Scalar, Index > &mesh)
Returns a read-only view of the mesh vertices in the form of an Eigen matrix.
Definition views.cpp:156
RowMatrixView< ValueType > attribute_matrix_ref(SurfaceMesh< Scalar, Index > &mesh, std::string_view name)
Returns a writable view of a mesh attribute in the form of an Eigen matrix.
Definition views.cpp:88
RowMatrixView< Scalar > vertex_ref(SurfaceMesh< Scalar, Index > &mesh)
Returns a writable view of the mesh vertices in the form of an Eigen matrix.
Definition views.cpp:150
ConstRowMatrixView< ValueType > reshaped_view(const Attribute< ValueType > &attribute, size_t num_cols)
Returns a read-only view of a given single-channel attribute in the form of an Eigen matrix with a pr...
Definition views.cpp:71
ConstRowMatrixView< Index > facet_view(const SurfaceMesh< Scalar, Index > &mesh)
Returns a read-only view of a mesh facets in the form of an Eigen matrix.
Definition views.cpp:170
RowMatrixView< ValueType > reshaped_ref(Attribute< ValueType > &attribute, size_t num_cols)
Returns a writable view of a given single-channel attribute in the form of an Eigen matrix with a pre...
Definition views.cpp:58
RowMatrixView< Index > facet_ref(SurfaceMesh< Scalar, Index > &mesh)
Returns a writable view of a mesh facets in the form of an Eigen matrix.
Definition views.cpp:162
RowMatrixView< ValueType > matrix_ref(Attribute< ValueType > &attribute)
Returns a writable view of a given attribute in the form of an Eigen matrix.
Definition views.cpp:26
#define LA_SURFACE_MESH_INDEX_X(mode, data)
X Macro arguments to iterate over index types available for the SurfaceMesh<> class.
Definition SurfaceMeshTypes.h:71
#define LA_SURFACE_MESH_SCALAR_X(mode, data)
X Macro arguments to iterate over scalar types available for the SurfaceMesh<> class.
Definition SurfaceMeshTypes.h:91
#define la_runtime_assert(...)
Runtime assertion check.
Definition assert.h:174
LA_CORE_API bool starts_with(std::string_view str, std::string_view prefix)
Checks if the string begins with the given prefix.
Definition strings.cpp:38
constexpr auto safe_cast(SourceType value) -> std::enable_if_t<!std::is_same< SourceType, TargetType >::value, TargetType >
Perform safe cast from SourceType to TargetType, where "safe" means:
Definition safe_cast.h:50
#define LA_IGNORE(x)
Ignore x to avoid an unused variable warning.
Definition warning.h:144
std::vector< Index > fast_edge_sort(Index num_edges, Index num_vertices, Func get_edge, span< Index > vertex_to_first_edge={})
Sort an array of edges using a parallel bucket sort.
Definition fast_edge_sort.h:71
Main namespace for Lagrange.
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
@ Error
Throw an error if collision is detected.
Definition MappingPolicy.h:24
static constexpr std::string_view normal
Normal.
Definition attribute_names.h:27
static constexpr std::string_view color
Color.
Definition attribute_names.h:32
static constexpr std::string_view texcoord
Texture coordinates.
Definition attribute_names.h:37