DGtal 1.3.0
Loading...
Searching...
No Matches
Typedefs | Functions
testHalfEdgeDataStructure.cpp File Reference
#include <iostream>
#include <algorithm>
#include "DGtal/base/Common.h"
#include "ConfigTest.h"
#include "DGtalCatch.h"
#include "DGtal/helpers/StdDefs.h"
#include "DGtal/topology/HalfEdgeDataStructure.h"

Go to the source code of this file.

Typedefs

typedef HalfEdgeDataStructure::Triangle Triangle
 
typedef HalfEdgeDataStructure::PolygonalFace PolygonalFace
 
typedef HalfEdgeDataStructure::Edge Edge
 
typedef HalfEdgeDataStructure::Arc ArcT
 
typedef HalfEdgeDataStructure::VertexIndexRange VertexIndexRange
 
typedef HalfEdgeDataStructure::Size Size
 

Functions

HalfEdgeDataStructure makeTwoTriangles ()
 
HalfEdgeDataStructure makeThreeTriangles ()
 
HalfEdgeDataStructure makeTetrahedron ()
 
HalfEdgeDataStructure makeOctahedron ()
 
HalfEdgeDataStructure makeRibbonWithHole ()
 
HalfEdgeDataStructure makeTriangulatedDisk ()
 
HalfEdgeDataStructure makePyramid ()
 
HalfEdgeDataStructure makeCube ()
 
HalfEdgeDataStructure makeBox ()
 
 SCENARIO ("HalfEdgeDataStructure build", "[halfedge][build]")
 
 SCENARIO ("HalfEdgeDataStructure neighboring relations", "[halfedge][neighbors]")
 
 SCENARIO ("HalfEdgeDataStructure flips", "[halfedge][flips]")
 
 SCENARIO ("HalfEdgeDataStructure splits", "[halfedge][splits]")
 
 SCENARIO ("HalfEdgeDataStructure merges", "[halfedge][merges]")
 

Detailed Description

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Author
Jacques-Olivier Lachaud (jacqu.nosp@m.es-o.nosp@m.livie.nosp@m.r.la.nosp@m.chaud.nosp@m.@uni.nosp@m.v-sav.nosp@m.oie..nosp@m.fr ) Laboratory of Mathematics (CNRS, UMR 5127), University of Savoie, France
Date
2017/02/04

Functions for testing class HalfEdgeDataStructure.

This file is part of the DGtal library.

Definition in file testHalfEdgeDataStructure.cpp.

Typedef Documentation

◆ ArcT

Definition at line 48 of file testHalfEdgeDataStructure.cpp.

◆ Edge

Definition at line 47 of file testHalfEdgeDataStructure.cpp.

◆ PolygonalFace

Definition at line 46 of file testHalfEdgeDataStructure.cpp.

◆ Size

Definition at line 50 of file testHalfEdgeDataStructure.cpp.

◆ Triangle

Definition at line 45 of file testHalfEdgeDataStructure.cpp.

◆ VertexIndexRange

Definition at line 49 of file testHalfEdgeDataStructure.cpp.

Function Documentation

◆ makeBox()

HalfEdgeDataStructure makeBox ( )

Definition at line 168 of file testHalfEdgeDataStructure.cpp.

169{
170 std::vector< PolygonalFace > faces( 6 );
171 faces[ 0 ] = PolygonalFace( { 1, 0, 2, 3 } );
172 faces[ 1 ] = PolygonalFace( { 0, 1, 5, 4 } );
173 faces[ 2 ] = PolygonalFace( { 1, 3, 7, 5 } );
174 faces[ 3 ] = PolygonalFace( { 3, 2, 6, 7 } );
175 faces[ 4 ] = PolygonalFace( { 2, 0, 4, 6 } );
176 faces[ 5 ] = PolygonalFace( { 4, 5, 8, 9 } );
178 mesh.build( faces );
179 return mesh;
180}
Aim: This class represents an half-edge data structure, which is a structure for representing the top...
bool build(const Size num_vertices, const std::vector< Triangle > &triangles, const std::vector< Edge > &edges)
HalfEdgeDataStructure::PolygonalFace PolygonalFace

References DGtal::HalfEdgeDataStructure::build().

Referenced by SCENARIO().

◆ makeCube()

HalfEdgeDataStructure makeCube ( )

Definition at line 154 of file testHalfEdgeDataStructure.cpp.

155{
156 std::vector< PolygonalFace > faces( 6 );
157 faces[ 0 ] = PolygonalFace( { 1, 0, 2, 3 } );
158 faces[ 1 ] = PolygonalFace( { 0, 1, 5, 4 } );
159 faces[ 2 ] = PolygonalFace( { 1, 3, 7, 5 } );
160 faces[ 3 ] = PolygonalFace( { 3, 2, 6, 7 } );
161 faces[ 4 ] = PolygonalFace( { 2, 0, 4, 6 } );
162 faces[ 5 ] = PolygonalFace( { 4, 5, 7, 6 } );
164 mesh.build( faces );
165 return mesh;
166}

References DGtal::HalfEdgeDataStructure::build().

Referenced by SCENARIO().

◆ makeOctahedron()

HalfEdgeDataStructure makeOctahedron ( )

Definition at line 90 of file testHalfEdgeDataStructure.cpp.

91{
92 std::vector< Triangle > triangles( 8 );
93 triangles[0].v = { 0, 1, 2 };
94 triangles[1].v = { 0, 2, 3 };
95 triangles[2].v = { 0, 3, 4 };
96 triangles[3].v = { 0, 4, 1 };
97 triangles[4].v = { 5, 2, 1 };
98 triangles[5].v = { 5, 3, 2 };
99 triangles[6].v = { 5, 4, 3 };
100 triangles[7].v = { 5, 1, 4 };
102 mesh.build( triangles );
103 return mesh;
104}

References DGtal::HalfEdgeDataStructure::build().

Referenced by SCENARIO().

◆ makePyramid()

HalfEdgeDataStructure makePyramid ( )

Definition at line 141 of file testHalfEdgeDataStructure.cpp.

142{
143 std::vector< PolygonalFace > faces( 5 );
144 faces[ 0 ] = PolygonalFace( { 0, 3, 2, 1 } );
145 faces[ 1 ] = PolygonalFace( { 0, 1, 4 } );
146 faces[ 2 ] = PolygonalFace( { 1, 2, 4 } );
147 faces[ 3 ] = PolygonalFace( { 2, 3, 4 } );
148 faces[ 4 ] = PolygonalFace( { 3, 0, 4 } );
150 mesh.build( faces );
151 return mesh;
152}

References DGtal::HalfEdgeDataStructure::build().

Referenced by SCENARIO().

◆ makeRibbonWithHole()

HalfEdgeDataStructure makeRibbonWithHole ( )

Definition at line 106 of file testHalfEdgeDataStructure.cpp.

107{
108 std::vector< Triangle > triangles( 6 );
109 triangles[0].v = { 0, 1, 2 };
110 triangles[1].v = { 2, 1, 3 };
111 triangles[2].v = { 2, 3, 4 };
112 triangles[3].v = { 4, 3, 5 };
113 triangles[4].v = { 4, 5, 0 };
114 triangles[5].v = { 0, 5, 1 };
115 std::vector< Edge > edges;
116 const auto kNumVertices
119 mesh.build( kNumVertices, triangles, edges );
120 return mesh;
121}
static Size getUnorderedEdgesFromTriangles(const std::vector< Triangle > &triangles, std::vector< Edge > &edges_out)
std::pair< typename graph_traits< DGtal::DigitalSurface< TDigitalSurfaceContainer > >::edge_iterator, typename graph_traits< DGtal::DigitalSurface< TDigitalSurfaceContainer > >::edge_iterator > edges(const DGtal::DigitalSurface< TDigitalSurfaceContainer > &digSurf)

References DGtal::HalfEdgeDataStructure::build(), and DGtal::HalfEdgeDataStructure::getUnorderedEdgesFromTriangles().

Referenced by SCENARIO().

◆ makeTetrahedron()

HalfEdgeDataStructure makeTetrahedron ( )

Definition at line 77 of file testHalfEdgeDataStructure.cpp.

78{
79 std::vector< Triangle > triangles( 4 );
80 triangles[0].v = { 0, 1, 2 };
81 triangles[1].v = { 2, 1, 3 };
82 triangles[2].v = { 2, 3, 0 };
83 triangles[3].v = { 0, 3, 1 };
84
86 mesh.build( triangles );
87 return mesh;
88}

References DGtal::HalfEdgeDataStructure::build().

Referenced by SCENARIO().

◆ makeThreeTriangles()

HalfEdgeDataStructure makeThreeTriangles ( )

Definition at line 65 of file testHalfEdgeDataStructure.cpp.

66{
67 std::vector< Triangle > triangles( 3 );
68 triangles[0].v = { 0, 1, 2 };
69 triangles[1].v = { 2, 1, 3 };
70 triangles[2].v = { 2, 3, 0 };
71
73 mesh.build( triangles );
74 return mesh;
75}

References DGtal::HalfEdgeDataStructure::build().

Referenced by SCENARIO().

◆ makeTriangulatedDisk()

HalfEdgeDataStructure makeTriangulatedDisk ( )

Definition at line 123 of file testHalfEdgeDataStructure.cpp.

124{
125 std::vector< Triangle > triangles( 7 );
126 triangles[0].v = { 0, 1, 2 };
127 triangles[1].v = { 2, 1, 3 };
128 triangles[2].v = { 2, 3, 4 };
129 triangles[3].v = { 4, 3, 5 };
130 triangles[4].v = { 4, 5, 0 };
131 triangles[5].v = { 0, 5, 1 };
132 triangles[6].v = { 4, 0, 2 };
133 std::vector< Edge > edges;
134 const auto kNumVertices
137 mesh.build( kNumVertices, triangles, edges );
138 return mesh;
139}

References DGtal::HalfEdgeDataStructure::build(), and DGtal::HalfEdgeDataStructure::getUnorderedEdgesFromTriangles().

Referenced by SCENARIO().

◆ makeTwoTriangles()

HalfEdgeDataStructure makeTwoTriangles ( )

Definition at line 54 of file testHalfEdgeDataStructure.cpp.

55{
56 std::vector< Triangle > triangles( 2 );
57 triangles[0].v = { 0, 1, 2 };
58 triangles[1].v = { 2, 1, 3 };
59
61 mesh.build( triangles );
62 return mesh;
63}

References DGtal::HalfEdgeDataStructure::build().

Referenced by SCENARIO().

◆ SCENARIO() [1/5]

SCENARIO ( "HalfEdgeDataStructure build"  ,
""  [halfedge][build] 
)

Definition at line 183 of file testHalfEdgeDataStructure.cpp.

184{
185 GIVEN( "Two triangles incident by an edge" ) {
187 THEN( "The mesh is valid" ) {
188 REQUIRE( mesh.isValid() );
189 }
190 THEN( "The mesh is a valid triangulation" ) {
192 }
193 THEN( "The mesh has 4 vertices, 5 edges, 2 faces, 10 half-edges" ) {
194 REQUIRE( mesh.nbVertices() == 4 );
195 REQUIRE( mesh.nbEdges() == 5 );
196 REQUIRE( mesh.nbFaces() == 2 );
197 REQUIRE( mesh.nbHalfEdges() == 10 );
198 }
199 THEN( "The mesh has 4 boundary vertices" ) {
201 std::sort( bdry.begin(), bdry.end() );
202 REQUIRE( bdry.size() == 4 );
203 REQUIRE( bdry[ 0 ] == 0 );
204 REQUIRE( bdry[ 1 ] == 1 );
205 REQUIRE( bdry[ 2 ] == 2 );
206 REQUIRE( bdry[ 3 ] == 3 );
207 }
208 THEN( "The mesh has 4 boundary arcs" ) {
209 std::vector<ArcT> bdry = mesh.boundaryArcs();
210 std::sort( bdry.begin(), bdry.end() );
211 REQUIRE( bdry.size() == 4 );
212 // std::cout << " arc=(" << bdry[ 0 ].first << "," << bdry[ 0 ].second << ")" << std::endl;
213 REQUIRE( bdry[ 0 ] == ArcT( 0, 2 ) );
214 REQUIRE( bdry[ 1 ] == ArcT( 1, 0 ) );
215 REQUIRE( bdry[ 2 ] == ArcT( 2, 3 ) );
216 REQUIRE( bdry[ 3 ] == ArcT( 3, 1 ) );
217 }
218 }
219 GIVEN( "Three triangles forming a fan around a vertex" ) {
221 THEN( "The mesh is valid" ) {
222 REQUIRE( mesh.isValid() );
223 }
224 THEN( "The mesh is a valid triangulation" ) {
226 }
227 THEN( "The mesh has 4 vertices, 6 edges, 3 faces, 12 half-edges" ) {
228 REQUIRE( mesh.nbVertices() == 4 );
229 REQUIRE( mesh.nbEdges() == 6 );
230 REQUIRE( mesh.nbFaces() == 3 );
231 REQUIRE( mesh.nbHalfEdges() == 12 );
232 }
233 THEN( "The mesh has 3 boundary vertices" ) {
235 std::sort( bdry.begin(), bdry.end() );
236 REQUIRE( bdry.size() == 3 );
237 REQUIRE( bdry[ 0 ] == 0 );
238 REQUIRE( bdry[ 1 ] == 1 );
239 REQUIRE( bdry[ 2 ] == 3 );
240 }
241 THEN( "The mesh has 3 boundary arcs" ) {
242 std::vector<ArcT> bdry = mesh.boundaryArcs();
243 std::sort( bdry.begin(), bdry.end() );
244 REQUIRE( bdry.size() == 3 );
245 // std::cout << " arc=(" << bdry[ 0 ].first << "," << bdry[ 0 ].second << ")" << std::endl;
246 REQUIRE( bdry[ 0 ] == ArcT( 0, 3 ) );
247 REQUIRE( bdry[ 1 ] == ArcT( 1, 0 ) );
248 REQUIRE( bdry[ 2 ] == ArcT( 3, 1 ) );
249 }
250 }
251 GIVEN( "Four triangles forming a tetrahedron" ) {
253 THEN( "The mesh is valid" ) {
254 REQUIRE( mesh.isValid() );
255 }
256 THEN( "The mesh is a valid triangulation" ) {
258 }
259 THEN( "The mesh has 4 vertices, 6 edges, 4 faces, 12 half-edges" ) {
260 REQUIRE( mesh.nbVertices() == 4 );
261 REQUIRE( mesh.nbEdges() == 6 );
262 REQUIRE( mesh.nbFaces() == 4 );
263 REQUIRE( mesh.nbHalfEdges() == 12 );
264 }
265 THEN( "The mesh has no boundary vertices" ) {
267 REQUIRE( bdry.size() == 0 );
268 }
269 THEN( "The mesh has no boundary arcs" ) {
270 std::vector<ArcT> bdry = mesh.boundaryArcs();
271 REQUIRE( bdry.size() == 0 );
272 }
273 }
274 GIVEN( "A ribbon with a hole" ) {
276 THEN( "The mesh is valid" ) {
277 REQUIRE( mesh.isValid() );
278 }
279 THEN( "The mesh has 6 vertices, 12 edges, 6 faces, 24 half-edges" ) {
280 REQUIRE( mesh.nbVertices() == 6 );
281 REQUIRE( mesh.nbEdges() == 12 );
282 REQUIRE( mesh.nbFaces() == 6 );
283 REQUIRE( mesh.nbHalfEdges() == 24 );
284 }
285 THEN( "The mesh has 6 boundary vertices" ) {
287 REQUIRE( bdry.size() == 6 );
288 }
289 THEN( "The mesh has 6 boundary arcs" ) {
290 std::vector<ArcT> bdry = mesh.boundaryArcs();
291 std::sort( bdry.begin(), bdry.end() );
292 REQUIRE( bdry.size() == 6 );
293 REQUIRE( bdry[ 0 ] == ArcT( 0, 2 ) );
294 REQUIRE( bdry[ 1 ] == ArcT( 1, 5 ) );
295 REQUIRE( bdry[ 2 ] == ArcT( 2, 4 ) );
296 REQUIRE( bdry[ 3 ] == ArcT( 3, 1 ) );
297 REQUIRE( bdry[ 4 ] == ArcT( 4, 0 ) );
298 REQUIRE( bdry[ 5 ] == ArcT( 5, 3 ) );
299 }
300 }
301 GIVEN( "The same ribbon with his hole closed" ) {
303 THEN( "The mesh is valid" ) {
304 REQUIRE( mesh.isValid() );
305 }
306 THEN( "The mesh is a valid triangulation" ) {
308 }
309 THEN( "The mesh has 6 vertices, 12 edges, 7 faces, 24 half-edges" ) {
310 REQUIRE( mesh.nbVertices() == 6 );
311 REQUIRE( mesh.nbEdges() == 12 );
312 REQUIRE( mesh.nbFaces() == 7 );
313 REQUIRE( mesh.nbHalfEdges() == 24 );
314 }
315 THEN( "The mesh has 3 boundary vertices" ) {
317 std::sort( bdry.begin(), bdry.end() );
318 REQUIRE( bdry.size() == 3 );
319 REQUIRE( bdry[ 0 ] == 1 );
320 REQUIRE( bdry[ 1 ] == 3 );
321 REQUIRE( bdry[ 2 ] == 5 );
322 }
323 THEN( "The mesh has 3 boundary arcs" ) {
324 std::vector<ArcT> bdry = mesh.boundaryArcs();
325 std::sort( bdry.begin(), bdry.end() );
326 REQUIRE( bdry.size() == 3 );
327 REQUIRE( bdry[ 0 ] == ArcT( 1, 5 ) );
328 REQUIRE( bdry[ 1 ] == ArcT( 3, 1 ) );
329 REQUIRE( bdry[ 2 ] == ArcT( 5, 3 ) );
330 }
331 }
332 GIVEN( "A pyramid with a square base" ) {
334 THEN( "The mesh is valid" ) {
335 REQUIRE( mesh.isValid() );
336 }
337 THEN( "The mesh has 5 vertices, 8 edges, 5 faces, 16 half-edges" ) {
338 REQUIRE( mesh.nbVertices() == 5 );
339 REQUIRE( mesh.nbEdges() == 8 );
340 REQUIRE( mesh.nbFaces() == 5 );
341 REQUIRE( mesh.nbHalfEdges() == 16 );
342 }
343 THEN( "The mesh has 0 boundary vertices" ) {
345 REQUIRE( bdry.size() == 0 );
346 }
347 THEN( "The mesh has 0 boundary arcs" ) {
348 std::vector<ArcT> bdry = mesh.boundaryArcs();
349 REQUIRE( bdry.size() == 0 );
350 }
351 }
352 GIVEN( "A cube" ) {
354 THEN( "The mesh is valid" ) {
355 REQUIRE( mesh.isValid() );
356 }
357 THEN( "The mesh has 8 vertices, 12 edges, 6 faces, 24 half-edges" ) {
358 REQUIRE( mesh.nbVertices() == 8 );
359 REQUIRE( mesh.nbEdges() == 12 );
360 REQUIRE( mesh.nbFaces() == 6 );
361 REQUIRE( mesh.nbHalfEdges() == 24 );
362 }
363 THEN( "The mesh has 0 boundary vertices" ) {
365 REQUIRE( bdry.size() == 0 );
366 }
367 THEN( "The mesh has 0 boundary arcs" ) {
368 std::vector<ArcT> bdry = mesh.boundaryArcs();
369 REQUIRE( bdry.size() == 0 );
370 }
371 }
372 GIVEN( "A box with an open side" ) {
374 THEN( "The mesh is valid" ) {
375 REQUIRE( mesh.isValid() );
376 }
377 THEN( "The mesh has 10 vertices, 15 edges, 6 faces, 30 half-edges" ) {
378 REQUIRE( mesh.nbVertices() == 10 );
379 REQUIRE( mesh.nbEdges() == 15 );
380 REQUIRE( mesh.nbFaces() == 6 );
381 REQUIRE( mesh.nbHalfEdges() == 30 );
382 }
383 THEN( "The mesh has 6 boundary vertices" ) {
385 REQUIRE( bdry.size() == 6 );
386 }
387 THEN( "The mesh has 6 boundary arcs" ) {
388 std::vector<ArcT> bdry = mesh.boundaryArcs();
389 REQUIRE( bdry.size() == 6 );
390 }
391 }
392
393}
std::vector< Arc > boundaryArcs() const
bool isValid(bool check_arc2index=true) const
VertexIndexRange boundaryVertices() const
GIVEN("A cubical complex with random 3-cells")
HalfEdgeDataStructure::VertexIndexRange VertexIndexRange
HalfEdgeDataStructure makeRibbonWithHole()
HalfEdgeDataStructure makePyramid()
HalfEdgeDataStructure makeThreeTriangles()
HalfEdgeDataStructure makeTriangulatedDisk()
HalfEdgeDataStructure::Arc ArcT
HalfEdgeDataStructure makeTwoTriangles()
HalfEdgeDataStructure makeTetrahedron()
HalfEdgeDataStructure makeBox()
HalfEdgeDataStructure makeCube()
REQUIRE(domain.isInside(aPoint))

References DGtal::HalfEdgeDataStructure::boundaryArcs(), DGtal::HalfEdgeDataStructure::boundaryVertices(), GIVEN(), DGtal::HalfEdgeDataStructure::isValid(), DGtal::HalfEdgeDataStructure::isValidTriangulation(), makeBox(), makeCube(), makePyramid(), makeRibbonWithHole(), makeTetrahedron(), makeThreeTriangles(), makeTriangulatedDisk(), makeTwoTriangles(), DGtal::HalfEdgeDataStructure::nbEdges(), DGtal::HalfEdgeDataStructure::nbFaces(), DGtal::HalfEdgeDataStructure::nbHalfEdges(), DGtal::HalfEdgeDataStructure::nbVertices(), and REQUIRE().

◆ SCENARIO() [2/5]

SCENARIO ( "HalfEdgeDataStructure flips"  ,
""  [halfedge][flips] 
)

Definition at line 471 of file testHalfEdgeDataStructure.cpp.

471 {
472 GIVEN( "Two triangles incident by an edge" ) {
474 THEN( "Only one edge is flippable" ) {
475 int nbflippable = 0;
476 for ( Size e = 0; e < mesh.nbEdges(); e++ )
477 {
478 if ( mesh.isFlippable( mesh.halfEdgeIndexFromEdgeIndex( e ) ) )
479 nbflippable++;
480 }
481 REQUIRE( nbflippable == 1 );
482 }
483 }
484 GIVEN( "A pyramid" ) {
486 THEN( "Only four edges are flippable" ) {
487 int nbflippable = 0;
488 for ( Size e = 0; e < mesh.nbEdges(); e++ )
489 {
490 if ( mesh.isFlippable( mesh.halfEdgeIndexFromEdgeIndex( e ) ) )
491 nbflippable++;
492 }
493 REQUIRE( nbflippable == 4 );
494 }
495 }
496 GIVEN( "A tetrahedron" ) {
498 THEN( "No edges are flippable" ) {
499 int nbflippable = 0;
500 for ( Size e = 0; e < mesh.nbEdges(); e++ )
501 {
502 if ( mesh.isFlippable( mesh.halfEdgeIndexFromEdgeIndex( e ) ) )
503 nbflippable++;
504 }
505 REQUIRE( nbflippable == 0 );
506 }
507 }
508 GIVEN( "Two triangles incident by an edge" ) {
510 auto he = mesh.halfEdgeIndexFromArc( {1,2} );
511 REQUIRE( mesh.isFlippable( he ) );
512 mesh.flip( he );
513 THEN( "The mesh is valid after flip" ) {
514 REQUIRE( mesh.isValid() );
515 }
516 THEN( "The mesh is a valid triangulation after flip" ) {
518 }
519 THEN( "Vertex 0 has 2,3,1 as neighbors after flip" ) {
521 VertexIndexRange expected = { 2, 3, 1 };
522 REQUIRE( nv.size() == 3 );
523 REQUIRE( std::equal( nv.begin(), nv.end(), expected.begin() ) );
524 }
525 THEN( "Vertex 1 has 0,3 as neighbors after flip" ) {
527 VertexIndexRange expected = { 0, 3 };
528 REQUIRE( nv.size() == 2 );
529 REQUIRE( std::equal( nv.begin(), nv.end(), expected.begin() ) );
530 }
531 THEN( "Vertex 2 has 3,0 as neighbors after flip" ) {
533 VertexIndexRange expected = { 3, 0 };
534 REQUIRE( nv.size() == 2 );
535 REQUIRE( std::equal( nv.begin(), nv.end(), expected.begin() ) );
536 }
537 THEN( "Vertex 3 has 2,0,1 as neighbors after flip" ) {
539 VertexIndexRange expected = { 1, 0, 2 };
540 REQUIRE( nv.size() == 3 );
541 REQUIRE( std::equal( nv.begin(), nv.end(), expected.begin() ) );
542 }
543 }
544 GIVEN( "Two triangles incident by an edge" ) {
546 auto he = mesh.findHalfEdgeIndexFromArc( {1,2} );
547 REQUIRE( mesh.isFlippable( he ) );
548 mesh.flip( he );
549 auto he2 = mesh.findHalfEdgeIndexFromArc( {0,3} );
550 REQUIRE( mesh.isFlippable( he2 ) );
551 mesh.flip( he2 );
552 THEN( "The mesh is valid after two flips" ) {
553 REQUIRE( mesh.isValid() );
554 }
555 THEN( "The mesh is a valid triangulation after two flips" ) {
557 }
558 THEN( "Vertex 0 has 2,1 as neighbors after flip" ) {
560 VertexIndexRange expected = { 2, 1 };
561 REQUIRE( nv.size() == 2 );
562 REQUIRE( std::equal( nv.begin(), nv.end(), expected.begin() ) );
563 }
564 THEN( "Vertex 1 has 0,2,3 as neighbors after flip" ) {
566 VertexIndexRange expected = { 0,2,3 };
567 REQUIRE( nv.size() == 3 );
568 REQUIRE( std::equal( nv.begin(), nv.end(), expected.begin() ) );
569 }
570 THEN( "Vertex 2 has 3,1,0 as neighbors after flip" ) {
572 VertexIndexRange expected = { 3, 1, 0 };
573 REQUIRE( nv.size() == 3 );
574 REQUIRE( std::equal( nv.begin(), nv.end(), expected.begin() ) );
575 }
576 THEN( "Vertex 3 has 1,2 as neighbors after flip" ) {
578 VertexIndexRange expected = { 1, 2 };
579 REQUIRE( nv.size() == 2 );
580 REQUIRE( std::equal( nv.begin(), nv.end(), expected.begin() ) );
581 }
582 }
583}
Index halfEdgeIndexFromEdgeIndex(const EdgeIndex ei) const
Index findHalfEdgeIndexFromArc(const VertexIndex i, const VertexIndex j) const
bool isFlippable(const Index hei) const
VertexIndexRange neighboringVertices(const VertexIndex vi) const
void flip(const Index hei, bool update_arc2index=true)
Index halfEdgeIndexFromArc(const VertexIndex i, const VertexIndex j) const
HalfEdgeDataStructure::Size Size

References DGtal::HalfEdgeDataStructure::findHalfEdgeIndexFromArc(), DGtal::HalfEdgeDataStructure::flip(), GIVEN(), DGtal::HalfEdgeDataStructure::halfEdgeIndexFromArc(), DGtal::HalfEdgeDataStructure::halfEdgeIndexFromEdgeIndex(), DGtal::HalfEdgeDataStructure::isFlippable(), DGtal::HalfEdgeDataStructure::isValid(), DGtal::HalfEdgeDataStructure::isValidTriangulation(), makePyramid(), makeTetrahedron(), makeTwoTriangles(), DGtal::HalfEdgeDataStructure::nbEdges(), DGtal::HalfEdgeDataStructure::neighboringVertices(), and REQUIRE().

◆ SCENARIO() [3/5]

SCENARIO ( "HalfEdgeDataStructure merges"  ,
""  [halfedge][merges] 
)

Definition at line 612 of file testHalfEdgeDataStructure.cpp.

612 {
613 GIVEN( "An octahedron" ) {
615 auto he = mesh.findHalfEdgeIndexFromArc( {1,2} );
616 REQUIRE( mesh.isMergeable( he ) );
617 auto vtx = mesh.merge( he );
618 THEN( "After merge, mesh is valid" ) {
619 REQUIRE( mesh.isValid() );
620 }
621 THEN( "The mesh is a valid triangulation after merge" ) {
623 }
624 THEN( "After merge, merged vertex is 1" ) {
625 REQUIRE( vtx == 1 );
626 }
627 THEN( "After merge, mesh has 5 vertices, 9 edges, 6 faces" ) {
628 REQUIRE( mesh.nbVertices() == 5 );
629 REQUIRE( mesh.nbEdges() == 9 );
630 REQUIRE( mesh.nbFaces() == 6 );
631 }
632 THEN( "After merge, vertex 0 has 3 neighbors { 1,3,4 }" ) {
634 VertexIndexRange expected = { 1, 3, 4 };
635 REQUIRE( nv.size() == 3 );
636 REQUIRE( std::is_permutation( nv.begin(), nv.end(), expected.begin() ) );
637 }
638 }
639}
bool isMergeable(const Index hei) const
VertexIndex merge(const Index hei, bool update_arc2index=true)
HalfEdgeDataStructure makeOctahedron()

References DGtal::HalfEdgeDataStructure::findHalfEdgeIndexFromArc(), GIVEN(), DGtal::HalfEdgeDataStructure::isMergeable(), DGtal::HalfEdgeDataStructure::isValid(), DGtal::HalfEdgeDataStructure::isValidTriangulation(), makeOctahedron(), DGtal::HalfEdgeDataStructure::merge(), DGtal::HalfEdgeDataStructure::nbEdges(), DGtal::HalfEdgeDataStructure::nbFaces(), DGtal::HalfEdgeDataStructure::nbVertices(), DGtal::HalfEdgeDataStructure::neighboringVertices(), and REQUIRE().

◆ SCENARIO() [4/5]

SCENARIO ( "HalfEdgeDataStructure neighboring relations"  ,
""  [halfedge][neighbors] 
)

Definition at line 395 of file testHalfEdgeDataStructure.cpp.

395 {
396 GIVEN( "Two triangles incident by an edge" ) {
399 THEN( "Vertex 0 has 2 neighboring vertices" ) {
400 mesh.getNeighboringVertices( 0, nv );
401 VertexIndexRange expected = { 1, 2 };
402 REQUIRE( nv.size() == 2 );
403 REQUIRE( std::is_permutation( nv.begin(), nv.end(), expected.begin() ) );
404 }
405 THEN( "Vertex 1 has 3 neighboring vertices" ) {
406 mesh.getNeighboringVertices( 1, nv );
407 VertexIndexRange expected = { 3, 2, 0 };
408 REQUIRE( nv.size() == 3 );
409 REQUIRE( std::is_permutation( nv.begin(), nv.end(), expected.begin() ) );
410 }
411 THEN( "Vertex 2 has 3 neighboring vertices" ) {
412 mesh.getNeighboringVertices( 2, nv );
413 VertexIndexRange expected = { 0, 1, 3 };
414 REQUIRE( nv.size() == 3 );
415 REQUIRE( std::is_permutation( nv.begin(), nv.end(), expected.begin() ) );
416 }
417 THEN( "Vertex 3 has 2 neighboring vertices" ) {
418 mesh.getNeighboringVertices( 3, nv );
419 VertexIndexRange expected = { 2, 1 };
420 REQUIRE( nv.size() == 2 );
421 REQUIRE( std::is_permutation( nv.begin(), nv.end(), expected.begin() ) );
422 }
423 }
424 GIVEN( "A ribbon with a hole" ) {
427 THEN( "Vertex 0 has 4 neighboring vertices" ) {
428 mesh.getNeighboringVertices( 0, nv );
429 VertexIndexRange expected = { 4, 5, 1, 2 };
430 REQUIRE( nv.size() == 4 );
431 REQUIRE( std::is_permutation( nv.begin(), nv.end(), expected.begin() ) );
432 }
433 THEN( "Vertex 1 has 4 neighboring vertices" ) {
434 mesh.getNeighboringVertices( 1, nv );
435 VertexIndexRange expected = { 3, 2, 0, 5 };
436 REQUIRE( nv.size() == 4 );
437 REQUIRE( std::is_permutation( nv.begin(), nv.end(), expected.begin() ) );
438 }
439 THEN( "Vertex 2 has 4 neighboring vertices" ) {
440 mesh.getNeighboringVertices( 2, nv );
441 VertexIndexRange expected = { 0, 1, 3, 4 };
442 REQUIRE( nv.size() == 4 );
443 REQUIRE( std::is_permutation( nv.begin(), nv.end(), expected.begin() ) );
444 }
445 }
446
447 GIVEN( "A box with an open side" ) {
450 THEN( "Vertex 0 has 3 neighboring vertices" ) {
451 mesh.getNeighboringVertices( 0, nv );
452 VertexIndexRange expected = { 1, 4, 2 };
453 REQUIRE( nv.size() == 3 );
454 REQUIRE( std::is_permutation( nv.begin(), nv.end(), expected.begin() ) );
455 }
456 THEN( "Vertex 5 has 4 neighboring vertices" ) {
457 mesh.getNeighboringVertices( 5, nv );
458 VertexIndexRange expected = { 8, 4, 1, 7 };
459 REQUIRE( nv.size() == 4 );
460 REQUIRE( std::is_permutation( nv.begin(), nv.end(), expected.begin() ) );
461 }
462 THEN( "Vertex 7 has 3 neighboring vertices" ) {
463 mesh.getNeighboringVertices( 7, nv );
464 VertexIndexRange expected = { 5, 3, 6 };
465 REQUIRE( nv.size() == 3 );
466 REQUIRE( std::is_permutation( nv.begin(), nv.end(), expected.begin() ) );
467 }
468 }
469}
void getNeighboringVertices(const VertexIndex vi, VertexIndexRange &result) const

References DGtal::HalfEdgeDataStructure::getNeighboringVertices(), GIVEN(), makeBox(), makeRibbonWithHole(), makeTwoTriangles(), and REQUIRE().

◆ SCENARIO() [5/5]

SCENARIO ( "HalfEdgeDataStructure splits"  ,
""  [halfedge][splits] 
)

Definition at line 585 of file testHalfEdgeDataStructure.cpp.

585 {
586 GIVEN( "Two triangles incident by an edge" ) {
588 auto he = mesh.findHalfEdgeIndexFromArc( {1,2} );
589 REQUIRE( mesh.isFlippable( he ) );
590 //auto vtx =
591 mesh.split( he );
592 THEN( "After split, mesh is valid" ) {
593 REQUIRE( mesh.isValid() );
594 }
595 THEN( "The mesh is a valid triangulation after split" ) {
597 }
598 THEN( "After split, mesh has 5 vertices, 8 edges, 4 faces" ) {
599 REQUIRE( mesh.nbVertices() == 5 );
600 REQUIRE( mesh.nbEdges() == 8 );
601 REQUIRE( mesh.nbFaces() == 4 );
602 }
603 THEN( "After split, vertex 4 has 4 neighbors { 0,1,2,3 }" ) {
605 VertexIndexRange expected = { 0, 1, 2, 3 };
606 REQUIRE( nv.size() == 4 );
607 REQUIRE( std::is_permutation( nv.begin(), nv.end(), expected.begin() ) );
608 }
609 }
610}
VertexIndex split(const Index i, bool update_arc2index=true)

References DGtal::HalfEdgeDataStructure::findHalfEdgeIndexFromArc(), GIVEN(), DGtal::HalfEdgeDataStructure::isFlippable(), DGtal::HalfEdgeDataStructure::isValid(), DGtal::HalfEdgeDataStructure::isValidTriangulation(), makeTwoTriangles(), DGtal::HalfEdgeDataStructure::nbEdges(), DGtal::HalfEdgeDataStructure::nbFaces(), DGtal::HalfEdgeDataStructure::nbVertices(), DGtal::HalfEdgeDataStructure::neighboringVertices(), REQUIRE(), and DGtal::HalfEdgeDataStructure::split().