Skip to content

Commit 4460ec0

Browse files
MathiasPaulinnmellado
authored andcommitted
[tests] Add command test to tests/unittest/Core/topomesh.cpp
Co-authored-by: David Vanderhaeghe <github@dlyr.fr> update test
1 parent 18ba1e9 commit 4460ec0

1 file changed

Lines changed: 123 additions & 8 deletions

File tree

tests/unittest/Core/topomesh.cpp

Lines changed: 123 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ using namespace Ra::Core;
1313
using namespace Ra::Core::Utils;
1414
using namespace Ra::Core::Geometry;
1515

16-
bool isSameMesh( Ra::Core::Geometry::TriangleMesh& meshOne,
17-
Ra::Core::Geometry::TriangleMesh& meshTwo ) {
16+
bool isSameMesh( const Ra::Core::Geometry::TriangleMesh& meshOne,
17+
const Ra::Core::Geometry::TriangleMesh& meshTwo ) {
1818

1919
bool result = true;
2020
int i = 0;
@@ -196,13 +196,13 @@ TEST_CASE( "Core/Geometry/TopologicalMesh", "[Core][Core/Geometry][TopologicalMe
196196
using Ra::Core::Geometry::TopologicalMesh;
197197
using Ra::Core::Geometry::TriangleMesh;
198198

199-
using Catmull =
200-
OpenMesh::Subdivider::Uniform::CatmullClarkT<Ra::Core::Geometry::TopologicalMesh>;
201-
using Loop = OpenMesh::Subdivider::Uniform::LoopT<Ra::Core::Geometry::TopologicalMesh>;
199+
// using Catmull =
200+
// OpenMesh::Subdivider::Uniform::CatmullClarkT<Ra::Core::Geometry::TopologicalMesh>;
201+
// using Loop = OpenMesh::Subdivider::Uniform::LoopT<Ra::Core::Geometry::TopologicalMesh>;
202202

203-
using Decimater = OpenMesh::Decimater::DecimaterT<Ra::Core::Geometry::TopologicalMesh>;
204-
using HModQuadric =
205-
OpenMesh::Decimater::ModQuadricT<Ra::Core::Geometry::TopologicalMesh>::Handle;
203+
// using Decimater = OpenMesh::Decimater::DecimaterT<Ra::Core::Geometry::TopologicalMesh>;
204+
// using HModQuadric =
205+
// OpenMesh::Decimater::ModQuadricT<Ra::Core::Geometry::TopologicalMesh>::Handle;
206206

207207
TriangleMesh newMesh;
208208
TriangleMesh newMesh2;
@@ -384,3 +384,118 @@ TEST_CASE( "Core/Geometry/TopologicalMesh/EdgeSplit", "[Core][Core/Geometry][Top
384384
// collapse
385385
// check float attrib value
386386
}
387+
388+
TEST_CASE( "Core/Geometry/TopologicalMesh/Manifold", "[Core][Core/Geometry][TopologicalMesh]" ) {
389+
390+
struct MyNonManifoldCommand {
391+
inline MyNonManifoldCommand( int target ) : targetNonManifoldFaces( target ) {}
392+
inline void initialize( const TriangleMesh& /*triMesh*/ ) {}
393+
inline void process( const std::vector<TopologicalMesh::VertexHandle>& /*face_vhandles*/ ) {
394+
LOG( logINFO ) << "Non Manifold face found";
395+
nonManifoldFaces++;
396+
}
397+
inline void postProcess( TopologicalMesh& /*tm*/ ) {
398+
// Todo : For each non manifold face, remove the vertices that are not part of a face of
399+
// the topomesh For the test, this will reduce the mesh_2 to mesh1
400+
REQUIRE( nonManifoldFaces == targetNonManifoldFaces );
401+
LOG( logINFO ) << "Process non-manifold faces";
402+
}
403+
404+
int nonManifoldFaces {0};
405+
const int targetNonManifoldFaces;
406+
};
407+
408+
VectorArray<Vector3> vertices = {
409+
{0_ra, 0_ra, 0_ra}, {0_ra, 1_ra, 0_ra}, {1_ra, 1_ra, 0_ra}, {1_ra, 0_ra, 0_ra}};
410+
VectorArray<Vector3> normals {
411+
{0_ra, 0_ra, 1_ra}, {0_ra, 0_ra, 1_ra}, {0_ra, 0_ra, 1_ra}, {0_ra, 0_ra, 1_ra}};
412+
VectorArray<Vector3ui> indices {{0, 2, 1}, {0, 3, 2}};
413+
414+
VectorArray<Vector3> vertices_2 = {{0_ra, 0_ra, 0_ra},
415+
{0_ra, 1_ra, 0_ra},
416+
{1_ra, 1_ra, 0_ra},
417+
{1_ra, 0_ra, 0_ra},
418+
{1_ra, 0_ra, 1_ra}};
419+
VectorArray<Vector3> normals_2 {
420+
{0_ra, 0_ra, 1_ra},
421+
{0_ra, 0_ra, 1_ra},
422+
{0_ra, 0_ra, 1_ra},
423+
{0_ra, 0_ra, 1_ra},
424+
{0_ra, -1_ra, 0_ra},
425+
};
426+
427+
VectorArray<Vector3ui> indices_2 {{0, 2, 1}, {0, 3, 2}, {0, 2, 4}};
428+
429+
auto buildMesh = []( const VectorArray<Vector3>& v,
430+
const VectorArray<Vector3>& n,
431+
const VectorArray<Vector3ui>& i ) {
432+
TriangleMesh m;
433+
m.setVertices( v );
434+
m.setNormals( n );
435+
auto& idx = m.getIndicesWithLock();
436+
std::copy( i.begin(), i.end(), std::back_inserter( idx ) );
437+
m.indicesUnlock();
438+
439+
LOG( logINFO ) << " Built a mesh with " << m.vertices().size() << " vertices, "
440+
<< m.normals().size() << " normals and " << m.getIndices().size()
441+
<< " indices.";
442+
443+
return m;
444+
};
445+
446+
auto testConverter =
447+
[]( const TriangleMesh& mesh, const TriangleMesh& mesh2, MyNonManifoldCommand command ) {
448+
// test with functor
449+
LOG( logINFO ) << "Converter with custom command";
450+
TopologicalMesh topo2 {mesh2, command};
451+
auto mesh3 = topo2.toTriangleMesh();
452+
REQUIRE( isSameMesh( mesh, mesh3 ) );
453+
454+
// test without functor
455+
LOG( logINFO ) << "Converter without custom command";
456+
TopologicalMesh topo3 {mesh2};
457+
auto mesh4 = topo3.toTriangleMesh();
458+
REQUIRE( isSameMesh( mesh, mesh4 ) );
459+
return mesh4;
460+
};
461+
462+
using Vector5 = Eigen::Matrix<Scalar, 5, 1>;
463+
VectorArray<Vector5> attrib_array {
464+
{0_ra, 0_ra, 0_ra, 0_ra, 1_ra},
465+
{0_ra, 0_ra, 0_ra, 0_ra, 1_ra},
466+
{0_ra, 0_ra, 0_ra, 0_ra, 1_ra},
467+
{0_ra, -1_ra, 0_ra, 0_ra, 0_ra},
468+
};
469+
470+
// well formed mesh
471+
auto mesh = buildMesh( vertices, normals, indices );
472+
473+
// edge shared by three faces
474+
LOG( logINFO ) << "Test with edge shared by three faces";
475+
auto mesh2 = buildMesh( vertices_2, normals_2, indices_2 );
476+
testConverter( mesh, mesh2, MyNonManifoldCommand( 1 ) ); // we should find 1 non-manifold face
477+
478+
// test with unsupported attribute type
479+
LOG( logINFO ) << "Test with unsupported attribute (all faces are manifold)";
480+
auto mesh3 {mesh}, mesh4 {mesh};
481+
auto handle = mesh3.addAttrib<Vector5>( "vector5_attrib" );
482+
auto& attrib = mesh3.getAttrib( handle );
483+
auto& buf = attrib.getDataWithLock();
484+
buf = attrib_array;
485+
attrib.unlock();
486+
487+
REQUIRE( mesh4.vertexAttribs().hasSameAttribs( mesh.vertexAttribs() ) );
488+
REQUIRE( mesh.vertexAttribs().hasSameAttribs( mesh4.vertexAttribs() ) );
489+
REQUIRE( !mesh4.vertexAttribs().hasSameAttribs( mesh3.vertexAttribs() ) );
490+
REQUIRE( !mesh3.vertexAttribs().hasSameAttribs( mesh4.vertexAttribs() ) );
491+
mesh4 = testConverter(
492+
mesh, mesh3, MyNonManifoldCommand( 0 ) ); // we should find 0 non-manifold face
493+
REQUIRE( mesh4.vertexAttribs().hasSameAttribs( mesh.vertexAttribs() ) );
494+
REQUIRE( mesh.vertexAttribs().hasSameAttribs( mesh4.vertexAttribs() ) );
495+
REQUIRE( !mesh4.vertexAttribs().hasSameAttribs( mesh3.vertexAttribs() ) );
496+
REQUIRE( !mesh3.vertexAttribs().hasSameAttribs( mesh4.vertexAttribs() ) );
497+
498+
// TODO : build a functor that add the faces as independant faces in the topomesh and
499+
// define a manifold mesh that is similar to the result of processing of this non manifold.
500+
//
501+
}

0 commit comments

Comments
 (0)