15#include <lagrange/SurfaceMesh.h>
16#include <lagrange/foreach_attribute.h>
17#include <lagrange/utils/invalid.h>
18#include <lagrange/utils/safe_cast.h>
21#include <lagrange/utils/warnoff.h>
22#include <catch2/catch_test_macros.hpp>
23#include <catch2/matchers/catch_matchers_contains.hpp>
24#include <lagrange/utils/warnon.h>
31#include <unordered_set>
34namespace lagrange::testing {
38template <
typename Index>
41 using namespace lagrange;
43 for (Index x = 0; x < Index(func.size()); ++x) {
44 const Index y = func[x];
45 if (y >= first && y < last) {
50 return std::none_of(inv.begin(), inv.end(), [&](Index y) { return y == invalid<Index>(); });
55template <
typename Index>
58 using namespace lagrange;
60 for (Index x = 0; x < Index(func.size()); ++x) {
61 const Index y = func[x];
62 if (y >= first && y < last) {
74template <
typename Index>
77 return std::all_of(func.begin(), func.end(), [&](Index y) { return first <= y && y < last; });
80template <
typename Index>
83 return std::all_of(func.begin(), func.end(), [&](Index y) {
84 return (first <= y && y < last) || y == lagrange::invalid<Index>();
88template <
typename Index>
91 return is_in_range(func, first, last) && is_restriction_surjective(func, first, last);
94template <
typename Index>
97 return is_in_range(func, first, last) && is_restriction_injective(func, first, last);
100template <
typename MeshType>
101void check_mesh(
const MeshType& mesh)
103 using namespace lagrange;
104 using Index =
typename MeshType::Index;
105 const Index nv = mesh.get_num_vertices();
106 const Index nf = mesh.get_num_facets();
107 const Index nc = mesh.get_num_corners();
108 const Index ne = mesh.get_num_edges();
111 for (Index f = 0; f < nf; ++f) {
112 const Index c0 = mesh.get_facet_corner_begin(f);
113 const Index c1 = mesh.get_facet_corner_end(f);
115 for (Index c = c0; c < c1; ++c) {
116 const Index v = mesh.get_corner_vertex(c);
117 REQUIRE(mesh.get_corner_facet(c) == f);
118 REQUIRE((v >= 0 && v < nv));
124 REQUIRE(attr.get_num_elements() == nv);
127 REQUIRE(attr.get_num_elements() == nf);
130 REQUIRE(attr.get_num_elements() == nc);
135 using AttributeType = std::decay_t<
decltype(attr)>;
136 using ValueType =
typename AttributeType::ValueType;
138 auto usage = attr.get_usage();
150 REQUIRE(std::is_same_v<ValueType, Index>);
151 if constexpr (std::is_same_v<ValueType, Index>) {
152 if constexpr (AttributeType::IsIndexed) {
153 REQUIRE(is_in_range_or_invalid<ValueType>(attr.values().get_all(), 0, n));
155 REQUIRE(is_in_range_or_invalid<ValueType>(attr.get_all(), 0, n));
163 if (mesh.is_hybrid()) {
167 REQUIRE(mesh.is_regular());
173 if (mesh.has_edges()) {
175 auto c2e = mesh.template get_attribute<Index>(mesh.attr_id_corner_to_edge()).get_all();
177 mesh.template get_attribute<Index>(mesh.attr_id_edge_to_first_corner()).get_all();
179 mesh.template get_attribute<Index>(mesh.attr_id_vertex_to_first_corner()).get_all();
180 auto next_around_edge =
181 mesh.template get_attribute<Index>(mesh.attr_id_next_corner_around_edge()).get_all();
182 auto next_around_vertex =
183 mesh.template get_attribute<Index>(mesh.attr_id_next_corner_around_vertex()).get_all();
184 REQUIRE(is_surjective<Index>(c2e, 0, ne));
185 REQUIRE(is_injective<Index>(e2c, 0, nc));
186 REQUIRE(is_in_range_or_invalid<Index>(v2c, 0, nc));
188 is_restriction_injective<Index>(
194 std::set<std::pair<Index, Index>> edges;
195 for (Index f = 0; f < nf; ++f) {
196 for (Index lv0 = 0, s = mesh.get_facet_size(f); lv0 < s; ++lv0) {
197 const Index lv1 = (lv0 + 1) % s;
198 const Index v0 = mesh.get_facet_vertex(f, lv0);
199 const Index v1 = mesh.get_facet_vertex(f, lv1);
200 edges.emplace(std::min(v0, v1), std::max(v0, v1));
203 std::vector<std::array<Index, 2>> mesh_edges;
204 for (Index e = 0; e < ne; ++e) {
205 auto v = mesh.get_edge_vertices(e);
206 mesh_edges.push_back({v[0], v[1]});
208 REQUIRE(edges.size() == e2c.size());
212 const Index f = mesh.get_corner_facet(c);
213 const Index first_corner = mesh.get_facet_corner_begin(f);
214 const Index s = mesh.get_facet_size(f);
215 const Index lv0 = c - first_corner;
216 const Index lv1 = (lv0 + 1) % s;
217 const Index v0 = mesh.get_facet_vertex(f, lv0);
218 const Index v1 = mesh.get_facet_vertex(f, lv1);
219 edges.emplace(std::min(v0, v1), std::max(v0, v1));
221 REQUIRE(edges.size() == e2c.size());
224 for (Index f = 0; f < nf; ++f) {
225 const Index first_corner = mesh.get_facet_corner_begin(f);
226 for (Index lv0 = 0, s = mesh.get_facet_size(f); lv0 < s; ++lv0) {
227 const Index v0 = mesh.get_facet_vertex(f, lv0);
228 const Index c = first_corner + lv0;
229 const Index e = c2e[c];
230 const Index c_other = e2c[e];
231 const Index v_other = mesh.get_corner_vertex(c_other);
234 REQUIRE_THAT(mesh_edges[e], Catch::Matchers::Contains(v0));
235 REQUIRE_THAT(mesh_edges[e], Catch::Matchers::Contains(v_other));
240 std::vector<std::unordered_set<Index>> corners_around_vertex(nv);
241 std::vector<std::unordered_set<Index>> corners_around_edge(ne);
242 std::vector<std::unordered_set<Index>> facets_around_vertex(nv);
243 std::vector<std::unordered_set<Index>> facets_around_edge(ne);
244 for (Index f = 0; f < nf; ++f) {
245 const Index first_corner = mesh.get_facet_corner_begin(f);
246 for (Index lv = 0, s = mesh.get_facet_size(f); lv < s; ++lv) {
247 const Index v = mesh.get_facet_vertex(f, lv);
248 const Index c = first_corner + lv;
249 const Index e = c2e[c];
250 REQUIRE(mesh.get_edge(f, lv) == e);
251 REQUIRE(mesh.get_corner_edge(c) == e);
252 REQUIRE(corners_around_vertex[v].count(c) == 0);
253 REQUIRE(corners_around_edge[e].count(c) == 0);
254 corners_around_vertex[v].insert(c);
255 corners_around_edge[e].insert(c);
256 facets_around_vertex[v].insert(f);
257 facets_around_edge[e].insert(f);
260 std::unordered_set<Index> corners_around;
261 std::unordered_set<Index> facets_around;
262 for (Index v = 0; v < nv; ++v) {
263 corners_around.clear();
264 facets_around.clear();
265 const Index c0 = v2c[v];
266 REQUIRE(mesh.get_first_corner_around_vertex(v) == c0);
267 REQUIRE(mesh.get_one_corner_around_vertex(v) == c0);
268 for (Index ci = c0; ci !=
invalid<Index>(); ci = next_around_vertex[ci]) {
269 REQUIRE(mesh.get_next_corner_around_vertex(ci) == next_around_vertex[ci]);
270 REQUIRE(corners_around_vertex[v].count(ci));
271 REQUIRE(corners_around.count(ci) == 0);
272 corners_around.insert(ci);
274 mesh.foreach_corner_around_vertex(v, [&](Index c) {
275 REQUIRE(corners_around.count(c));
277 mesh.foreach_facet_around_vertex(v, [&](Index f) {
278 REQUIRE(facets_around_vertex[v].count(f));
279 facets_around.insert(f);
281 REQUIRE(corners_around.size() == corners_around_vertex[v].size());
282 REQUIRE(facets_around.size() == facets_around_vertex[v].size());
284 corners_around.size() ==
287 for (Index e = 0; e < ne; ++e) {
288 corners_around.clear();
289 facets_around.clear();
290 const Index c0 = e2c[e];
291 REQUIRE(mesh.get_first_corner_around_edge(e) == c0);
292 REQUIRE(mesh.get_one_corner_around_edge(e) == c0);
293 for (Index ci = c0; ci !=
invalid<Index>(); ci = next_around_edge[ci]) {
294 REQUIRE(mesh.get_next_corner_around_edge(ci) == next_around_edge[ci]);
295 REQUIRE(corners_around_edge[e].count(ci));
296 REQUIRE(corners_around.count(ci) == 0);
297 corners_around.insert(ci);
299 mesh.foreach_corner_around_edge(e, [&](Index c) { REQUIRE(corners_around.count(c)); });
301 mesh.foreach_facet_around_edge(e, [&](Index f) {
302 REQUIRE(facets_around_edge[e].count(f));
303 facets_around.insert(f);
308 REQUIRE(mesh.get_one_facet_around_edge(e) == first_facet);
309 REQUIRE(corners_around.size() == corners_around_edge[e].size());
310 REQUIRE(facets_around.size() == facets_around_edge[e].size());
312 corners_around.size() ==
safe_cast<size_t>(mesh.count_num_corners_around_edge(e)));
313 if (mesh.is_boundary_edge(e)) {
314 REQUIRE(corners_around.size() == 1);
constexpr AttributeId invalid_attribute_id()
Invalid attribute id.
Definition AttributeFwd.h:76
@ CornerIndex
Single channel integer attribute indexing a mesh corner.
Definition AttributeFwd.h:65
@ VertexIndex
Single channel integer attribute indexing a mesh vertex.
Definition AttributeFwd.h:63
@ EdgeIndex
Single channel integer attribute indexing a mesh edge.
Definition AttributeFwd.h:66
@ FacetIndex
Single channel integer attribute indexing a mesh facet.
Definition AttributeFwd.h:64
void seq_foreach_attribute_read(const SurfaceMesh< Scalar, Index > &mesh, Visitor &&vis)
Applies a function to each attribute of a mesh.
Definition foreach_attribute.h:233
::nonstd::span< T, Extent > span
A bounds-safe view for sequences of objects.
Definition span.h:27
constexpr T invalid()
You can use invalid<T>() to get a value that can represent "invalid" values, such as invalid indices ...
Definition invalid.h:40
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