Lagrange
Loading...
Searching...
No Matches
primitive_test_utils.h
1/*
2 * Copyright 2019 Adobe. All rights reserved.
3 * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License. You may obtain a copy
5 * of the License at http://www.apache.org/licenses/LICENSE-2.0
6 *
7 * Unless required by applicable law or agreed to in writing, software distributed under
8 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9 * OF ANY KIND, either express or implied. See the License for the specific language
10 * governing permissions and limitations under the License.
11 */
12#pragma once
13
14#ifdef LAGRANGE_ENABLE_LEGACY_FUNCTIONS
15 #include <lagrange/ExactPredicatesShewchuk.h>
16 #include <lagrange/Mesh.h>
17 #include <lagrange/mesh_cleanup/detect_degenerate_triangles.h>
18 #include <lagrange/primitive/legacy/generation_utils.h>
19
20 #include <catch2/catch_approx.hpp>
21#endif
22
23#include <lagrange/SurfaceMesh.h>
24#include <lagrange/compute_components.h>
25#include <lagrange/extract_boundary_loops.h>
26#include <lagrange/mesh_cleanup/detect_degenerate_facets.h>
27#include <lagrange/testing/common.h>
28#include <lagrange/topology.h>
29#include <lagrange/uv_mesh.h>
30
31namespace lagrange {
32namespace primitive_test_utils {
33
34template <typename Scalar, typename Index>
35void validate_primitive(SurfaceMesh<Scalar, Index>& mesh, int num_boundaries = 0)
36{
37 REQUIRE(is_vertex_manifold(mesh));
38 REQUIRE(is_edge_manifold(mesh));
39 REQUIRE(compute_components(mesh) == 1);
40
41 const auto bd_loops = lagrange::extract_boundary_loops(mesh);
42 REQUIRE(safe_cast<int>(bd_loops.size()) == num_boundaries);
43}
44
45template <typename Scalar, typename Index>
46void check_degeneracy(SurfaceMesh<Scalar, Index>& mesh)
47{
48 auto degenerate_facets = lagrange::detect_degenerate_facets(mesh);
49 REQUIRE(degenerate_facets.empty());
50
51 for (auto i : range(mesh.get_num_vertices())) {
52 REQUIRE(mesh.count_num_corners_around_vertex(i) > 0);
53 }
54}
55
56template <typename Scalar, typename Index>
57void check_UV(SurfaceMesh<Scalar, Index>& mesh)
58{
59 auto uv_mesh = uv_mesh_view(mesh);
60 uv_mesh.initialize_edges();
61 check_degeneracy(uv_mesh);
62}
63
64#ifdef LAGRANGE_ENABLE_LEGACY_FUNCTIONS
65template <typename MeshType>
66void validate_primitive(MeshType& mesh, int num_boundaries = 0)
67{
68 mesh.initialize_topology();
69 REQUIRE(mesh.is_vertex_manifold());
70 REQUIRE(mesh.is_edge_manifold());
71
72 mesh.initialize_components();
73 REQUIRE(mesh.get_num_components() == 1);
74
75 // Fix geometry to remove boundary loops
76 const auto bd_loops = lagrange::extract_boundary_loops(mesh);
77 REQUIRE(safe_cast<int>(bd_loops.size()) == num_boundaries);
78}
79
80template <typename MeshType>
81void check_degeneracy(MeshType& mesh)
82{
83 lagrange::detect_degenerate_triangles(mesh);
84 REQUIRE(mesh.has_facet_attribute("is_degenerate"));
85 REQUIRE(mesh.get_facet_attribute("is_degenerate").maxCoeff() == Catch::Approx(0.0));
86
87 if (!mesh.is_connectivity_initialized()) {
88 mesh.initialize_connectivity();
89 }
90 for (auto i : range(mesh.get_num_vertices())) {
91 const auto adj_facets = mesh.get_facets_adjacent_to_vertex(i);
92 REQUIRE(adj_facets.size() > 0);
93 }
94}
95
96template <typename MeshType>
97void check_UV(MeshType& mesh)
98{
99 REQUIRE(mesh.is_uv_initialized());
100 auto uv_mesh = mesh.get_uv_mesh();
101 lagrange::detect_degenerate_triangles(*uv_mesh);
102 REQUIRE(uv_mesh->has_facet_attribute("is_degenerate"));
103 REQUIRE(uv_mesh->get_facet_attribute("is_degenerate").maxCoeff() == Catch::Approx(0.0));
104
105 const auto& uvs = uv_mesh->get_vertices();
106 const auto& uv_indices = uv_mesh->get_facets();
107 ExactPredicatesShewchuk predicates;
108 for (const auto f : uv_indices.rowwise()) {
109 Eigen::Matrix<double, 1, 2> p0 = uvs.row(f[0]).template cast<double>();
110 Eigen::Matrix<double, 1, 2> p1 = uvs.row(f[1]).template cast<double>();
111 Eigen::Matrix<double, 1, 2> p2 = uvs.row(f[2]).template cast<double>();
112
113 REQUIRE(predicates.orient2D(p0.data(), p1.data(), p2.data()) == 1);
114 }
115}
116
117template <typename MeshType>
118void check_semantic_labels(const MeshType& mesh)
119{
120 REQUIRE(mesh.has_facet_attribute("semantic_label"));
121
122 const auto& labels = mesh.get_facet_attribute("semantic_label");
123 const auto num_facets = mesh.get_num_facets();
124 for (auto i : range(num_facets)) {
125 const auto l = safe_cast_enum<PrimitiveSemanticLabel>(labels(i, 0));
126 REQUIRE(l != PrimitiveSemanticLabel::UNKNOWN);
127 }
128}
129#endif
130
131} // namespace primitive_test_utils
132} // namespace lagrange
Index get_num_vertices() const
Retrieves the number of vertices.
Definition SurfaceMesh.h:680
Index count_num_corners_around_vertex(Index v) const
Count the number of corners incident to a given vertex.
Definition SurfaceMesh.cpp:2750
Index get_num_facets() const
Retrieves the number of facets.
Definition SurfaceMesh.h:687
bool is_edge_manifold(const SurfaceMesh< Scalar, Index > &mesh)
Check if a mesh is edge-manifold.
Definition topology.cpp:125
bool is_vertex_manifold(const SurfaceMesh< Scalar, Index > &mesh)
Check if a mesh is vertex-manifold.
Definition topology.cpp:98
std::vector< std::vector< Index > > extract_boundary_loops(const SurfaceMesh< Scalar, Index > &mesh)
Extract boundary loops from a surface mesh.
Definition extract_boundary_loops.cpp:24
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.
size_t compute_components(SurfaceMesh< Scalar, Index > &mesh, ComponentOptions options={})
Compute connected components of an input mesh.
Definition compute_components.cpp:99
internal::Range< Index > range(Index end)
Returns an iterable object representing the range [0, end).
Definition range.h:176
constexpr T safe_cast_enum(const U u)
Casting an enum to scalar and vice versa.
Definition safe_cast.h:163
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
Main namespace for Lagrange.
SurfaceMesh< UVScalar, Index > uv_mesh_view(const SurfaceMesh< Scalar, Index > &mesh, const UVMeshOptions &options={})
Extract a UV mesh view from an input mesh.
Definition uv_mesh.cpp:52
std::vector< Index > detect_degenerate_facets(const SurfaceMesh< Scalar, Index > &mesh)
Detects degenerate facets in a mesh.
Definition detect_degenerate_facets.cpp:32