Skip to content
Snippets Groups Projects
Commit 2435630b authored by Philip Trettner's avatar Philip Trettner
Browse files

migrate polymesh tests from glow-tests

parent 84b81bf1
Branches
No related tags found
No related merge requests found
Pipeline #12381 passed
glow @ f1f7299b
Subproject commit 81502c09d72d8a58d38745cf492a31d974150eda
Subproject commit f1f7299ba8453e5fbc2dc7229811eba3071aa31e
polymesh @ a50e12bf
Subproject commit cc1a1619e0b14b230c8036c99227b14d50d8b486
Subproject commit a50e12bfb73f7cf764d954200cc770261e52fb70
typed-geometry @ f2737400
Subproject commit 7deba410bcb9a222072242ee9d839db27bf4d5f7
Subproject commit f2737400016d652e77048e54885e466ce769cb6c
#include <doctest.hh>
#include <random>
#include <glm/ext.hpp>
#include <glm/glm.hpp>
#include <polymesh/Mesh.hh>
#include <polymesh/algorithms.hh>
#include <polymesh/debug.hh>
#include <polymesh/formats/obj.hh>
TEST_CASE("PolyMesh, Basics")
{
polymesh::Mesh m;
auto v0 = m.vertices().add();
auto v1 = m.vertices().add();
auto v2 = m.vertices().add();
auto i = 0;
for (auto vh : m.vertices())
{
CHECK(vh.mesh == &m);
++i;
}
auto j = 0;
for (auto vh : m.vertices())
{
CHECK(vh.mesh == &m);
++j;
}
CHECK(i == 3);
CHECK(i == j);
m.assert_consistency();
auto f1 = m.faces().add(v0, v1, v2);
CHECK(m.faces().size() == 1);
CHECK(m.faces().count() == 1);
m.assert_consistency();
auto v3 = m.vertices().add();
auto f2 = m.faces().add(v0, v2, v3);
CHECK(m.faces().size() == 2);
CHECK(m.faces().count() == 2);
m.assert_consistency();
m.faces().remove(f1);
CHECK(m.faces().size() == 1);
CHECK(m.faces().count() == 1);
m.assert_consistency();
m.faces().remove(f2);
CHECK(m.faces().size() == 0);
CHECK(m.faces().count() == 0);
m.assert_consistency();
}
TEST_CASE("PolyMesh, Properties")
{
using namespace polymesh;
Mesh m;
auto v0 = m.vertices().add();
auto v1 = m.vertices().add();
auto v2 = m.vertices().add();
auto f = m.faces().add(v0, v1, v2);
auto pos = m.vertices().make_attribute_with_default(glm::vec3(7, 7, 7));
auto centroid = m.faces().make_attribute<glm::vec3>();
CHECK(pos[v0] == glm::vec3(7));
CHECK(valence(v0) == 2);
CHECK(valence(v1) == 2);
CHECK(valence(v2) == 2);
CHECK(!v0.faces().empty());
// .faces() contains invalid ones as well!
// CHECK(v0.faces().size() == 1);
// CHECK(v0.faces().count() == 1);
// CHECK(v0.faces().first() == f);
v0[pos] = {1, 2, 3};
v1[pos] = {2, 3, 4};
v2[pos] = {3, 1, 8};
centroid[f] = (pos[v0] + pos[v1] + pos[v2]) / 3.0f;
CHECK(f[centroid] == glm::vec3(2, 2, 5));
// CHECK(f[centroid] == f.adjacent_faces().);
CHECK(f.vertices().min(pos) == glm::vec3(1, 1, 3));
CHECK(f.vertices().max(pos) == glm::vec3(3, 3, 8));
CHECK(f.vertices().avg(pos) == triangle_centroid(f, pos));
auto v3 = m.vertices().add();
auto f2 = m.faces().add(v0, v2, v3);
CHECK(pos[v3] == glm::vec3(7));
f2[centroid] = f[centroid];
CHECK(valence(v0) == 3);
CHECK(valence(v1) == 2);
CHECK(valence(v2) == 3);
CHECK(valence(v3) == 2);
auto pos2 = pos; // copy!
pos2[v0] = {9, 9, 9};
CHECK(pos[v0] == glm::vec3(1, 2, 3));
CHECK(pos2[v0] == glm::vec3(9, 9, 9));
pos[v0] = {8, 8, 8};
CHECK(pos[v0] == glm::vec3(8, 8, 8));
CHECK(pos2[v0] == glm::vec3(9, 9, 9));
}
TEST_CASE("PolyMesh, Grid")
{
auto size = 32;
polymesh::Mesh m;
auto position = m.vertices().make_attribute<glm::vec3>();
std::vector<polymesh::vertex_handle> vs;
for (auto x = 0; x < size; ++x)
for (auto y = 0; y < size; ++y)
{
auto pos = glm::vec3(x, glm::sin(x * y * 1234.12341), y);
auto v = m.vertices().add();
v[position] = pos;
vs.push_back(v);
}
for (auto x = 0; x < size - 1; ++x)
for (auto y = 0; y < size - 1; ++y)
{
auto v00 = vs[(y + 0) * size + (x + 0)];
auto v10 = vs[(y + 0) * size + (x + 1)];
auto v01 = vs[(y + 1) * size + (x + 0)];
auto v11 = vs[(y + 1) * size + (x + 1)];
m.faces().add(v00, v01, v11, v10);
}
m.assert_consistency();
}
TEST_CASE("PolyMesh, GridTopoMod")
{
std::default_random_engine rng(12345);
auto size = 5;
polymesh::Mesh m;
auto position = m.vertices().make_attribute<glm::vec3>();
std::vector<polymesh::vertex_handle> vs;
for (auto x = 0; x < size; ++x)
for (auto y = 0; y < size; ++y)
{
auto pos = glm::vec3(x, 0, y);
auto v = m.vertices().add();
v[position] = pos;
vs.push_back(v);
}
for (auto x = 0; x < size - 1; ++x)
for (auto y = 0; y < size - 1; ++y)
{
auto v00 = vs[(y + 0) * size + (x + 0)];
auto v10 = vs[(y + 0) * size + (x + 1)];
auto v01 = vs[(y + 1) * size + (x + 0)];
auto v11 = vs[(y + 1) * size + (x + 1)];
m.faces().add(v00, v01, v11, v10);
}
m.assert_consistency();
for (auto i = 0; i < 30; ++i)
{
std::uniform_int_distribution<int> op(0, 3);
switch (op(rng))
{
case 0:
{
auto es = m.edges().to_vector();
std::uniform_int_distribution<int> re(0, int(es.size() - 1));
auto e = es[re(rng)];
while (e.is_boundary() || valence(e.vertexA()) <= 2 || valence(e.vertexB()) <= 2)
e = es[re(rng)];
m.edges().rotate_next(e);
m.assert_consistency();
}
break;
case 1:
{
auto es = m.edges().to_vector();
std::uniform_int_distribution<int> re(0, int(es.size() - 1));
auto e = es[re(rng)];
while (e.is_boundary() || valence(e.vertexA()) <= 2 || valence(e.vertexB()) <= 2)
e = es[re(rng)];
m.edges().rotate_prev(e);
m.assert_consistency();
}
break;
case 2:
{
auto hs = m.halfedges().to_vector();
std::uniform_int_distribution<int> re(0, int(hs.size() - 1));
auto h = hs[re(rng)];
while (h.edge().is_boundary() || valence(h.vertex_to()) <= 2 || h.face().vertices().size() <= 3)
h = hs[re(rng)];
m.halfedges().rotate_next(h);
m.assert_consistency();
}
break;
case 3:
{
auto hs = m.halfedges().to_vector();
std::uniform_int_distribution<int> re(0, int(hs.size() - 1));
auto h = hs[re(rng)];
while (h.edge().is_boundary() || valence(h.vertex_from()) <= 2 || h.face().vertices().size() <= 3)
h = hs[re(rng)];
m.halfedges().rotate_prev(h);
m.assert_consistency();
}
break;
}
}
}
TEST_CASE("PolyMesh, GridFuzzer")
{
std::default_random_engine rng(12345);
auto size = 6; // 8
for (auto _ = 0; _ < 2; ++_)
{
polymesh::Mesh m;
auto position = m.vertices().make_attribute<glm::vec3>();
struct Face
{
polymesh::vertex_handle v0;
polymesh::vertex_handle v1;
polymesh::vertex_handle v2;
polymesh::vertex_handle v3;
polymesh::face_handle f0 = {};
polymesh::face_handle f1 = {};
int face_order = -1;
};
std::vector<polymesh::vertex_handle> vs;
for (auto x = 0; x < size; ++x)
for (auto y = 0; y < size; ++y)
{
auto v = m.vertices().add();
vs.push_back(v);
position[v] = {x, 0, y};
}
std::vector<Face> faces;
std::bernoulli_distribution coin(0.5);
for (auto x = 0; x < size - 1; ++x)
for (auto y = 0; y < size - 1; ++y)
{
auto v00 = vs[(y + 0) * size + (x + 0)];
auto v10 = vs[(y + 0) * size + (x + 1)];
auto v01 = vs[(y + 1) * size + (x + 0)];
auto v11 = vs[(y + 1) * size + (x + 1)];
faces.push_back({v00, v01, v11, v10});
faces.back().face_order = coin(rng) ? 0 : coin(rng) ? 1 : 2;
}
std::shuffle(faces.begin(), faces.end(), rng);
m.assert_consistency();
for (auto& f : faces)
{
// print_debug(m);
if (f.face_order == 0)
{
f.f0 = m.faces().add(f.v0, f.v1, f.v2, f.v3);
f.f1 = {};
}
else if (f.face_order == 1)
{
f.f0 = m.faces().add(f.v0, f.v1, f.v2);
f.f1 = m.faces().add(f.v0, f.v2, f.v3);
}
else
{
f.f0 = m.faces().add(f.v1, f.v2, f.v3);
f.f1 = m.faces().add(f.v1, f.v3, f.v0);
}
m.assert_consistency();
}
// flips some faces
for (auto i = 0; i < 100; ++i)
{
std::uniform_int_distribution<> rfi(0, (int)faces.size() - 1);
auto& f = faces[rfi(rng)];
if (f.f0.is_valid()) // remove
{
m.faces().remove(f.f0);
if (f.f1.is_valid())
m.faces().remove(f.f1);
f.f0 = {};
f.f1 = {};
}
else // add
{
auto v0_free = false;
auto v1_free = false;
auto v2_free = false;
auto v3_free = false;
for (auto ff : f.v0.all_faces())
if (ff.is_invalid())
v0_free = true;
for (auto ff : f.v1.all_faces())
if (ff.is_invalid())
v1_free = true;
for (auto ff : f.v2.all_faces())
if (ff.is_invalid())
v2_free = true;
for (auto ff : f.v3.all_faces())
if (ff.is_invalid())
v3_free = true;
assert(v0_free);
assert(v1_free);
assert(v2_free);
assert(v3_free);
if (f.face_order == 0)
{
f.f0 = m.faces().add(f.v0, f.v1, f.v2, f.v3);
f.f1 = {};
}
else if (f.face_order == 1)
{
f.f0 = m.faces().add(f.v0, f.v1, f.v2);
f.f1 = m.faces().add(f.v0, f.v2, f.v3);
}
else
{
f.f0 = m.faces().add(f.v1, f.v2, f.v3);
f.f1 = m.faces().add(f.v1, f.v3, f.v0);
}
}
m.assert_consistency();
}
// compactify
// CAUTION: face_handles are now invalid!
m.compactify();
m.assert_consistency();
// remove some random edges
std::bernoulli_distribution coin_remove_edge(0.1);
for (auto e : m.edges())
if (coin_remove_edge(rng))
{
m.edges().remove(e);
m.assert_consistency();
}
// remove some random vertices
std::bernoulli_distribution coin_remove_vertex(0.1);
for (auto v : m.vertices())
if (coin_remove_vertex(rng))
{
m.vertices().remove(v);
m.assert_consistency();
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment