51 "[convexity_helper][lattice_polytope][2d]" )
54 typedef Helper::Point
Point;
56 GIVEN(
"Given a star { (0,0), (-4,-1), (-3,5), (7,3), (5, -2) } " ) {
59 WHEN(
"Computing its lattice polytope" ){
60 const auto P = Helper::computeLatticePolytope( V,
false,
true );
62 THEN(
"The polytope is valid and has 4 non trivial facets" ) {
63 REQUIRE( P.nbHalfSpaces() - 4 == 4 );
65 THEN(
"The polytope is Minkowski summable" ) {
68 THEN(
"The polytope contains the input points" ) {
69 REQUIRE( P.isInside( V[ 0 ] ) );
70 REQUIRE( P.isInside( V[ 1 ] ) );
71 REQUIRE( P.isInside( V[ 2 ] ) );
72 REQUIRE( P.isInside( V[ 3 ] ) );
73 REQUIRE( P.isInside( V[ 4 ] ) );
75 THEN(
"The polytope contains 58 points" ) {
78 THEN(
"The interior of the polytope contains 53 points" ) {
79 REQUIRE( P.countInterior() == 53 );
81 THEN(
"The boundary of the polytope contains 5 points" ) {
82 REQUIRE( P.countBoundary() == 5 );
86 GIVEN(
"Given a square with an additional outside vertex " ) {
90 WHEN(
"Computing its Delaunay cell complex" ){
91 CvxCellComplex complex;
92 bool ok = Helper::computeDelaunayCellComplex( complex, V,
false );
94 THEN(
"The complex has 2 cells, 6 faces, 5 vertices" ) {
96 REQUIRE( complex.nbCells() == 2 );
97 REQUIRE( complex.nbFaces() == 6 );
98 REQUIRE( complex.nbVertices() == 5 );
100 THEN(
"The faces of cells are finite" ) {
101 bool ok_finite =
true;
102 for ( CvxCellComplex::Size c = 0; c < complex.nbCells(); ++c ) {
103 const auto faces = complex.cellFaces( c );
104 for (
auto f : faces )
105 ok_finite = ok_finite && ! complex.isInfinite( complex.faceCell( f ) );
109 THEN(
"The opposite of faces of cells are infinite except two" ) {
111 for ( CvxCellComplex::Size c = 0; c < complex.nbCells(); ++c ) {
112 const auto faces = complex.cellFaces( c );
113 for (
auto f : faces ) {
114 const auto opp_f = complex.opposite( f );
115 nb_finite += complex.isInfinite( complex.faceCell( opp_f ) ) ? 0 : 1;
122 GIVEN(
"Given a degenerated polytope { (0,0), (3,-1), (9,-3), (-6,2) } " ) {
125 WHEN(
"Computing its lattice polytope" ){
126 const auto P = Helper::computeLatticePolytope( V,
false,
true );
128 THEN(
"The polytope is valid and has 2 non trivial facets" ) {
129 REQUIRE( P.nbHalfSpaces() - 4 == 2 );
131 THEN(
"The polytope contains 6 points" ) {
134 THEN(
"The polytope contains no interior points" ) {
135 REQUIRE( P.countInterior() == 0 );
138 WHEN(
"Computing the vertices of its convex hull" ){
139 auto X = Helper::computeConvexHullVertices( V,
false );
140 std::sort( X.begin(), X.end() );
142 THEN(
"The polytope is a segment defined by two points" ) {
149 GIVEN(
"Given a degenerated simplex { (4,0), (7,2), (-5,-6) } " ) {
152 WHEN(
"Computing its lattice polytope" ){
153 const auto P = Helper::computeLatticePolytope( V,
false,
true );
155 THEN(
"The polytope is valid and has 2 non trivial facets" ) {
156 REQUIRE( P.nbHalfSpaces() - 4 == 2 );
158 THEN(
"The polytope contains 5 points" ) {
161 THEN(
"The polytope contains no interior points" ) {
162 REQUIRE( P.countInterior() == 0 );
165 WHEN(
"Computing the vertices of its convex hull" ){
166 auto X = Helper::computeConvexHullVertices( V,
false );
167 std::sort( X.begin(), X.end() );
169 THEN(
"The polytope is a segment defined by two points" ) {
183 "[convexity_helper][3d]" )
186 typedef Helper::Point
Point;
192 GIVEN(
"Given an octahedron star { (0,0,0), (-2,0,0), (2,0,0), (0,-2,0), (0,2,0), (0,0,-2), (0,0,2) } " ) {
194 = {
Point(0,0,0),
Point(-2,0,0),
Point(2,0,0),
Point(0,-2,0),
Point(0,2,0),
196 WHEN(
"Computing its lattice polytope" ){
197 const auto P = Helper::computeLatticePolytope( V,
false,
true );
199 THEN(
"The polytope is valid and has 8 non trivial facets plus 12 edge constraints" ) {
200 REQUIRE( P.nbHalfSpaces() - 6 == 20 );
202 THEN(
"The polytope is Minkowski summable" ) {
205 THEN(
"The polytope contains the input points" ) {
206 REQUIRE( P.isInside( V[ 0 ] ) );
207 REQUIRE( P.isInside( V[ 1 ] ) );
208 REQUIRE( P.isInside( V[ 2 ] ) );
209 REQUIRE( P.isInside( V[ 3 ] ) );
210 REQUIRE( P.isInside( V[ 4 ] ) );
211 REQUIRE( P.isInside( V[ 5 ] ) );
212 REQUIRE( P.isInside( V[ 6 ] ) );
214 THEN(
"The polytope contains 25 points" ) {
217 THEN(
"The interior of the polytope contains 7 points" ) {
218 REQUIRE( P.countInterior() == 7 );
220 THEN(
"The boundary of the polytope contains 18 points" ) {
221 REQUIRE( P.countBoundary() == 18 );
224 WHEN(
"Computing the boundary of its convex hull as a SurfaceMesh" ){
226 bool ok = Helper::computeConvexHullBoundary( smesh, V,
false );
228 THEN(
"The surface mesh is valid and has 6 vertices, 12 edges and 8 faces" ) {
234 THEN(
"The surface mesh has the topology of a sphere" ) {
240 WHEN(
"Computing the boundary of its convex hull as a lattice PolygonalSurface" ){
241 LatticePolySurf lpsurf;
242 bool ok = Helper::computeConvexHullBoundary( lpsurf, V,
false );
244 THEN(
"The polygonal surface is valid and has 6 vertices, 12 edges and 8 faces" ) {
246 REQUIRE( lpsurf.nbVertices() == 6 );
247 REQUIRE( lpsurf.nbEdges() == 12 );
248 REQUIRE( lpsurf.nbFaces() == 8 );
249 REQUIRE( lpsurf.nbArcs() == 24 );
251 THEN(
"The polygonal surface has the topology of a sphere and no boundary" ) {
252 REQUIRE( lpsurf.Euler() == 2 );
253 REQUIRE( lpsurf.allBoundaryArcs().size() == 0 );
254 REQUIRE( lpsurf.allBoundaryVertices().size() == 0 );
257 WHEN(
"Computing its convex hull as a ConvexCellComplex" ){
258 CvxCellComplex complex;
259 bool ok = Helper::computeConvexHullCellComplex( complex, V,
false );
261 THEN(
"The convex cell complex is valid and has 6 vertices, 8 faces and 1 finite cell" ) {
263 REQUIRE( complex.nbVertices() == 6 );
264 REQUIRE( complex.nbFaces() == 8 );
265 REQUIRE( complex.nbCells() == 1 );
268 WHEN(
"Computing the vertices of its convex hull" ){
269 const auto X = Helper::computeConvexHullVertices( V,
false );
271 THEN(
"The polytope has 6 vertices" ) {
276 GIVEN(
"Given a cube with an additional outside vertex " ) {
278 = {
Point(-10,-10,-10),
Point(10,-10,-10),
Point(-10,10,-10),
Point(10,10,-10),
279 Point(-10,-10,10),
Point(10,-10,10),
Point(-10,10,10),
Point(10,10,10),
281 WHEN(
"Computing its Delaunay cell complex" ){
282 CvxCellComplex complex;
283 bool ok = Helper::computeDelaunayCellComplex( complex, V,
false );
285 THEN(
"The complex has 2 cells, 10 faces, 9 vertices" ) {
287 REQUIRE( complex.nbCells() == 2 );
288 REQUIRE( complex.nbFaces() == 10 );
289 REQUIRE( complex.nbVertices() == 9 );
291 THEN(
"The faces of cells are finite" ) {
292 bool ok_finite =
true;
293 for ( CvxCellComplex::Size c = 0; c < complex.nbCells(); ++c ) {
294 const auto faces = complex.cellFaces( c );
295 for (
auto f : faces )
296 ok_finite = ok_finite && ! complex.isInfinite( complex.faceCell( f ) );
300 THEN(
"The opposite of faces of cells are infinite except two" ) {
302 for ( CvxCellComplex::Size c = 0; c < complex.nbCells(); ++c ) {
303 const auto faces = complex.cellFaces( c );
304 for (
auto f : faces ) {
305 const auto opp_f = complex.opposite( f );
306 nb_finite += complex.isInfinite( complex.faceCell( opp_f ) ) ? 0 : 1;
312 WHEN(
"Computing the vertices of its convex hull" ){
313 const auto X = Helper::computeConvexHullVertices( V,
false );
315 THEN(
"The polytope has 9 vertices" ) {
320 GIVEN(
"Given a degenerated 1d polytope { (0,0,1), (3,-1,2), (9,-3,4), (-6,2,-1) } " ) {
322 = {
Point(0,0,1),
Point(3,-1,2),
Point(9,-3,4),
Point(-6,2,-1) };
323 WHEN(
"Computing its lattice polytope" ){
324 const auto P = Helper::computeLatticePolytope( V,
false,
true );
326 THEN(
"The polytope is valid and has 6 non trivial facets" ) {
327 REQUIRE( P.nbHalfSpaces() - 6 == 6 );
329 THEN(
"The polytope contains 6 points" ) {
332 THEN(
"The polytope contains no interior points" ) {
333 REQUIRE( P.countInterior() == 0 );
336 WHEN(
"Computing the vertices of its convex hull" ){
337 auto X = Helper::computeConvexHullVertices( V,
false );
338 std::sort( X.begin(), X.end() );
340 THEN(
"The polytope is a segment defined by two points" ) {
347 GIVEN(
"Given a degenerated 1d simplex { (1,0,-1), Point(4,-1,-2), Point(10,-3,-4) } " ) {
350 WHEN(
"Computing its lattice polytope" ){
351 const auto P = Helper::computeLatticePolytope( V,
false,
true );
353 THEN(
"The polytope is valid and has 6 non trivial facets" ) {
354 REQUIRE( P.nbHalfSpaces() - 6 == 6 );
356 THEN(
"The polytope contains 4 points" ) {
359 THEN(
"The polytope contains no interior points" ) {
360 REQUIRE( P.countInterior() == 0 );
363 WHEN(
"Computing the vertices of its convex hull" ){
364 auto X = Helper::computeConvexHullVertices( V,
false );
365 std::sort( X.begin(), X.end() );
367 THEN(
"The polytope is a segment defined by two points" ) {
374 GIVEN(
"Given a degenerated 2d polytope { (2,1,0), (1,0,1), (1,2,1), (0,1,2), (0,3,2) } " ) {
376 = {
Point(2,1,0),
Point(1,0,1),
Point(1,2,1),
Point(0,1,2),
Point(0,3,2) };
377 WHEN(
"Computing its lattice polytope" ){
378 const auto P = Helper::computeLatticePolytope( V,
false,
true );
380 THEN(
"The polytope is valid and has more than 6 non trivial facets" ) {
381 REQUIRE( P.nbHalfSpaces() - 6 == 6 );
383 THEN(
"The polytope contains 7 points" ) {
386 THEN(
"The polytope contains no interior points" ) {
387 REQUIRE( P.countInterior() == 0 );
390 WHEN(
"Computing the vertices of its convex hull" ){
391 auto X = Helper::computeConvexHullVertices( V,
false );
392 std::sort( X.begin(), X.end() );
394 THEN(
"The polytope is a quad" ) {
403 GIVEN(
"Given a degenerated 2d simplex { (2,1,0), (1,0,1), (1,5,1), (0,3,2) } " ) {
405 = {
Point(2,1,0),
Point(1,0,1),
Point(1,5,1),
Point(0,3,2) };
406 WHEN(
"Computing its lattice polytope" ){
407 const auto P = Helper::computeLatticePolytope( V,
false,
true );
409 THEN(
"The polytope is valid and has more than 6 non trivial facets" ) {
410 REQUIRE( P.nbHalfSpaces() - 6 == 6 );
412 THEN(
"The polytope contains 8 points" ) {
415 THEN(
"The polytope contains no interior points" ) {
416 REQUIRE( P.countInterior() == 0 );
419 WHEN(
"Computing the vertices of its convex hull" ){
420 auto X = Helper::computeConvexHullVertices( V,
false );
421 std::sort( X.begin(), X.end() );
423 THEN(
"The polytope is a quad" ) {
440 "[convexity_helper][triangle][3d]" )
443 typedef Helper::Point
Point;
444 typedef Helper::Vector
Vector;
445 GIVEN(
"Given non degenerated triplets of points" ) {
446 Helper::LatticePolytope P;
447 Helper::LatticePolytope T;
453 int nb_P = 0, nb_T = 0, nbi_P = 0, nbi_T = 0;
454 for (
int i = 0; i < 20; i++ )
457 a =
Point( rand() % 10, rand() % 10, rand() % 10 );
458 b =
Point( rand() % 10, rand() % 10, rand() % 10 );
459 c =
Point( rand() % 10, rand() % 10, rand() % 10 );
461 }
while ( n == Vector::zero );
462 std::vector<Point> V = { a, b, c };
463 P = Helper::computeLatticePolytope( V,
false,
false );
464 T = Helper::compute3DTriangle( a, b, c );
467 nbi_P = P.countInterior();
468 nbi_T = T.countInterior();
470 nb_ok += ( nb_P == nb_T ) ? 1 : 0;
471 nbi_ok += ( nbi_P == 0 && nbi_T == 0 ) ? 1 : 0;
472 if ( ( nb_ok != nb_total ) || ( nbi_ok != nb_total ) )
break;
477 WHEN(
"Computing their tightiest polytope or triangle" ) {
478 THEN(
"They have the same number of inside points" ) {
481 THEN(
"They do not have interior points" ) {
487 GIVEN(
"Given non degenerated triplets of points" ) {
488 typedef Helper::LatticePolytope::UnitSegment UnitSegment;
489 Helper::LatticePolytope P;
490 Helper::LatticePolytope T;
496 int nb_P = 0, nb_T = 0, nbi_P = 0, nbi_T = 0;
497 for (
int i = 0; i < 20; i++ )
500 a =
Point( rand() % 10, rand() % 10, rand() % 10 );
501 b =
Point( rand() % 10, rand() % 10, rand() % 10 );
502 c =
Point( rand() % 10, rand() % 10, rand() % 10 );
504 }
while ( n == Vector::zero );
505 std::vector<Point> V = { a, b, c };
506 P = Helper::computeLatticePolytope( V,
false,
true );
507 T = Helper::compute3DTriangle( a, b, c,
true );
510 P += UnitSegment( k );
511 T += UnitSegment( k );
515 nbi_P = P.countInterior();
516 nbi_T = T.countInterior();
518 nb_ok += ( nb_P == nb_T ) ? 1 : 0;
519 nbi_ok += ( nbi_P == nbi_T ) ? 1 : 0;
520 if ( ( nb_ok != nb_total ) || ( nbi_ok != nb_total ) )
break;
525 WHEN(
"Computing their tightiest polytope or triangle, dilated by a cube" ) {
526 THEN(
"They have the same number of inside points" ) {
529 THEN(
"They have the same number of interior points" ) {
537SCENARIO(
"ConvexityHelper< 3 > degenerated triangle tests",
538 "[convexity_helper][triangle][degenerate][3d]" )
541 typedef Helper::Point
Point;
542 typedef Helper::Vector
Vector;
543 GIVEN(
"Given degenerated triplets of points" ) {
544 Helper::LatticePolytope P;
545 Helper::LatticePolytope T;
551 int nb_P = 0, nb_T = 0, nbi_P = 0, nbi_T = 0;
552 for (
int i = 0; i < 20; i++ )
555 a =
Point( rand() % 10, rand() % 10, rand() % 10 );
556 b =
Point( rand() % 10, rand() % 10, rand() % 10 );
557 c =
Point( rand() % 10, rand() % 10, rand() % 10 );
559 }
while ( n != Vector::zero );
560 std::vector<Point> V = { a, b, c };
561 P = Helper::computeLatticePolytope( V,
true,
false );
562 T = Helper::compute3DTriangle( a, b, c );
565 nbi_P = P.countInterior();
566 nbi_T = T.countInterior();
568 nb_ok += ( nb_P == nb_T ) ? 1 : 0;
569 nbi_ok += ( nbi_P == 0 && nbi_T == 0 ) ? 1 : 0;
570 if ( ( nb_ok != nb_total ) || ( nbi_ok != nb_total ) )
break;
575 WHEN(
"Computing their tightiest polytope or triangle" ) {
576 THEN(
"They have the same number of inside points" ) {
579 THEN(
"They do not have interior points" ) {
585 GIVEN(
"Given degenerated triplets of points" ) {
586 typedef Helper::LatticePolytope::UnitSegment UnitSegment;
587 Helper::LatticePolytope P;
588 Helper::LatticePolytope T;
594 int nb_P = 0, nb_T = 0, nbi_P = 0, nbi_T = 0;
595 for (
int i = 0; i < 20; i++ )
598 a =
Point( rand() % 10, rand() % 10, rand() % 10 );
599 b =
Point( rand() % 10, rand() % 10, rand() % 10 );
600 c =
Point( rand() % 10, rand() % 10, rand() % 10 );
602 }
while ( n != Vector::zero );
603 std::vector<Point> V = { a, b, c };
604 P = Helper::computeLatticePolytope( V,
true,
true );
605 T = Helper::compute3DTriangle( a, b, c,
true );
608 P += UnitSegment( k );
609 T += UnitSegment( k );
613 nbi_P = P.countInterior();
614 nbi_T = T.countInterior();
616 nb_ok += ( nb_P == nb_T ) ? 1 : 0;
617 nbi_ok += ( nbi_P == nbi_T ) ? 1 : 0;
618 if ( ( nb_ok != nb_total ) || ( nbi_ok != nb_total ) )
break;
623 WHEN(
"Computing their tightiest polytope or triangle, dilated by a cube" ) {
624 THEN(
"They have the same number of inside points" ) {
627 THEN(
"They have the same number of interior points" ) {
635SCENARIO(
"ConvexityHelper< 3 > open segment tests",
636 "[convexity_helper][open segment][3d]" )
639 typedef Helper::Point
Point;
641 typedef Helper::LatticePolytope::UnitSegment UnitSegment;
643 auto nb_open_segment_smaller_than_segment = 0;
644 auto nb_dilated_open_segment_smaller_than_dilated_segment = 0;
645 auto nb_dilated_open_segment_greater_than_interior_dilated_segment = 0;
648 for (
auto n = 0; n < N; n++ )
650 Point a( rand() %
K, rand() %
K, rand() %
K );
651 Point b( rand() %
K, rand() %
K, rand() %
K );
652 if ( a == b ) b[ rand() % 3 ] += 1;
653 Helper::LatticePolytope CS = Helper::computeSegment( a, b );
654 Helper::LatticePolytope OS = Helper::computeOpenSegment( a, b );
658 auto cs_in = CS.count();
659 auto os_in = OS.count();
661 nb_open_segment_smaller_than_segment += ( os_in < cs_in ) ? 1 : 0;
665 CS += UnitSegment( k );
666 OS += UnitSegment( k );
671 auto cs_in = CS.count();
672 auto cs_int = CS.countInterior();
673 auto os_in = OS.count();
676 nb_dilated_open_segment_smaller_than_dilated_segment
677 += ( os_in < cs_in ) ? 1 : 0;
678 nb_dilated_open_segment_greater_than_interior_dilated_segment
679 += ( cs_int <= os_in ) ? 1 : 0;
682 WHEN(
"Computing open segments" ) {
683 THEN(
"They contain less lattice points than closed segments" ) {
684 REQUIRE( nb_open_segment_smaller_than_segment == N );
686 THEN(
"When dilated, they contain less lattice points than dilated closed segments" ) {
687 REQUIRE( nb_dilated_open_segment_smaller_than_dilated_segment == N );
689 THEN(
"When dilated, they contain more lattice points than the interior of dilated closed segments" ) {
690 REQUIRE( nb_dilated_open_segment_greater_than_interior_dilated_segment == N );
696SCENARIO(
"ConvexityHelper< 3 > open triangle tests",
697 "[convexity_helper][open triangle][3d]" )
700 typedef Helper::Point
Point;
702 typedef Helper::LatticePolytope::UnitSegment UnitSegment;
704 auto nb_open_triangle_smaller_than_triangle = 0;
705 auto nb_dilated_open_triangle_smaller_than_dilated_triangle = 0;
706 auto nb_dilated_open_triangle_greater_than_interior_dilated_triangle = 0;
709 for (
auto n = 0; n < N; n++ )
714 a =
Point( rand() %
K, rand() %
K, rand() %
K );
715 b =
Point( rand() %
K, rand() %
K, rand() %
K );
716 c =
Point( rand() %
K, rand() %
K, rand() %
K );
717 std::vector< Point > X = { a, b, c };
721 Helper::LatticePolytope CS = Helper::compute3DTriangle( a, b, c,
true );
722 Helper::LatticePolytope OS = Helper::compute3DOpenTriangle( a, b, c,
true );
726 auto cs_in = CS.count();
727 auto os_in = OS.count();
729 nb_open_triangle_smaller_than_triangle += ( os_in < cs_in ) ? 1 : 0;
733 CS += UnitSegment( k );
734 OS += UnitSegment( k );
739 auto cs_in = CS.count();
740 auto cs_int = CS.countInterior();
741 auto os_in = OS.count();
744 nb_dilated_open_triangle_smaller_than_dilated_triangle
745 += ( os_in < cs_in ) ? 1 : 0;
746 nb_dilated_open_triangle_greater_than_interior_dilated_triangle
747 += ( cs_int <= os_in ) ? 1 : 0;
750 WHEN(
"Computing open triangles" ) {
751 THEN(
"They contain less lattice points than closed triangles" ) {
752 REQUIRE( nb_open_triangle_smaller_than_triangle == N );
754 THEN(
"When dilated, they contain less lattice points than dilated closed triangles" ) {
755 REQUIRE( nb_dilated_open_triangle_smaller_than_dilated_triangle == N );
757 THEN(
"When dilated, they contain more lattice points than the interior of dilated closed triangles" ) {
758 REQUIRE( nb_dilated_open_triangle_greater_than_interior_dilated_triangle == N );
auto crossProduct(PointVector< 3, LeftEuclideanRing, LeftContainer > const &lhs, PointVector< 3, RightEuclideanRing, RightContainer > const &rhs) -> decltype(DGtal::constructFromArithmeticConversion(lhs, rhs))
Cross product of two 3D Points/Vectors.