14#include <lagrange/Mesh.h>
15#include <lagrange/MeshTrait.h>
16#include <lagrange/attributes/map_indexed_attributes.h>
17#include <lagrange/compute_vertex_normal.h>
18#include <lagrange/create_mesh.h>
19#include <lagrange/legacy/inline.h>
21#include <unordered_map>
48template <
typename MeshType>
51 bool use_direction_and_mirror,
52 Eigen::Matrix<ScalarOf<MeshType>, 3, 1> direction,
53 ScalarOf<MeshType> offset_amount,
54 ScalarOf<MeshType> mirror_amount,
55 typename MeshType::Index num_segments = 1)
57 static_assert(MeshTrait<MeshType>::is_mesh(),
"Input type is not Mesh");
59 using Scalar =
typename MeshType::Scalar;
60 using Index =
typename MeshType::Index;
61 using VertexArray =
typename MeshType::VertexArray;
62 using AttributeArray =
typename MeshType::AttributeArray;
63 using UVArray =
typename MeshType::UVArray;
64 using UVIndices =
typename MeshType::UVIndices;
65 using FacetArray =
typename MeshType::FacetArray;
66 using Vector3s = Eigen::Matrix<Scalar, 3, 1>;
68 la_runtime_assert(input_mesh.get_dim() == 3,
"This function only supports 3D meshes.");
70 input_mesh.get_vertex_per_facet() == 3,
71 "This function only supports triangle meshes.");
74 "This function requires the mesh to have edge data pre-initialized.");
77 auto compute_vertex = [](
const Vector3s& vertex,
78 const Vector3s& offset_vector,
79 const Vector3s& mirror_vector,
80 const Vector3s& target_direction,
81 bool with_direction_and_mirror,
83 Vector3s offset_vertex = vertex + amount * offset_vector;
84 if (with_direction_and_mirror) {
85 offset_vertex -= (offset_vertex.dot(target_direction) * amount) * mirror_vector;
91 if (num_segments < 1) num_segments = 1;
92 direction.stableNormalize();
95 Vector3s offset_vector(0.0, 1.0, 0.0);
96 Vector3s mirror_vector(0.0, 0.0, 0.0);
97 AttributeArray vertex_normal;
98 if (use_direction_and_mirror) {
99 offset_vector = offset_amount * direction;
100 mirror_vector = (Scalar(1) - mirror_amount) * direction;
103 std::unique_ptr<MeshType> copied_mesh = wrap_with_mesh<VertexArray, FacetArray>(
104 input_mesh.get_vertices(),
105 input_mesh.get_facets());
107 copied_mesh->export_vertex_attribute(
"normal", vertex_normal);
110 const Index num_input_vertices = input_mesh.get_num_vertices();
111 const Index num_input_facets = input_mesh.get_num_facets();
112 const bool has_uvs = input_mesh.is_uv_initialized();
113 const Index num_input_uvs =
static_cast<Index
>(has_uvs ? input_mesh.get_uv().rows() : 0);
116 Index num_boundary_edges = 0;
117 Index num_boundary_vertices = 0;
118 std::unordered_map<Index, Index>
122 ++num_boundary_edges;
124 boundary_vertices.emplace(v, Index(boundary_vertices.size()));
128 num_boundary_vertices =
static_cast<Index
>(boundary_vertices.size());
135 VertexArray offset_vertices(
136 num_input_vertices * 2 + (num_segments - 1) * num_boundary_vertices,
138 for (Index v = 0; v < num_input_vertices; ++v) {
139 if (!use_direction_and_mirror) {
144 offset_vector = -vertex_normal.row(v).template head<3>() * offset_amount;
146 Vector3s vertex = input_mesh.get_vertices().row(v).template head<3>();
148 offset_vertices.row(v) = vertex;
150 auto offset_vertex = compute_vertex(
155 use_direction_and_mirror,
157 offset_vertices.row(num_input_vertices + v) = offset_vertex;
160 Scalar segment_increment = Scalar(1) /
static_cast<Scalar
>(num_segments);
161 if (num_segments > 1) {
162 auto vb = boundary_vertices.find(v);
163 if (vb != boundary_vertices.end()) {
164 for (Index is = 1; is < num_segments; ++is) {
165 Scalar offset_ratio =
static_cast<Scalar
>(is) * segment_increment;
166 assert(offset_ratio < 1.0);
168 num_input_vertices * 2 +
169 (is - 1) * num_boundary_vertices +
177 use_direction_and_mirror,
189 FacetArray offset_facets((num_input_facets + num_boundary_edges * num_segments) * 2, 3);
190 for (Index f = 0; f < num_input_facets; ++f) {
191 const auto& facet = input_mesh.get_facets().row(f);
192 offset_facets.row(2 * f) = facet;
193 offset_facets.row(2 * f + 1) << facet[0] + num_input_vertices,
194 facet[2] + num_input_vertices,
195 facet[1] + num_input_vertices;
199 Index vbstart = num_input_vertices * 2;
200 for (Index e = 0, f = 2 * num_input_facets; e < input_mesh.
get_num_edges(); ++e) {
203 assert(boundary_vertices.find(edge_vertices[0]) != boundary_vertices.end());
204 assert(boundary_vertices.find(edge_vertices[1]) != boundary_vertices.end());
205 assert(f + 1 < offset_facets.rows());
207 for (Index is = 0; is < num_segments; ++is) {
208 Index vbstart_on_this_segment = vbstart + (is - 1) * num_boundary_vertices;
209 Index vbstart_on_next_segment = vbstart + is * num_boundary_vertices;
210 bool is_first_segment = (is == 0);
211 bool is_last_segment = (is == num_segments - 1);
212 Index v0 = is_first_segment
214 : vbstart_on_this_segment + boundary_vertices[edge_vertices[0]];
215 Index v1 = is_first_segment
217 : vbstart_on_this_segment + boundary_vertices[edge_vertices[1]];
218 Index v2 = is_last_segment
219 ? edge_vertices[0] + num_input_vertices
220 : vbstart_on_next_segment + boundary_vertices[edge_vertices[0]];
221 Index v3 = is_last_segment
222 ? edge_vertices[1] + num_input_vertices
223 : vbstart_on_next_segment + boundary_vertices[edge_vertices[1]];
225 assert(v0 < offset_vertices.rows());
226 assert(v1 < offset_vertices.rows());
227 assert(v2 < offset_vertices.rows());
228 assert(v3 < offset_vertices.rows());
230 offset_facets.row(f++) << v0, v2, v1;
231 offset_facets.row(f++) << v1, v2, v3;
239 const auto& input_uv_values = input_mesh.get_uv();
240 const auto& input_uv_indices = input_mesh.get_uv_indices();
243 UVArray uv_values(num_input_uvs * 2 + (num_segments - 1) * num_boundary_vertices, 2);
244 for (Index u = 0; u < num_input_uvs; ++u) {
246 uv_values.row(u) = uv_values.row(u + num_input_uvs) = input_uv_values.row(u);
249 for (Index f = 0; f < input_mesh.get_facets().rows(); ++f) {
251 const auto& uv_facet = input_mesh.get_uv_indices().row(f);
253 const auto& facet = input_mesh.get_facets().row(f);
255 for (Index fv = 0; fv < 3; ++fv) {
257 auto vb = boundary_vertices.find(v);
258 if (vb != boundary_vertices.end()) {
260 Index uv_index = uv_facet[fv];
261 auto uv_value = input_mesh.get_uv().row(uv_index);
266 for (Index is = 1; is < num_segments; ++is) {
268 num_input_vertices * 2 +
269 (is - 1) * num_boundary_vertices +
270 vb->second) = uv_value;
277 UVIndices uv_facets((input_uv_indices.rows() + num_boundary_edges * num_segments) * 2, 3);
278 for (Index u = 0; u < input_uv_indices.rows(); ++u) {
279 const auto& uv_facet = input_uv_indices.row(u);
280 uv_facets.row(2 * u) = uv_facet;
281 uv_facets.row(2 * u + 1) << uv_facet[0] + num_input_uvs, uv_facet[2] + num_input_uvs,
282 uv_facet[1] + num_input_uvs;
286 Index uvbstart =
static_cast<Index
>(2 * input_uv_values.rows());
287 for (Index e = 0, f_uv = 2 *
static_cast<Index
>(input_uv_indices.rows());
293 assert(f != lagrange::invalid<Index>());
294 const auto& facet = input_mesh.get_facets().row(f);
295 assert((facet.array() < num_input_vertices).all());
296 const auto& uv_facet = input_uv_indices.row(f);
297 assert((uv_facet.array() < num_input_uvs).all());
301 Index uv_index_0 = lagrange::invalid<Index>();
302 Index uv_index_1 = lagrange::invalid<Index>();
303 for (Index i = 0; i < 3; ++i) {
304 Index vtx_index = facet[i];
305 Index uv_index = uv_facet[i];
306 if (vtx_index == edge_vertices[0]) {
307 uv_index_0 = uv_index;
308 }
else if (vtx_index == edge_vertices[1]) {
309 uv_index_1 = uv_index;
312 assert(uv_index_0 != lagrange::invalid<Index>());
313 assert(uv_index_1 != lagrange::invalid<Index>());
315 assert(boundary_vertices.find(edge_vertices[0]) != boundary_vertices.end());
316 assert(boundary_vertices.find(edge_vertices[1]) != boundary_vertices.end());
317 assert(f_uv + 1 < uv_facets.rows());
319 for (Index is = 0; is < num_segments; ++is) {
320 Index uvbstart_on_this_segment = uvbstart + (is - 1) * num_boundary_vertices;
321 Index uvbstart_on_next_segment = uvbstart + is * num_boundary_vertices;
322 bool is_first_segment = (is == 0);
323 bool is_last_segment = (is == num_segments - 1);
325 Index uv0 = is_first_segment ? uv_index_0
326 : uvbstart_on_this_segment +
327 boundary_vertices[edge_vertices[0]];
328 Index uv1 = is_first_segment ? uv_index_1
329 : uvbstart_on_this_segment +
330 boundary_vertices[edge_vertices[1]];
331 Index uv2 = is_last_segment ? uv_index_0 + num_input_vertices
332 : uvbstart_on_next_segment +
333 boundary_vertices[edge_vertices[0]];
334 Index uv3 = is_last_segment ? uv_index_1 + num_input_vertices
335 : uvbstart_on_next_segment +
336 boundary_vertices[edge_vertices[1]];
338 assert(uv0 < uv_values.rows());
339 assert(uv1 < uv_values.rows());
340 assert(uv2 < uv_values.rows());
341 assert(uv3 < uv_values.rows());
343 uv_facets.row(f_uv++) << uv0, uv2, uv1;
344 uv_facets.row(f_uv++) << uv1, uv2, uv3;
350 assert(uv_values.rows() == num_input_uvs * 2 + (num_segments - 1) * num_boundary_vertices);
351 offset_mesh->initialize_uv(std::move(uv_values), std::move(uv_facets));
356 offset_mesh->get_num_vertices() ==
357 num_input_vertices * 2 + num_boundary_vertices * (num_segments - 1));
382template <
typename MeshType>
385 Eigen::Matrix<ScalarOf<MeshType>, 3, 1> direction,
386 ScalarOf<MeshType> offset_amount,
387 ScalarOf<MeshType> mirror_amount,
388 typename MeshType::Index num_segments = 1)
412template <
typename MeshType>
415 ScalarOf<MeshType> offset_amount,
416 typename MeshType::Index num_segments = 1)
421 Eigen::Matrix<ScalarOf<MeshType>, 3, 1>(0.0, 1.0, 0.0),
bool is_boundary_edge(Index e) const
Determines whether the specified edge e is a boundary edge.
Definition: Mesh.h:821
bool is_edge_data_initialized() const
Edge data accessors (const)
Definition: Mesh.h:643
std::array< Index, 2 > get_edge_vertices(Index e) const
Retrieve edge endpoints.
Definition: Mesh.h:730
Index get_one_facet_around_edge(Index e) const
Get the index of one facet around a given edge.
Definition: Mesh.h:782
Index get_num_edges() const
Gets the number of edges.
Definition: Mesh.h:650
AttributeId compute_vertex_normal(SurfaceMesh< Scalar, Index > &mesh, VertexNormalOptions options={})
Compute per-vertex normals based on specified weighting type.
Definition: compute_vertex_normal.cpp:34
#define la_runtime_assert(...)
Runtime assertion check.
Definition: assert.h:169
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
SurfaceMesh< Scalar, Index > thicken_and_close_mesh(SurfaceMesh< Scalar, Index > input_mesh, const ThickenAndCloseOptions &options={})
Thicken a mesh by offsetting it, and close the shape into a thick 3D solid.
Definition: thicken_and_close_mesh.cpp:270