DGtal  1.5.beta
testPolygonalSurface.cpp
Go to the documentation of this file.
1 
31 #include <iostream>
32 #include <algorithm>
33 #include "DGtal/base/Common.h"
34 #include "ConfigTest.h"
35 #include "DGtalCatch.h"
36 #include "DGtal/helpers/StdDefs.h"
37 #include "DGtal/kernel/PointVector.h"
38 #include "DGtal/graph/CUndirectedSimpleGraph.h"
39 #include "DGtal/graph/BreadthFirstVisitor.h"
40 #include "DGtal/shapes/PolygonalSurface.h"
41 #include "DGtal/shapes/MeshHelpers.h"
43 
44 using namespace std;
45 using namespace DGtal;
46 
48 // Functions for testing class PolygonalSurface.
50 
51 
52 
54 {
56  typedef PolygonalSurface< RealPoint > PolygonMesh;
58  PolygonMesh mesh;
59  mesh.addVertex( RealPoint( 0, 0, 0 ) );
60  mesh.addVertex( RealPoint( 1, 0, 0 ) );
61  mesh.addVertex( RealPoint( 0, 1, 0 ) );
62  mesh.addVertex( RealPoint( 1, 1, 0 ) );
63  mesh.addVertex( RealPoint( 0, 0, 1 ) );
64  mesh.addVertex( RealPoint( 1, 0, 1 ) );
65  mesh.addVertex( RealPoint( 0, 1, 1 ) );
66  mesh.addVertex( RealPoint( 1, 1, 1 ) );
67  mesh.addVertex( RealPoint( 1, 0, 2 ) );
68  mesh.addVertex( RealPoint( 0, 0, 2 ) );
69  mesh.addPolygonalFace( PolygonalFace( { 1, 0, 2, 3 } ) );
70  mesh.addPolygonalFace( PolygonalFace( { 0, 1, 5, 4 } ) );
71  mesh.addPolygonalFace( PolygonalFace( { 1, 3, 7, 5 } ) );
72  mesh.addPolygonalFace( PolygonalFace( { 3, 2, 6, 7 } ) );
73  mesh.addPolygonalFace( PolygonalFace( { 2, 0, 4, 6 } ) );
74  mesh.addPolygonalFace( PolygonalFace( { 4, 5, 8, 9 } ) );
75  mesh.build();
76  return mesh;
77 }
78 
79 SCENARIO( "PolygonalSurface< RealPoint3 > build tests", "[polysurf][build]" )
80 {
82  typedef PolygonalSurface< RealPoint > PolygonMesh;
85  typedef PolygonMesh::Arc Arc;
86  typedef PolygonMesh::Face Face;
89  GIVEN( "A box with an open side" ) {
90  PolygonMesh polymesh = makeBox();
91  THEN( "The mesh has 10 vertices, v0 has 3 neighbors, v1 has 3 neighbors, etc" ) {
92  REQUIRE( polymesh.size() == 10 );
93  REQUIRE( polymesh.degree( 0 ) == 3 );
94  REQUIRE( polymesh.degree( 1 ) == 3 );
95  REQUIRE( polymesh.degree( 2 ) == 3 );
96  REQUIRE( polymesh.degree( 3 ) == 3 );
97  REQUIRE( polymesh.degree( 4 ) == 4 );
98  REQUIRE( polymesh.degree( 5 ) == 4 );
99  REQUIRE( polymesh.degree( 6 ) == 3 );
100  REQUIRE( polymesh.degree( 7 ) == 3 );
101  REQUIRE( polymesh.degree( 8 ) == 2 );
102  REQUIRE( polymesh.degree( 9 ) == 2 );
103  }
104  THEN( "Euler number is 1 as is the Euler number of a disk." )
105  {
106  REQUIRE( polymesh.nbVertices() == 10 );
107  REQUIRE( polymesh.nbEdges() == 15 );
108  REQUIRE( polymesh.nbFaces() == 6 );
109  REQUIRE( polymesh.Euler() == 1 );
110  }
111  THEN( "Breadth-first visiting the mesh from vertex 0, visit {0}, then {1,2,4}, then {3,5,6,9}, then {7,8}." )
112  {
113  BreadthFirstVisitor< PolygonMesh > visitor( polymesh, 0 );
114  std::vector<unsigned long> vertices;
115  std::vector<unsigned long> distances;
116  while ( ! visitor.finished() )
117  {
118  vertices.push_back( visitor.current().first );
119  distances.push_back( visitor.current().second );
120  visitor.expand();
121  }
122  REQUIRE( vertices.size() == 10 );
123  REQUIRE( distances.size() == 10 );
124  int expected_vertices[] = { 0, 1, 2, 4, 3, 5, 6, 9, 7, 8 };
125  int expected_distance[] = { 0, 1, 1, 1, 2, 2, 2, 2, 3, 3 };
126  auto itb = vertices.begin();
127  std::sort( itb+1, itb+4 );
128  std::sort( itb+4, itb+8 );
129  std::sort( itb+8, itb+10 );
130  bool vertices_ok
131  = std::equal( vertices.begin(), vertices.end(), expected_vertices );
132  REQUIRE( vertices_ok );
133  bool distances_ok
134  = std::equal( distances.begin(), distances.end(), expected_distance );
135  REQUIRE( distances_ok );
136  }
137  THEN( "The mesh has 6 boundary vertices" ) {
138  VertexRange bv = polymesh.allBoundaryVertices();
139  std::sort( bv.begin(), bv.end() );
140  int expected_bv [] = { 4, 5, 6, 7, 8, 9 };
141  REQUIRE( bv.size() == 6 );
142  bool bv_ok = std::equal( bv.begin(), bv.end(), expected_bv );
143  REQUIRE( bv_ok );
144  }
145  THEN( "The mesh has 6 boundary arcs" ) {
146  ArcRange ba = polymesh.allBoundaryArcs();
147  REQUIRE( ba.size() == 6 );
148  }
149  THEN( "The face along (1,3) is a quadrangle (1,3,7,5)" ) {
150  Arc a13 = polymesh.arc( 1, 3 );
151  Face f = polymesh.faceAroundArc( a13 );
152  ArcRange A = polymesh.arcsAroundFace( f );
153  VertexRange T = polymesh.verticesAroundFace( f );
154  REQUIRE( A.size() == 4 );
155  REQUIRE( T.size() == 4 );
156  REQUIRE( polymesh.head( A[ 0 ] ) == T[ 0 ] );
157  REQUIRE( polymesh.head( A[ 1 ] ) == T[ 1 ] );
158  REQUIRE( polymesh.head( A[ 2 ] ) == T[ 2 ] );
159  REQUIRE( polymesh.head( A[ 3 ] ) == T[ 3 ] );
160  std::sort( T.begin(), T.end() );
161  REQUIRE( T[ 0 ] == 1 );
162  REQUIRE( T[ 1 ] == 3 );
163  REQUIRE( T[ 2 ] == 5 );
164  REQUIRE( T[ 3 ] == 7 );
165  }
166  THEN( "The face along (3,1) is a quadrangle (3,1,0,2)" ) {
167  Arc a31 = polymesh.arc( 3, 1 );
168  Face f = polymesh.faceAroundArc( a31 );
169  VertexRange T = polymesh.verticesAroundFace( f );
170  REQUIRE( T.size() == 4 );
171  std::sort( T.begin(), T.end() );
172  REQUIRE( T[ 0 ] == 0 );
173  REQUIRE( T[ 1 ] == 1 );
174  REQUIRE( T[ 2 ] == 2 );
175  REQUIRE( T[ 3 ] == 3 );
176  }
177  THEN( "The lower part of the mesh has the barycenter (0.5, 0.5, 0.5) " ) {
178  PositionsMap positions = polymesh.positions();
179  RealPoint b;
180  for ( Vertex v = 0; v < 8; ++v )
181  b += positions( v );
182  b /= 8;
183  REQUIRE( b[ 0 ] == 0.5 );
184  REQUIRE( b[ 1 ] == 0.5 );
185  REQUIRE( b[ 2 ] == 0.5 );
186  }
187  THEN( "We can convert the triangulated surface to a mesh and vice versa" ) {
188  Mesh<RealPoint> mesh;
189  MeshHelpers::polygonalSurface2Mesh( polymesh, mesh );
190  PolygonMesh polymesh2;
191  MeshHelpers::mesh2PolygonalSurface( mesh, polymesh2 );
192  REQUIRE( mesh.nbVertex() == polymesh.nbVertices() );
193  REQUIRE( mesh.nbFaces() == polymesh.nbFaces() );
194  REQUIRE( polymesh2.nbVertices() == polymesh.nbVertices() );
195  REQUIRE( polymesh2.nbArcs() == polymesh.nbArcs() );
196  REQUIRE( polymesh2.nbFaces() == polymesh.nbFaces() );
197  }
198  THEN( "We can iterate over the vertices" ) {
199  PositionsMap positions = polymesh.positions();
200  RealPoint exp_positions[] = { { 0,0,0 }, { 1,0,0 }, { 0,1,0 }, { 1,1,0 },
201  { 0,0,1 }, { 1,0,1 }, { 0,1,1 }, { 1,1,1 },
202  { 1,0,2 }, { 0,0,2 } };
203  for ( auto it = polymesh.begin(), itE = polymesh.end(); it != itE; ++it ) {
204  REQUIRE( positions[ *it ] == exp_positions[ *it ] );
205  }
206  }
207  }
208 }
209 
210 SCENARIO( "PolygonalSurface< RealPoint3 > concept check tests", "[polysurf][concepts]" )
211 {
213  typedef PolygonalSurface< RealPoint > PolygonMesh;
214  BOOST_CONCEPT_ASSERT(( concepts::CUndirectedSimpleGraph< PolygonMesh > ));
215 }
216 
Aim: This class is useful to perform a breadth-first exploration of a graph given a starting point or...
const Node & current() const
Aim: This class is defined to represent a surface mesh through a set of vertices and faces....
Definition: Mesh.h:92
Size nbFaces() const
Size nbVertex() const
Aim: Represents a polygon mesh, i.e. a 2-dimensional combinatorial surface whose faces are (topologic...
DGtal is the top-level namespace which contains all DGtal functions and types.
Aim: Represents the concept of local graph: each vertex has neighboring vertices, but we do not neces...
GIVEN("A cubical complex with random 3-cells")
HalfEdgeDataStructure::PolygonalFace PolygonalFace
PolygonalSurface< PointVector< 3, double > > makeBox()
SCENARIO("PolygonalSurface< RealPoint3 > build tests", "[polysurf][build]")
REQUIRE(domain.isInside(aPoint))
TriMesh::VertexRange VertexRange
TriMesh::PositionsMap PositionsMap
TriMesh::Face Face
PointVector< 3, double > RealPoint
TriMesh::ArcRange ArcRange
TriMesh::Vertex Vertex