33 #include "DGtal/base/Common.h"
34 #include "ConfigTest.h"
35 #include "DGtalCatch.h"
36 #include "DGtal/helpers/StdDefs.h"
37 #include "DGtal/topology/HalfEdgeDataStructure.h"
40 using namespace DGtal;
56 std::vector< Triangle > triangles( 2 );
57 triangles[0].v = { 0, 1, 2 };
58 triangles[1].v = { 2, 1, 3 };
61 mesh.
build( triangles );
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 };
73 mesh.
build( triangles );
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 };
86 mesh.
build( triangles );
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 );
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 );
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 );
143 std::vector< PolygonalFace > faces( 5 );
156 std::vector< PolygonalFace > faces( 6 );
170 std::vector< PolygonalFace > faces( 6 );
183 SCENARIO(
"HalfEdgeDataStructure build",
"[halfedge][build]" )
185 GIVEN(
"Two triangles incident by an edge" ) {
187 THEN(
"The mesh is valid" ) {
190 THEN(
"The mesh is a valid triangulation" ) {
193 THEN(
"The mesh has 4 vertices, 5 edges, 2 faces, 10 half-edges" ) {
199 THEN(
"The mesh has 4 boundary vertices" ) {
201 std::sort( bdry.begin(), bdry.end() );
208 THEN(
"The mesh has 4 boundary arcs" ) {
210 std::sort( bdry.begin(), bdry.end() );
219 GIVEN(
"Three triangles forming a fan around a vertex" ) {
221 THEN(
"The mesh is valid" ) {
224 THEN(
"The mesh is a valid triangulation" ) {
227 THEN(
"The mesh has 4 vertices, 6 edges, 3 faces, 12 half-edges" ) {
233 THEN(
"The mesh has 3 boundary vertices" ) {
235 std::sort( bdry.begin(), bdry.end() );
241 THEN(
"The mesh has 3 boundary arcs" ) {
243 std::sort( bdry.begin(), bdry.end() );
251 GIVEN(
"Four triangles forming a tetrahedron" ) {
253 THEN(
"The mesh is valid" ) {
256 THEN(
"The mesh is a valid triangulation" ) {
259 THEN(
"The mesh has 4 vertices, 6 edges, 4 faces, 12 half-edges" ) {
265 THEN(
"The mesh has no boundary vertices" ) {
269 THEN(
"The mesh has no boundary arcs" ) {
274 GIVEN(
"A ribbon with a hole" ) {
276 THEN(
"The mesh is valid" ) {
279 THEN(
"The mesh has 6 vertices, 12 edges, 6 faces, 24 half-edges" ) {
285 THEN(
"The mesh has 6 boundary vertices" ) {
289 THEN(
"The mesh has 6 boundary arcs" ) {
291 std::sort( bdry.begin(), bdry.end() );
301 GIVEN(
"The same ribbon with his hole closed" ) {
303 THEN(
"The mesh is valid" ) {
306 THEN(
"The mesh is a valid triangulation" ) {
309 THEN(
"The mesh has 6 vertices, 12 edges, 7 faces, 24 half-edges" ) {
315 THEN(
"The mesh has 3 boundary vertices" ) {
317 std::sort( bdry.begin(), bdry.end() );
323 THEN(
"The mesh has 3 boundary arcs" ) {
325 std::sort( bdry.begin(), bdry.end() );
332 GIVEN(
"A pyramid with a square base" ) {
334 THEN(
"The mesh is valid" ) {
337 THEN(
"The mesh has 5 vertices, 8 edges, 5 faces, 16 half-edges" ) {
343 THEN(
"The mesh has 0 boundary vertices" ) {
347 THEN(
"The mesh has 0 boundary arcs" ) {
354 THEN(
"The mesh is valid" ) {
357 THEN(
"The mesh has 8 vertices, 12 edges, 6 faces, 24 half-edges" ) {
363 THEN(
"The mesh has 0 boundary vertices" ) {
367 THEN(
"The mesh has 0 boundary arcs" ) {
372 GIVEN(
"A box with an open side" ) {
374 THEN(
"The mesh is valid" ) {
377 THEN(
"The mesh has 10 vertices, 15 edges, 6 faces, 30 half-edges" ) {
383 THEN(
"The mesh has 6 boundary vertices" ) {
387 THEN(
"The mesh has 6 boundary arcs" ) {
395 SCENARIO(
"HalfEdgeDataStructure neighboring relations",
"[halfedge][neighbors]" ){
396 GIVEN(
"Two triangles incident by an edge" ) {
399 THEN(
"Vertex 0 has 2 neighboring vertices" ) {
403 REQUIRE( std::is_permutation( nv.begin(), nv.end(), expected.begin() ) );
405 THEN(
"Vertex 1 has 3 neighboring vertices" ) {
409 REQUIRE( std::is_permutation( nv.begin(), nv.end(), expected.begin() ) );
411 THEN(
"Vertex 2 has 3 neighboring vertices" ) {
415 REQUIRE( std::is_permutation( nv.begin(), nv.end(), expected.begin() ) );
417 THEN(
"Vertex 3 has 2 neighboring vertices" ) {
421 REQUIRE( std::is_permutation( nv.begin(), nv.end(), expected.begin() ) );
424 GIVEN(
"A ribbon with a hole" ) {
427 THEN(
"Vertex 0 has 4 neighboring vertices" ) {
431 REQUIRE( std::is_permutation( nv.begin(), nv.end(), expected.begin() ) );
433 THEN(
"Vertex 1 has 4 neighboring vertices" ) {
437 REQUIRE( std::is_permutation( nv.begin(), nv.end(), expected.begin() ) );
439 THEN(
"Vertex 2 has 4 neighboring vertices" ) {
443 REQUIRE( std::is_permutation( nv.begin(), nv.end(), expected.begin() ) );
447 GIVEN(
"A box with an open side" ) {
450 THEN(
"Vertex 0 has 3 neighboring vertices" ) {
454 REQUIRE( std::is_permutation( nv.begin(), nv.end(), expected.begin() ) );
456 THEN(
"Vertex 5 has 4 neighboring vertices" ) {
460 REQUIRE( std::is_permutation( nv.begin(), nv.end(), expected.begin() ) );
462 THEN(
"Vertex 7 has 3 neighboring vertices" ) {
466 REQUIRE( std::is_permutation( nv.begin(), nv.end(), expected.begin() ) );
471 SCENARIO(
"HalfEdgeDataStructure flips",
"[halfedge][flips]" ){
472 GIVEN(
"Two triangles incident by an edge" ) {
474 THEN(
"Only one edge is flippable" ) {
484 GIVEN(
"A pyramid" ) {
486 THEN(
"Only four edges are flippable" ) {
496 GIVEN(
"A tetrahedron" ) {
498 THEN(
"No edges are flippable" ) {
508 GIVEN(
"Two triangles incident by an edge" ) {
513 THEN(
"The mesh is valid after flip" ) {
516 THEN(
"The mesh is a valid triangulation after flip" ) {
519 THEN(
"Vertex 0 has 2,3,1 as neighbors after flip" ) {
523 REQUIRE( std::equal( nv.begin(), nv.end(), expected.begin() ) );
525 THEN(
"Vertex 1 has 0,3 as neighbors after flip" ) {
529 REQUIRE( std::equal( nv.begin(), nv.end(), expected.begin() ) );
531 THEN(
"Vertex 2 has 3,0 as neighbors after flip" ) {
535 REQUIRE( std::equal( nv.begin(), nv.end(), expected.begin() ) );
537 THEN(
"Vertex 3 has 2,0,1 as neighbors after flip" ) {
541 REQUIRE( std::equal( nv.begin(), nv.end(), expected.begin() ) );
544 GIVEN(
"Two triangles incident by an edge" ) {
552 THEN(
"The mesh is valid after two flips" ) {
555 THEN(
"The mesh is a valid triangulation after two flips" ) {
558 THEN(
"Vertex 0 has 2,1 as neighbors after flip" ) {
562 REQUIRE( std::equal( nv.begin(), nv.end(), expected.begin() ) );
564 THEN(
"Vertex 1 has 0,2,3 as neighbors after flip" ) {
568 REQUIRE( std::equal( nv.begin(), nv.end(), expected.begin() ) );
570 THEN(
"Vertex 2 has 3,1,0 as neighbors after flip" ) {
574 REQUIRE( std::equal( nv.begin(), nv.end(), expected.begin() ) );
576 THEN(
"Vertex 3 has 1,2 as neighbors after flip" ) {
580 REQUIRE( std::equal( nv.begin(), nv.end(), expected.begin() ) );
585 SCENARIO(
"HalfEdgeDataStructure splits",
"[halfedge][splits]" ){
586 GIVEN(
"Two triangles incident by an edge" ) {
592 THEN(
"After split, mesh is valid" ) {
595 THEN(
"The mesh is a valid triangulation after split" ) {
598 THEN(
"After split, mesh has 5 vertices, 8 edges, 4 faces" ) {
603 THEN(
"After split, vertex 4 has 4 neighbors { 0,1,2,3 }" ) {
607 REQUIRE( std::is_permutation( nv.begin(), nv.end(), expected.begin() ) );
612 SCENARIO(
"HalfEdgeDataStructure merges",
"[halfedge][merges]" ){
613 GIVEN(
"An octahedron" ) {
617 auto vtx = mesh.
merge( he );
618 THEN(
"After merge, mesh is valid" ) {
621 THEN(
"The mesh is a valid triangulation after merge" ) {
624 THEN(
"After merge, merged vertex is 1" ) {
627 THEN(
"After merge, mesh has 5 vertices, 9 edges, 6 faces" ) {
632 THEN(
"After merge, vertex 0 has 3 neighbors { 1,3,4 }" ) {
636 REQUIRE( std::is_permutation( nv.begin(), nv.end(), expected.begin() ) );
Aim: This class represents an half-edge data structure, which is a structure for representing the top...
std::vector< VertexIndex > VertexIndexRange
Index halfEdgeIndexFromEdgeIndex(const EdgeIndex ei) const
VertexIndex split(const Index i, bool update_arc2index=true)
Index findHalfEdgeIndexFromArc(const VertexIndex i, const VertexIndex j) const
std::vector< VertexIndex > PolygonalFace
bool isMergeable(const Index hei) const
static Size getUnorderedEdgesFromTriangles(const std::vector< Triangle > &triangles, std::vector< Edge > &edges_out)
std::vector< Arc > boundaryArcs() const
bool isValid(bool check_arc2index=true) const
bool isFlippable(const Index hei) const
VertexIndexRange neighboringVertices(const VertexIndex vi) const
bool isValidTriangulation() const
std::size_t Size
The type for counting elements.
VertexIndexRange boundaryVertices() const
void flip(const Index hei, bool update_arc2index=true)
std::pair< VertexIndex, VertexIndex > Arc
An arc is a directed edge from a first vertex to a second vertex.
VertexIndex merge(const Index hei, bool update_arc2index=true)
Index halfEdgeIndexFromArc(const VertexIndex i, const VertexIndex j) const
bool build(const Size num_vertices, const std::vector< Triangle > &triangles, const std::vector< Edge > &edges)
void getNeighboringVertices(const VertexIndex vi, VertexIndexRange &result) const
DGtal is the top-level namespace which contains all DGtal functions and types.
Represents an unoriented triangle as three vertices.
GIVEN("A cubical complex with random 3-cells")
HalfEdgeDataStructure::VertexIndexRange VertexIndexRange
HalfEdgeDataStructure::Size Size
HalfEdgeDataStructure makeRibbonWithHole()
HalfEdgeDataStructure makePyramid()
HalfEdgeDataStructure makeThreeTriangles()
HalfEdgeDataStructure makeTriangulatedDisk()
HalfEdgeDataStructure::Triangle Triangle
HalfEdgeDataStructure::Arc ArcT
HalfEdgeDataStructure makeTwoTriangles()
HalfEdgeDataStructure makeOctahedron()
HalfEdgeDataStructure::Edge Edge
SCENARIO("HalfEdgeDataStructure build", "[halfedge][build]")
HalfEdgeDataStructure makeTetrahedron()
HalfEdgeDataStructure makeBox()
HalfEdgeDataStructure::PolygonalFace PolygonalFace
HalfEdgeDataStructure makeCube()
REQUIRE(domain.isInside(aPoint))