16#include <lagrange/Attribute.h>
17#include <lagrange/AttributeTypes.h>
18#include <lagrange/ExactPredicatesShewchuk.h>
19#include <lagrange/IndexedAttribute.h>
20#include <lagrange/Logger.h>
21#include <lagrange/SurfaceMeshTypes.h>
22#include <lagrange/cast_attribute.h>
23#include <lagrange/find_matching_attributes.h>
24#include <lagrange/internal/get_uv_attribute.h>
25#include <lagrange/map_attribute.h>
26#include <lagrange/solver/DirectSolver.h>
27#include <lagrange/triangulate_polygonal_facets.h>
28#include <lagrange/utils/Error.h>
29#include <lagrange/utils/fmt_eigen.h>
30#include <lagrange/views.h>
31#include <lagrange/weld_indexed_attribute.h>
34#include "ThreadPool.h"
35#define MULTI_THREADING_INCLUDED
36using namespace lagrange::texproc::threadpool;
39#include <lagrange/utils/warnoff.h>
40#include <Misha/RegularGrid.h>
41#include <lagrange/utils/warnon.h>
44#include <Eigen/Sparse>
48namespace lagrange::texproc {
52using namespace MishaK;
55template <
typename T,
unsigned N>
56using Vector = MishaK::Point<T, N>;
59static const unsigned int Dim = 3;
62static const unsigned int K = 2;
65using Solver = lagrange::solver::SolverLDLT<Eigen::SparseMatrix<double>>;
69enum class RequiresIndexedTexcoords { Yes, No };
70enum class CheckFlippedUV { Yes, No };
74template <
unsigned int NumChannels,
typename ValueType>
76 image::experimental::View3D<ValueType> texture,
79 unsigned int num_channels =
static_cast<unsigned int>(texture.extent(2));
80 if (num_channels != NumChannels)
la_debug_assert(
"Number of channels don't match");
83 grid.resize(texture.extent(0), texture.extent(1));
84 for (
unsigned int j = 0; j < grid.res(1); j++) {
85 for (
unsigned int i = 0; i < grid.res(0); i++) {
86 for (
unsigned int c = 0; c < NumChannels; c++) {
87 grid(i, j)[c] = texture(i, j, c);
93template <
unsigned int NumChannels,
typename ValueType>
96 image::experimental::View3D<ValueType> texture)
99 for (
unsigned int j = 0; j < grid.res(1); j++) {
100 for (
unsigned int i = 0; i < grid.res(0); i++) {
101 for (
unsigned int c = 0; c < NumChannels; c++) {
102 texture(i, j, c) = grid(i, j)[c];
108template <
typename ValueType>
110 const RegularGrid<K, double>& grid,
111 image::experimental::View3D<ValueType> texture)
114 for (
unsigned int j = 0; j < grid.res(1); j++) {
115 for (
unsigned int i = 0; i < grid.res(0); i++) {
116 texture(i, j, 0) = grid(i, j);
121template <
typename Scalar,
typename Index>
122void check_for_flipped_uv(
const SurfaceMesh<Scalar, Index>& mesh,
AttributeId id)
127 const auto& uv_attr = mesh.template get_indexed_attribute<Scalar>(
id);
130 return {uv_values, uv_indices};
132 const auto& uv_attr = mesh.template get_attribute<Scalar>(
id);
136 "UV attribute must be per-vertex or per-corner.");
142 : std::optional<ConstRowMatrixView<Index>>(
facet_view(mesh))};
146 auto uv_index = [&](Index f,
unsigned int k) {
147 if (uv_mesh.second.has_value()) {
148 return (*uv_mesh.second)(f, k);
154 ExactPredicatesShewchuk predicates;
156 Eigen::RowVector2d p0 = uv_mesh.first.row(uv_index(f, 0)).template
cast<double>();
157 Eigen::RowVector2d p1 = uv_mesh.first.row(uv_index(f, 1)).template
cast<double>();
158 Eigen::RowVector2d p2 = uv_mesh.first.row(uv_index(f, 2)).template
cast<double>();
159 auto r = predicates.
orient2D(p0.data(), p1.data(), p2.data());
163 "The input mesh has flipped UVs:\n p0=({:.3g})\n p1=({:.3g})\n p2=("
165 "Please fix the input mesh before proceeding.",
168 fmt::join(p2,
", ")));
196template <
typename Scalar>
201 double epsilon = 1e-4)
203 if (std::abs(epsilon) < std::numeric_limits<double>().denorm_min()) {
207 Scalar jitter_scale =
static_cast<Scalar>(epsilon / std::max<unsigned int>(width, height));
209 std::uniform_real_distribution<Scalar> dist(-jitter_scale, jitter_scale);
210 for (
auto& x : texcoords_buffer) {
215template <
typename Scalar,
typename Index>
222 size_t num_simplices()
const {
return static_cast<size_t>(mesh.get_num_facets()); }
223 size_t num_vertices()
const {
return static_cast<size_t>(mesh.get_num_vertices()); }
224 size_t num_texcoords()
const {
return texcoords.size() / K; }
229 for (
unsigned int d = 0; d < Dim; d++) {
230 p[d] =
static_cast<double>(vertices[i * Dim + d]);
238 for (
unsigned int k = 0; k < K; k++) {
239 q[k] =
static_cast<double>(texcoords[i * K + k]);
247 for (
unsigned int k = 0; k < K; k++) {
248 q[k] =
static_cast<double>(texcoords[i * K + k]);
254 int vertex_index(
size_t f,
unsigned int k)
const
256 return static_cast<int>(vertex_indices[f * (K + 1) + k]);
259 int texture_index(
size_t f,
unsigned int k)
const
261 switch (texture_element) {
265 default:
la_debug_assert(
"Unsupported texture element type");
return 0;
269 Simplex<double, K, K> simplex_texcoords(
size_t f)
const
271 Simplex<double, K, K> s;
272 for (
unsigned int k = 0; k <= K; k++) {
273 s[k] = texcoord(texture_index(f, k));
278 Simplex<double, K, K> vflipped_simplex_texcoords(
size_t f)
const
280 Simplex<double, K, K> s;
281 for (
unsigned int k = 0; k <= K; k++) {
282 s[k] = vflipped_texcoord(texture_index(f, k));
287 Simplex<double, Dim, K> simplex_vertices(
size_t f)
const
289 Simplex<double, Dim, K> s;
290 for (
unsigned int k = 0; k <= K; k++) {
291 s[k] = vertex(vertex_index(f, k));
296 SimplexIndex<K> facet_indices(
size_t f)
const
298 SimplexIndex<K> simplex;
299 for (
unsigned int k = 0; k <= K; ++k) {
300 simplex[k] =
static_cast<int>(vertex_indices[f * (K + 1) + k]);
313template <
typename Scalar,
typename Index>
316 RequiresIndexedTexcoords requires_indexed_texcoords,
317 CheckFlippedUV check_flipped_uv)
329 texcoord_id = res.value();
334 if (!_mesh.template is_attribute_type<Scalar>(texcoord_id)) {
336 "Input uv coordinates do not have the same scalar type as the input points. Casting "
342 if (requires_indexed_texcoords == RequiresIndexedTexcoords::Yes &&
344 logger().warn(
"UV coordinates are not indexed. Welding.");
346 weld_indexed_attribute(_mesh, texcoord_id);
352 "Numer of corners doesn't match the number of simplices");
354 if (check_flipped_uv == CheckFlippedUV::Yes) {
355 check_for_flipped_uv(_mesh, texcoord_id);
361 auto& uv_attr = _mesh.template ref_indexed_attribute<Scalar>(texcoord_id);
362 wrapper.texcoords = uv_attr.values().ref_all();
363 wrapper.texture_indices = uv_attr.indices().get_all();
366 auto& uv_attr = _mesh.template ref_attribute<Scalar>(texcoord_id);
367 wrapper.texcoords = uv_attr.ref_all();
368 wrapper.texture_indices = {};
369 wrapper.texture_element = uv_attr.get_element_type();
377template <
typename Scalar,
typename Index>
380 static_assert(
sizeof(std::array<Scalar, 2>) == 2 *
sizeof(
Scalar));
382 reinterpret_cast<std::array<Scalar, 2>*
>(wrapper.texcoords.data()),
383 wrapper.num_texcoords());
385 padding = Padding::init<Scalar>(width, height, texcoords);
386 padding.pad(width, height, texcoords);
AttributeElement get_element_type() const
Gets the attribute element type.
Definition Attribute.h:101
lagrange::span< const ValueType > get_all() const
Returns a read-only view of the buffer spanning num elements x num channels.
Definition Attribute.cpp:512
virtual short orient2D(double p1[2], double p2[2], double p3[2]) const
Exact 2D orientation test.
Definition ExactPredicatesShewchuk.cpp:37
A general purpose polygonal mesh class.
Definition SurfaceMesh.h:66
const AttributeBase & get_attribute_base(std::string_view name) const
Gets a read-only reference to the base class of attribute given its name.
Definition SurfaceMesh.cpp:1276
bool is_attribute_indexed(std::string_view name) const
Determines whether the specified attribute is indexed.
Definition SurfaceMesh.cpp:1235
const Attribute< Index > & get_corner_to_vertex() const
Gets a read-only reference to the corner -> vertex id attribute.
Definition SurfaceMesh.cpp:1399
Index get_num_facets() const
Retrieves the number of facets.
Definition SurfaceMesh.h:678
const Attribute< Scalar > & get_vertex_to_position() const
Gets a read-only reference to the vertex -> positions attribute.
Definition SurfaceMesh.cpp:1387
Index get_num_corners() const
Retrieves the number of corners.
Definition SurfaceMesh.h:685
LA_CORE_API spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:40
AttributeId map_attribute_in_place(SurfaceMesh< Scalar, Index > &mesh, AttributeId id, AttributeElement new_element)
Map attribute values to a different element type.
Definition map_attribute.cpp:270
uint32_t AttributeId
Identified to be used to access an attribute.
Definition AttributeFwd.h:73
AttributeElement
Type of element to which the attribute is attached.
Definition AttributeFwd.h:26
@ UV
Mesh attribute must have exactly 2 channels.
Definition AttributeFwd.h:62
@ Scalar
Mesh attribute must have exactly 1 channel.
Definition AttributeFwd.h:56
@ Value
Values that are not attached to a specific element.
Definition AttributeFwd.h:42
@ Indexed
Indexed mesh attributes.
Definition AttributeFwd.h:45
@ Corner
Per-corner mesh attributes.
Definition AttributeFwd.h:37
@ Vertex
Per-vertex mesh attributes.
Definition AttributeFwd.h:28
AttributeId cast_attribute_in_place(SurfaceMesh< Scalar, Index > &mesh, AttributeId attribute_id)
Cast an attribute in place to a different value type.
Definition cast_attribute.cpp:68
std::optional< AttributeId > find_matching_attribute(const SurfaceMesh< Scalar, Index > &mesh, const AttributeMatcher &options)
Finds the first attribute with the specified usage/element type/number of channels.
Definition find_matching_attributes.cpp:37
void triangulate_polygonal_facets(SurfaceMesh< Scalar, Index > &mesh, const TriangulationOptions &options={})
Triangulate polygonal facets of a mesh using a prescribed set of rules.
Definition triangulate_polygonal_facets.cpp:520
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.
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
Eigen::Matrix< Scalar, Eigen::Dynamic, 1 > Vector
Type alias for one-dimensional column Eigen vectors.
Definition views.h:79
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
const Eigen::Map< const RowMatrix< Scalar >, Eigen::Unaligned > ConstRowMatrixView
Type alias for row-major const matrix view.
Definition views.h:75
#define la_runtime_assert(...)
Runtime assertion check.
Definition assert.h:174
#define la_debug_assert(...)
Debug assertion check.
Definition assert.h:194
::nonstd::span< T, Extent > span
A bounds-safe view for sequences of objects.
Definition span.h:27
@ Error
Throw an error if collision is detected.
Definition MappingPolicy.h:24
Definition mesh_utils.h:217