17#include <lagrange/Edge.h>
18#include <lagrange/Mesh.h>
19#include <lagrange/common.h>
20#include <lagrange/compute_vertex_normal.h>
21#include <lagrange/create_mesh.h>
22#include <lagrange/legacy/inline.h>
23#include <lagrange/mesh_cleanup/remove_degenerate_triangles.h>
24#include <lagrange/mesh_cleanup/remove_duplicate_vertices.h>
25#include <lagrange/primitive/generation_utils.h>
26#include <lagrange/utils/safe_cast.h>
36template <
typename MeshType>
37typename MeshType::VertexArray generate_vertices(
38 typename MeshType::Scalar width,
39 typename MeshType::Scalar height,
40 typename MeshType::Scalar radius,
41 const Eigen::Matrix<ScalarOf<MeshType>, 3, 1>& center);
43template <
typename VertexArray,
typename FacetArray>
44SubdividedMeshData<VertexArray, FacetArray> subdivide_corners(
45 const VertexArray& vertices,
46 const FacetArray& corner_tris,
47 typename FacetArray::Scalar segments);
49template <
typename MeshType>
50typename MeshType::FacetArray generate_facets();
52template <
typename MeshType>
53typename MeshType::FacetArray generate_corner_triangles();
55template <
typename MeshType>
56typename MeshType::FacetArray generate_quads();
58template <
typename MeshType>
59typename MeshType::AttributeArray generate_uvs(
60 typename MeshType::Scalar width,
61 typename MeshType::Scalar height,
62 typename MeshType::Scalar radius);
64template <
typename MeshType>
65void generate_normals(MeshType& mesh);
71 using Index = uint32_t;
79 Index num_segments = 1;
80 Eigen::Matrix<Scalar, 3, 1> center{0, 0, 0};
85 bool output_normals =
true;
105 width = std::max(width,
static_cast<Scalar
>(0.0f));
106 height = std::max(height,
static_cast<Scalar
>(0.0f));
108 std::max(radius,
static_cast<Scalar
>(0.0f)),
109 (std::min(width, height)) /
static_cast<Scalar
>(2.0f));
110 num_segments = std::max(num_segments,
static_cast<Index
>(0));
114template <
typename MeshType>
117 using VertexArray =
typename MeshType::VertexArray;
118 using FacetArray =
typename MeshType::FacetArray;
119 using Scalar =
typename MeshType::Scalar;
120 using Index =
typename MeshType::Index;
121 using VertexType =
typename MeshType::VertexType;
123 config.project_to_valid_range();
128 if (config.width < config.dist_threshold || config.height < config.dist_threshold) {
129 auto mesh = create_empty_mesh<VertexArray, FacetArray>();
130 lagrange::set_uniform_semantic_label(*mesh, PrimitiveSemanticLabel::TOP);
134 auto vertices = Plane::generate_vertices<MeshType>(
139 auto facets = Plane::generate_facets<MeshType>();
140 auto corner_tris = Plane::generate_corner_triangles<MeshType>();
141 auto quads = Plane::generate_quads<MeshType>();
142 auto uvs = Plane::generate_uvs<MeshType>(config.width, config.height, config.radius);
143 FacetArray concat_tris;
145 if (config.radius < config.dist_threshold) {
149 normalize_to_unit_box(uvs);
150 mesh->initialize_uv(uvs, facets);
154 if (config.output_normals) {
155 Plane::generate_normals(*mesh);
159 lagrange::set_uniform_semantic_label(*mesh, PrimitiveSemanticLabel::TOP);
163 }
else if (config.num_segments <= 1) {
164 concat_tris.resize(facets.rows() + corner_tris.rows() + quads.rows(), 3);
165 concat_tris << facets, corner_tris, quads;
170 normalize_to_unit_box(uvs);
171 mesh->initialize_uv(uvs, concat_tris);
173 if (config.width > config.dist_threshold && config.height > config.dist_threshold) {
174 mesh = remove_degenerate_triangles(*mesh);
178 if (config.output_normals) {
179 Plane::generate_normals(*mesh);
183 lagrange::set_uniform_semantic_label(*mesh, PrimitiveSemanticLabel::TOP);
189 Plane::subdivide_corners(vertices, corner_tris,
safe_cast<Index>(config.num_segments));
192 Plane::subdivide_corners(uvs, corner_tris,
safe_cast<Index>(config.num_segments));
194 auto output_vertices = vertex_data.vertices;
195 auto output_uvs = uv_data.vertices;
198 Eigen::Matrix<Index, Eigen::Dynamic, 1> centers = corner_tris.col(0);
199 assert(centers.rows() == 4);
200 for (
auto i :
range(centers.rows())) {
201 VertexType center = vertices.row(centers[i]);
202 Eigen::Matrix<Scalar, Eigen::Dynamic, 2> uv_center = uvs.row(centers[i]);
203 auto vertex_indices = vertex_data.segment_indices[i];
204 auto uv_indices = uv_data.segment_indices[i];
206 for (Index col :
range(size)) {
208 VertexType point = output_vertices.row(vertex_indices[col]);
209 output_vertices.row(vertex_indices[col]) =
210 project_to_sphere(center, point, config.radius);
213 Eigen::Matrix<Scalar, Eigen::Dynamic, 2> uv_point = output_uvs.row(uv_indices[col]);
214 output_uvs.row(uv_indices[col]) = project_to_sphere(uv_center, uv_point, config.radius);
218 concat_tris.resize(facets.rows() + quads.rows() + vertex_data.triangles.rows(), 3);
219 concat_tris << facets, quads, vertex_data.triangles;
223 normalize_to_unit_box(output_uvs);
224 mesh->initialize_uv(output_uvs, concat_tris);
227 if (config.width > config.dist_threshold && config.height > config.dist_threshold) {
228 mesh = remove_degenerate_triangles(*mesh);
232 if (config.output_normals) {
233 Plane::generate_normals(*mesh);
237 lagrange::set_uniform_semantic_label(*mesh, PrimitiveSemanticLabel::TOP);
241template <
typename MeshType>
242std::unique_ptr<MeshType> generate_rounded_plane(
243 typename MeshType::Scalar width,
244 typename MeshType::Scalar height,
245 typename MeshType::Scalar radius,
246 typename MeshType::Index num_segments)
248 using Scalar =
typename RoundedPlaneConfig::Scalar;
249 using Index =
typename RoundedPlaneConfig::Index;
257 return generate_rounded_plane<MeshType>(std::move(config));
262template <
typename MeshType>
263typename MeshType::VertexArray generate_vertices(
264 typename MeshType::Scalar width,
265 typename MeshType::Scalar height,
266 typename MeshType::Scalar radius,
267 const Eigen::Matrix<ScalarOf<MeshType>, 3, 1>& center)
269 typename MeshType::VertexArray vertices(12, 3);
274 -width + radius, 0, height - radius,
275 width - radius, 0, height - radius,
278 width - radius, 0, -height + radius,
279 -width + radius, 0, -height + radius,
282 -width + radius, 0, height,
283 width - radius, 0, height,
284 width, 0, height - radius,
285 -width, 0, height - radius,
288 -width, 0, -height + radius,
289 width, 0, -height + radius,
290 width - radius, 0, -height,
291 -width + radius, 0, -height;
294 return (vertices / 2).rowwise() + center.transpose();
297template <
typename MeshType>
298typename MeshType::FacetArray generate_facets()
300 typename MeshType::FacetArray facets(2, 3);
301 facets << 0, 2, 3, 0, 1, 2;
305template <
typename MeshType>
306typename MeshType::FacetArray generate_corner_triangles()
308 typename MeshType::FacetArray triangles(4, 3);
320template <
typename MeshType>
321typename MeshType::FacetArray generate_quads()
323 typename MeshType::FacetArray quads(8, 3);
324 quads << 0, 4, 5, 0, 5, 1, 0, 3, 8, 0, 8, 7, 1, 6, 9, 1, 9, 2, 3, 2, 10, 3, 10, 11;
328template <
typename MeshType>
329typename MeshType::AttributeArray generate_uvs(
330 const typename MeshType::Scalar width,
331 const typename MeshType::Scalar height,
332 const typename MeshType::Scalar radius)
334 typename MeshType::AttributeArray uvs(12, 2);
335 const auto h = height - 2 * radius;
336 const auto w = width - 2 * radius;
337 const auto r = radius;
341 uvs.row(0) << r, r + h;
342 uvs.row(1) << r + w, r + h;
345 uvs.row(2) << r + w, r;
349 uvs.row(4) << r, h + 2 * r;
350 uvs.row(5) << r + w, h + 2 * r;
351 uvs.row(6) << 2 * r + w, r + h;
352 uvs.row(7) << 0, r + h;
356 uvs.row(9) << 2 * r + w, r;
357 uvs.row(10) << r + w, 0;
364template <
typename VertexArray,
typename FacetArray>
365SubdividedMeshData<VertexArray, FacetArray> subdivide_corners(
366 const VertexArray& vertices,
367 const FacetArray& corner_tris,
368 typename FacetArray::Scalar num_segments)
370 using Index =
typename FacetArray::Scalar;
371 using IndexList = std::vector<Index>;
373 assert(corner_tris.rows() == 4);
374 SubdividedMeshData<VertexArray, FacetArray> subdiv_data;
375 std::vector<IndexList> index_list;
376 FacetArray subdivided_tris(num_segments * 4, 3);
377 VertexArray output_vertices = vertices;
378 IndexList seg_indices;
381 for (Index i = 0; i < 4; i++) {
382 auto triangle = corner_tris.row(i);
383 std::tie(output_vertices, seg_indices) =
384 divide_line_into_segments(output_vertices, triangle[1], triangle[2], num_segments);
386 for (
auto j :
range(num_segments)) {
387 subdivided_tris.row(sub_idx++) << triangle[0], seg_indices[j], seg_indices[j + 1];
389 index_list.push_back(seg_indices);
392 subdiv_data.vertices = output_vertices;
393 subdiv_data.triangles = subdivided_tris;
394 subdiv_data.segment_indices = index_list;
398template <
typename MeshType>
399void generate_normals(MeshType& mesh)
401 typename MeshType::AttributeArray normals(1, 3);
405 mesh.add_indexed_attribute(
"normal");
406 mesh.set_indexed_attribute(
"normal", std::move(normals), std::move(indices));
Index get_num_facets() const
Retrieves the number of facets.
Definition SurfaceMesh.h:687
@ Scalar
Mesh attribute must have exactly 1 channel.
Definition AttributeFwd.h:56
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.
internal::Range< Index > range(Index end)
Returns an iterable object representing the range [0, end).
Definition range.h:176
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
SurfaceMesh< Scalar, Index > generate_rounded_plane(RoundedPlaneOptions settings)
Generate a rounded plane mesh.
Definition generate_rounded_plane.cpp:126
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
void remove_duplicate_vertices(SurfaceMesh< Scalar, Index > &mesh, const RemoveDuplicateVerticesOptions &options={})
Removes duplicate vertices from a mesh.
Definition remove_duplicate_vertices.cpp:33
Definition generate_rounded_plane.h:69
void project_to_valid_range()
Project config setting into valid range.
Definition generate_rounded_plane.h:103
Scalar dist_threshold
Two vertices are considered coinciding iff the distance between them is smaller than dist_threshold.
Definition generate_rounded_plane.h:94