34#include "DGtal/base/Common.h"
35#include "DGtal/kernel/SpaceND.h"
36#include "DGtal/topology/KhalimskySpaceND.h"
37#include "DGtal/geometry/volumes/CellGeometry.h"
38#include "DGtal/geometry/volumes/DigitalConvexity.h"
39#include "DGtal/geometry/tools/AffineGeometry.h"
40#include "DGtal/geometry/tools/AffineBasis.h"
41#include "DGtalCatch.h"
52SCENARIO(
"DigitalConvexity< Z2 > unit tests",
"[digital_convexity][2d]" )
58 DConvexity dconv(
Point( -5, -5 ),
Point( 10, 10 ) );
60 GIVEN(
"Given a fat simplex { (0,0), (4,-1), (2,5) } " ) {
62 auto vertex_cover = dconv.
makeCellCover( V.begin(), V.end() );
63 auto fat_simplex = dconv.
makeSimplex ( V.begin(), V.end() );
66 auto point_cover = dconv.
makeCellCover( inside_pts.begin(), inside_pts.end() );
67 THEN(
"The fat simplex is not degenerated." ) {
70 THEN(
"Its vertex cover contains 3 0-cells, 12 1-cells, 12 2-cells" ) {
71 REQUIRE( vertex_cover.computeNbCells( 0 ) == 3 );
72 REQUIRE( vertex_cover.computeNbCells( 1 ) == 12 );
73 REQUIRE( vertex_cover.computeNbCells( 2 ) == 12 );
75 THEN(
"Its vertex cover is a subset of its point cover" ) {
76 REQUIRE( vertex_cover.subset( point_cover ) );
78 THEN(
"Its point cover is a subset of its simplex cover" ) {
79 REQUIRE( point_cover.subset( simplex_cover ) );
81 THEN(
"Being fat, its simplex cover is equal to its point cover" ) {
82 REQUIRE( simplex_cover.subset( point_cover ) );
85 GIVEN(
"Given a thin simplex { (0,0), (4,3), (7,5) } " ) {
87 auto vertex_cover = dconv.
makeCellCover( V.begin(), V.end() );
88 auto thin_simplex = dconv.
makeSimplex ( V.begin(), V.end() );
91 auto point_cover = dconv.
makeCellCover( inside_pts.begin(), inside_pts.end() );
92 THEN(
"The thin simplex is not degenerated." ) {
95 THEN(
"Its vertex cover contains 3 0-cells, 12 1-cells, 12 2-cells" ) {
96 REQUIRE( vertex_cover.computeNbCells( 0 ) == 3 );
97 REQUIRE( vertex_cover.computeNbCells( 1 ) == 12 );
98 REQUIRE( vertex_cover.computeNbCells( 2 ) == 12 );
100 THEN(
"Its vertex cover is a subset of its point cover" ) {
101 REQUIRE( vertex_cover.subset( point_cover ) );
103 THEN(
"Its point cover is a subset of its simplex cover" ) {
104 REQUIRE( point_cover.subset( simplex_cover ) );
106 THEN(
"Being thin, its simplex cover is not equal to its point cover for 1<=dim<=2" ) {
107 REQUIRE( ! simplex_cover.subset( point_cover ) );
108 REQUIRE( simplex_cover.subset( point_cover, 0 ) );
109 REQUIRE( ! simplex_cover.subset( point_cover, 1 ) );
110 REQUIRE( ! simplex_cover.subset( point_cover, 2 ) );
115SCENARIO(
"DigitalConvexity< Z2 > fully convex triangles",
"[convex_simplices][2d]" )
124 DConvexity dconv(
Point( -1, -1 ),
Point( 5, 5 ) );
126 WHEN(
"Computing all triangles in domain (0,0)-(4,4)." ) {
127 unsigned int nb_notsimplex = 0;
128 unsigned int nb_invalid = 0;
129 unsigned int nb_degenerated= 0;
130 unsigned int nb_common = 0;
131 unsigned int nb_unitary = 0;
138 nb_degenerated += tri_type == DConvexity::SimplexType::DEGENERATED ? 1 : 0;
139 nb_invalid += tri_type == DConvexity::SimplexType::INVALID ? 1 : 0;
140 nb_unitary += tri_type == DConvexity::SimplexType::UNITARY ? 1 : 0;
141 nb_common += tri_type == DConvexity::SimplexType::COMMON ? 1 : 0;
143 THEN(
"All 2737 invalid triangles are degenerated " ) {
145 REQUIRE( nb_notsimplex == nb_degenerated );
146 REQUIRE( nb_degenerated == 2737 );
148 THEN(
"There are 12888 valid triangles" ) {
149 REQUIRE( nb_unitary + nb_common == 12888 );
151 THEN(
"There are fewer (1920) unitary triangles than common triangles (10968)" ) {
154 REQUIRE( nb_unitary < nb_common );
156 THEN(
"The total number of triangles (unitary, common, degenerated) is (domain size)^3, i.e. 5^6" ) {
157 REQUIRE( nb_unitary + nb_common + nb_degenerated == 5*5*5*5*5*5 );
160 WHEN(
"Computing all triangles in domain (0,0)-(4,4)." ) {
161 unsigned int nbsimplex= 0;
162 unsigned int nb0 = 0;
163 unsigned int nb1 = 0;
164 unsigned int nb2 = 0;
165 unsigned int nb01_not2 = 0;
170 if ( ! ( ( a < b ) && ( b < c ) ) )
continue;
173 bool cvx0 = dconv.
isKConvex( triangle, 0 );
174 bool cvx1 = dconv.
isKConvex( triangle, 1 );
175 bool cvx2 = dconv.
isKConvex( triangle, 2 );
180 nb01_not2 += ( cvx0 && cvx1 && ! cvx2 ) ? 1 : 0;
182 THEN(
"All valid triangles are 0-convex." ) {
185 THEN(
"There are less 1-convex and 2-convex than 0-convex." ) {
189 THEN(
"When the triangle is 0-convex and 1-convex, then it is 2-convex." ) {
195SCENARIO(
"DigitalConvexity< Z3 > fully convex tetrahedra",
"[convex_simplices][3d]" )
204 DConvexity dconv(
Point( -1, -1, -1 ),
Point( 4, 4, 4 ) );
206 WHEN(
"Computing all lexicographically ordered tetrahedra anchored at (0,0,0) in domain (0,0,0)-(3,3,3)." ) {
207 unsigned int nb_notsimplex = 0;
208 unsigned int nb_invalid = 0;
209 unsigned int nb_degenerated= 0;
210 unsigned int nb_common = 0;
211 unsigned int nb_unitary = 0;
217 if ( ! ( ( a < b ) && ( b < c ) && ( c < d ) ) )
continue;
219 auto tri_type = dconv.
simplexType( { a, b, c, d } );
220 nb_degenerated += tri_type == DConvexity::SimplexType::DEGENERATED ? 1 : 0;
221 nb_invalid += tri_type == DConvexity::SimplexType::INVALID ? 1 : 0;
222 nb_unitary += tri_type == DConvexity::SimplexType::UNITARY ? 1 : 0;
223 nb_common += tri_type == DConvexity::SimplexType::COMMON ? 1 : 0;
225 THEN(
"All 4228 invalid tetrahedra are degenerated " ) {
227 REQUIRE( nb_notsimplex == nb_degenerated );
228 REQUIRE( nb_degenerated == 4228 );
230 THEN(
"There are 35483 valid tetrahedra" ) {
231 REQUIRE( nb_unitary + nb_common == 35483 );
233 THEN(
"There are fewer (2515) unitary triangles than common triangles (32968)" ) {
236 REQUIRE( nb_unitary < nb_common );
238 THEN(
"The total number of triangles (unitary, common, degenerated) is 39711" ) {
239 REQUIRE( nb_unitary + nb_common + nb_degenerated == 39711 );
242 WHEN(
"Computing many tetrahedra in domain (0,0,0)-(4,4,4)." ) {
243 const unsigned int nb = 50;
244 unsigned int nbsimplex= 0;
245 unsigned int nb0 = 0;
246 unsigned int nb1 = 0;
247 unsigned int nb2 = 0;
248 unsigned int nb3 = 0;
249 unsigned int nb012_not3 = 0;
250 unsigned int nbf = 0;
251 unsigned int nbfg = 0;
252 unsigned int nbffast = 0;
253 unsigned int nb0123 = 0;
254 unsigned int nbdim3 = 0;
255 unsigned int nbfull = 0;
256 for (
unsigned int i = 0; i < nb; ++i )
258 Point a( rand() % 5, rand() % 5, rand() % 5 );
259 Point b( rand() % 5, rand() % 5, rand() % 5 );
260 Point c( rand() % 5, rand() % 5, rand() % 5 );
261 Point d( rand() % 5, rand() % 5, rand() % 5 );
265 nbdim3 += (
dim == 3 ) ? 1 : 0;
267 std::vector< Point > X;
276 if ( cvxf != cvxfg || cvxf != cvxffast) {
277 bool cvxfc = dconv.
FC( X ).size() == X.size();
278 std::cout <<
"[0123 " << cvx0 << cvx1 << cvx2 << cvx3 <<
"] "
279 <<
"[K " << cvxf <<
"] [M " << cvxfg
280 <<
"] [MF " << cvxffast <<
"] [FC " << cvxfc <<
"] "
281 << a << b << c << d <<
"\n";
283 for (
auto p : X ) std::cout <<
" " << p;
292 nbfg += cvxfg ? 1 : 0;
293 nbffast += cvxffast ? 1 : 0;
294 nb0123 += ( cvx0 && cvx1 && cvx2 && cvx3 ) ? 1 : 0;
295 nb012_not3+= ( cvx0 && cvx1 && cvx2 && ! cvx3 ) ? 1 : 0;
297 THEN(
"All valid tetrahedra are 0-convex." ) {
300 THEN(
"All full dimensional simplices have affine dimension 3" ) {
303 THEN(
"There are less 1-convex, 2-convex and 3-convex than 0-convex." ) {
308 THEN(
"When the tetrahedron is 0-convex, 1-convex and 2-convex, then it is 3-convex." ) {
314 THEN(
"All methods for computing full convexity agree." ) {
321SCENARIO(
"DigitalConvexity< Z3 > rational fully convex tetrahedra",
"[convex_simplices][3d][rational]" )
327 DConvexity dconv(
Point( -10, -10, -10 ),
Point( 100, 100, 100 ) );
328 WHEN(
"Computing many tetrahedra in domain (0,0,0)-(4,4,4)." ) {
329 const unsigned int nb = 30;
330 unsigned int nbsimplex= 0;
331 unsigned int nb0 = 0;
332 unsigned int nb1 = 0;
333 unsigned int nb2 = 0;
334 unsigned int nb3 = 0;
335 unsigned int nb012_not3 = 0;
336 unsigned int nbf = 0;
337 unsigned int nb0123 = 0;
338 for (
unsigned int i = 0; i < nb; ++i )
340 Point a( 2*(rand() % 10), rand() % 20, 2*(rand() % 10) );
341 Point b( rand() % 20, 2*(rand() % 10), 2*(rand() % 10) );
342 Point c( 2*(rand() % 10), 2*(rand() % 10), rand() % 20 );
343 Point d( 2*(rand() % 10), 2*(rand() % 10), 2*(rand() % 10) );
357 nb0123 += ( cvx0 && cvx1 && cvx2 && cvx3 ) ? 1 : 0;
358 nb012_not3+= ( cvx0 && cvx1 && cvx2 && ! cvx3 ) ? 1 : 0;
360 THEN(
"All valid tetrahedra are 0-convex." ) {
363 THEN(
"There are less 1-convex, 2-convex and 3-convex than 0-convex." ) {
368 THEN(
"When the tetrahedron is 0-convex, 1-convex and 2-convex, then it is 3-convex." ) {
383SCENARIO(
"DigitalConvexity< Z2 > rational fully convex triangles",
"[convex_simplices][2d][rational]" )
389 DConvexity dconv(
Point( -1, -1 ),
Point( 30, 30 ) );
390 WHEN(
"Computing many triangle in domain (0,0)-(9,9)." ) {
391 const unsigned int nb = 50;
392 unsigned int nbsimplex= 0;
393 unsigned int nb0 = 0;
394 unsigned int nb1 = 0;
395 unsigned int nb2 = 0;
396 unsigned int nb01_not2 = 0;
397 unsigned int nbf = 0;
398 unsigned int nb012 = 0;
399 for (
unsigned int i = 0; i < nb; ++i )
401 Point a( 2*(rand() % 10), rand() % 20 );
402 Point b( rand() % 20 , 2*(rand() % 10) );
403 Point c( 2*(rand() % 10), 2*(rand() % 10) );
406 bool cvx0 = dconv.
isKConvex( triangle, 0 );
407 bool cvx1 = dconv.
isKConvex( triangle, 1 );
408 bool cvx2 = dconv.
isKConvex( triangle, 2 );
415 nb012 += ( cvx0 && cvx1 && cvx2 ) ? 1 : 0;
416 nb01_not2 += ( cvx0 && cvx1 && ! cvx2 ) ? 1 : 0;
418 THEN(
"All valid tetrahedra are 0-convex." ) {
421 THEN(
"There are less 1-convex, 2-convex than 0-convex." ) {
425 THEN(
"When the tetrahedron is 0-convex, and 1-convex, then it is 2-convex." ) {
438SCENARIO(
"DigitalConvexity< Z3 > full subconvexity of segments and triangles",
"[subconvexity][3d]" )
447 DConvexity dconv(
Point( -6, -6, -6 ),
Point( 6, 6, 6 ) );
449 WHEN(
"Computing many tetrahedra" ) {
450 const unsigned int nb = 50;
451 unsigned int nb_fulldim = 0;
452 unsigned int nb_ok_seg = 0;
453 unsigned int nb_ok_tri = 0;
454 for (
unsigned int l = 0; l < nb; ++l )
456 const Point a { (rand() % 10 - 5), (rand() % 10 - 5), (rand() % 10 - 5) };
457 const Point b { (rand() % 10 - 5), (rand() % 10 - 5), (rand() % 10 - 5) };
458 const Point c { (rand() % 10 - 5), (rand() % 10 - 5), (rand() % 10 - 5) };
459 const Point d { (rand() % 10 - 5), (rand() % 10 - 5), (rand() % 10 - 5) };
460 const std::vector<Point> pts = { a, b, c, d };
462 nb_fulldim += fulldim ? 1 : 0;
463 if ( ! fulldim )
continue;
464 auto simplex = dconv.
makeSimplex( pts.cbegin(), pts.cend() );
467 unsigned int nb_subconvex = 0;
468 unsigned int nb_total = 0;
469 for (
unsigned int i = 0; i < 4; i++ )
470 for (
unsigned int j = i+1; j < 4; j++ )
472 auto segment = dconv.
makeSimplex( { pts[ i ], pts[ j ] } );
474 nb_subconvex += ok ? 1 : 0;
477 trace.
info() <<
"****** SEGMENT NOT SUBCONVEX ******" << std::endl;
478 trace.
info() <<
"splx v =" << a << b << c << d << std::endl;
479 trace.
info() <<
"simplex=" << simplex << std::endl;
480 trace.
info() <<
"seg v =" << pts[ i ] << pts[ j ] << std::endl;
481 trace.
info() <<
"segment=" << segment << std::endl;
484 nb_ok_seg += ( nb_subconvex == nb_total ) ? 1 : 0;
487 unsigned int nb_subconvex = 0;
488 unsigned int nb_total = 0;
489 for (
unsigned int i = 0; i < 4; i++ )
490 for (
unsigned int j = i+1; j < 4; j++ )
491 for (
unsigned int k = j+1; k < 4; k++ )
493 auto triangle = dconv.
makeSimplex({ pts[ i ], pts[ j ], pts[ k ] });
495 nb_subconvex += ok ? 1 : 0;
498 trace.
info() <<
"****** TRIANGLE NOT SUBCONVEX ****" << std::endl;
499 trace.
info() <<
"splx v =" << a << b << c << d << std::endl;
500 trace.
info() <<
"simplex=" << simplex << std::endl;
501 trace.
info() <<
"tri v =" << pts[ i ] << pts[ j ]
502 << pts[ k ] << std::endl;
503 trace.
info() <<
"triangle=" << triangle << std::endl;
506 nb_ok_tri += ( nb_subconvex == nb_total ) ? 1 : 0;
509 THEN(
"At least half the tetrahedra are full dimensional." ) {
510 REQUIRE( nb_fulldim >= nb / 2 );
512 THEN(
"All segments of a tetrahedron should be subconvex to it." ) {
513 REQUIRE( nb_ok_seg == nb_fulldim );
515 THEN(
"All triangles of a tetrahedron should be subconvex to it." ) {
516 REQUIRE( nb_ok_tri == nb_fulldim );
521SCENARIO(
"DigitalConvexity< Z3 > full convexity of polyhedra",
"[full_convexity][3d]" )
530 DConvexity dconv(
Point( -36, -36, -36 ),
Point( 36, 36, 36 ) );
532 const unsigned int nb = 10;
533 unsigned int nbfg = 0;
534 unsigned int nbffast = 0;
535 unsigned int nbfenv = 0;
537 std::vector< PointRange > XX;
538 for (
unsigned int i = 0; i < nb; ++i )
540 unsigned int k = 100;
542 for (
unsigned int j = 0; j < k; ++ j )
543 X[ j ] =
Point( rand() % 10, rand() % 10, rand() % 10 );
551 for (
const auto& X : XX )
554 nbfg += fcvx ? 1 : 0;
558 for (
const auto& X : XX )
561 nbffast += fcvx ? 1 : 0;
565 for (
const auto& X : XX )
567 auto card = dconv.
envelope( X ).size();
568 bool fcvx = card == X.size();
569 nbfenv += fcvx ? 1 : 0;
572 WHEN(
"Computing many polytopes." ) {
573 THEN(
"All three methods agree on full convexity results" ) {
584SCENARIO(
"DigitalConvexity< Z4 > full convexity of polyhedra",
"[full_convexity][4d]" )
593 DConvexity dconv(
Point( -36, -36, -36, -36 ),
Point( 36, 36, 36, 36 ) );
595 const unsigned int nb = 4;
596 unsigned int nbfg = 0;
597 unsigned int nbffast = 0;
598 unsigned int nbfenv = 0;
600 std::vector< PointRange > XX;
601 for (
unsigned int i = 0; i < nb; ++i )
603 unsigned int k = 100;
605 for (
unsigned int j = 0; j < k; ++ j )
606 X[ j ] =
Point( rand() % 8, rand() % 8, rand() % 8, rand() % 8 );
614 for (
const auto& X : XX )
617 nbfg += fcvx ? 1 : 0;
621 for (
const auto& X : XX )
624 nbffast += fcvx ? 1 : 0;
628 for (
const auto& X : XX )
630 auto card = dconv.
envelope( X ).size();
631 bool fcvx = card == X.size();
632 nbfenv += fcvx ? 1 : 0;
635 WHEN(
"Computing many polytopes." ) {
636 THEN(
"All three methods agree on full convexity results" ) {
646SCENARIO(
"DigitalConvexity< Z2 > sub-convexity of polyhedra",
"[full_subconvexity][2d]" )
652 DConvexity dconv(
Point( -36, -36 ),
Point( 36, 36 ) );
654 std::vector< Point > X( k );
655 X[ 0 ] =
Point( 0,0 );
656 X[ 1 ] =
Point( 7,-2 );
657 X[ 2 ] =
Point( 3,6 );
658 X[ 3 ] =
Point( 5, 5 );
659 X[ 4 ] =
Point( 2, 3 );
660 X[ 5 ] =
Point( -1, 1 );
664 REQUIRE( CG.nbCells() ==
L.size() );
665 for (
unsigned int i = 0; i < k; i++ )
666 for (
unsigned int j = i+1; j < k; j++ )
668 std::vector< Point > Z { X[ i ], X[ j ] };
674 REQUIRE( tangent_old == tangent_new );
675 REQUIRE( tangent_ab_old == tangent_ab_new );
676 REQUIRE( tangent_new == tangent_ab_new );
680SCENARIO(
"DigitalConvexity< Z3 > sub-convexity of polyhedra",
"[full_subconvexity][3d]" )
686 DConvexity dconv(
Point( -36, -36, -36 ),
Point( 36, 36, 36 ) );
687 std::vector< Point > X( 5 );
688 X[ 0 ] =
Point( 0,0,0 );
689 X[ 1 ] =
Point( 0,5,1 );
690 X[ 2 ] =
Point( 2,1,6 );
691 X[ 3 ] =
Point( 6,1,1 );
692 X[ 4 ] =
Point( -2,-2,-3 );
696 std::vector< Point > Y;
698 REQUIRE( CG.nbCells() ==
L.size() );
700 unsigned int nb_ok = 0;
701 unsigned int nb_tgt= 0;
702 for (
int i = 0; i < 100; i++ )
704 Point a( rand() % 6, rand() % 6, rand() % 6 );
705 Point b( rand() % 6, rand() % 6, rand() % 6 );
709 nb_tgt += tangent_ab_new ? 1 : 0;
710 nb_ok += ( tangent_ab_old == tangent_ab_new ) ? 1 : 0;
718SCENARIO(
"DigitalConvexity< Z3 > envelope",
"[envelope][3d]" )
724 DConvexity dconv(
Point( -36, -36, -36 ),
Point( 36, 36, 36 ) );
726 WHEN(
"Computing the envelope Z of a digital set X with direct algorithm" ) {
727 THEN(
"Z contains X" ){
728 for (
int k = 0; k < 5; k++ )
730 int n = 3 + ( rand() % 7 );
732 for (
int i = 0; i < n; i++ )
733 S.insert(
Point( rand() % 10, rand() % 10, rand() % 10 ) );
734 std::vector< Point > X( S.cbegin(), S.cend() );
736 auto Z = dconv.
envelope( X, DConvexity::EnvelopeAlgorithm::DIRECT );
739 bool Z_includes_X = std::includes( Z.cbegin(), Z.cend(),
740 X.cbegin(), X.cend() );
741 REQUIRE( X.size() <= Z.size() );
744 THEN(
"Z is fully convex" ){
745 for (
int k = 0; k < 5; k++ )
747 int n = 3 + ( rand() % 7 );
749 for (
int i = 0; i < n; i++ )
750 S.insert(
Point( rand() % 10, rand() % 10, rand() % 10 ) );
751 std::vector< Point > X( S.cbegin(), S.cend() );
760 WHEN(
"Computing the envelope Z of a digital set X with LatticeSet algorithm" ) {
761 THEN(
"Z contains X" ){
762 for (
int k = 0; k < 5; k++ )
764 int n = 3 + ( rand() % 7 );
766 for (
int i = 0; i < n; i++ )
767 S.insert(
Point( rand() % 10, rand() % 10, rand() % 10 ) );
768 std::vector< Point > X( S.cbegin(), S.cend() );
769 auto Z = dconv.
envelope( X, DConvexity::EnvelopeAlgorithm::LATTICE_SET );
771 bool Z_includes_X = std::includes( Z.cbegin(), Z.cend(),
772 X.cbegin(), X.cend() );
773 REQUIRE( X.size() <= Z.size() );
776 THEN(
"Z is fully convex" ){
777 for (
int k = 0; k < 5; k++ )
779 int n = 3 + ( rand() % 7 );
781 for (
int i = 0; i < n; i++ )
782 S.insert(
Point( rand() % 10, rand() % 10, rand() % 10 ) );
783 std::vector< Point > X( S.cbegin(), S.cend() );
793SCENARIO(
"DigitalConvexity< Z2 > envelope",
"[envelope][2d]" )
799 DConvexity dconv(
Point( -360, -360 ),
Point( 360, 360 ) );
801 WHEN(
"Computing the envelope Z of two points" ) {
802 THEN(
"it requires at most one iteration" ){
803 for (
int k = 0; k < 10; k++ )
805 std::vector< Point > X;
806 X.push_back(
Point( rand() % 100, rand() % 100 ) );
807 X.push_back(
Point( rand() % 100, rand() % 100 ) );
808 std::sort( X.begin(), X.end() );
816SCENARIO(
"DigitalConvexity< Z2 > relative envelope",
"[rel_envelope][2d]" )
822 DConvexity dconv(
Point( -360, -360 ),
Point( 360, 360 ) );
824 std::vector< Point > X {
Point( -10, -7 ),
Point( 10, 7 ) };
825 std::vector< Point > Y {
Point( -11, -6 ),
Point( 9, 8 ) };
826 std::sort( X.begin(), X.end() );
827 std::sort( Y.begin(), Y.end() );
832 WHEN(
"Computing the envelope of X relative to Y and Y relative to X" ) {
835 THEN(
"Both sets are fully convex" ){
839 THEN(
"There are inclusion rules between sets" ){
842 REQUIRE( std::includes( Y.cbegin(), Y.cend(),
843 FC_X_rel_Y.cbegin(), FC_X_rel_Y.cend() ) );
844 REQUIRE( std::includes( X.cbegin(), X.cend(),
845 FC_Y_rel_X.cbegin(), FC_Y_rel_X.cend() ) );
848 WHEN(
"Computing the envelope of X relative to Y specified by a predicate" ) {
849 auto PredY = [] (
Point p )
850 {
return ( -4 <= p.dot(
Point( 2,5 ) ) ) && ( p.dot(
Point( 2,5 ) ) < 9 ); };
852 THEN(
"It is fully convex and included in Y" ){
857 for (
auto p : FC_X_rel_Y )
859 nb_in += PredY( p ) ? 1 : 0;
867SCENARIO(
"DigitalConvexity< Z3 > relative envelope",
"[rel_envelope][3d]" )
873 DConvexity dconv(
Point( -360, -360, -360 ),
Point( 360, 360, 360 ) );
875 std::vector< Point > X {
Point( -61, -20, -8 ),
Point( 43, 25, 9 ) };
876 std::vector< Point > Y {
Point( -50, -27, -10 ),
Point( 40, 37, 17 ) };
877 std::sort( X.begin(), X.end() );
878 std::sort( Y.begin(), Y.end() );
883 WHEN(
"Computing the envelope of X relative to Y and Y relative to X" ) {
886 THEN(
"Both sets are fully convex" ){
890 THEN(
"There are inclusion rules between sets" ){
893 REQUIRE( std::includes( Y.cbegin(), Y.cend(),
894 FC_X_rel_Y.cbegin(), FC_X_rel_Y.cend() ) );
895 REQUIRE( std::includes( X.cbegin(), X.cend(),
896 FC_Y_rel_X.cbegin(), FC_Y_rel_X.cend() ) );
902SCENARIO(
"DigitalConvexity< Z3 > full subconvexity of triangles",
"[subconvexity][3d]" )
911 DConvexity dconv(
Point( -6, -6, -6 ),
Point( 6, 6, 6 ) );
914 WHEN(
"Computing many tetrahedra" ) {
915 const unsigned int nb = 50;
916 unsigned int nb_fulldim = 0;
917 unsigned int nb_ok_tri1 = 0;
918 unsigned int nb_ok_tri2 = 0;
919 for (
unsigned int l = 0; l < nb; ++l )
921 const Point a { (rand() % 10 - 5), (rand() % 10 - 5), (rand() % 10 - 5) };
922 const Point b { (rand() % 10 - 5), (rand() % 10 - 5), (rand() % 10 - 5) };
923 const Point c { (rand() % 10 - 5), (rand() % 10 - 5), (rand() % 10 - 5) };
924 const Point d { (rand() % 10 - 5), (rand() % 10 - 5), (rand() % 10 - 5) };
925 const std::vector<Point> pts = { a, b, c, d };
927 nb_fulldim += fulldim ? 1 : 0;
928 if ( ! fulldim )
continue;
929 auto simplex = dconv.
makeSimplex( pts.cbegin(), pts.cend() );
933 unsigned int nb_subconvex1 = 0;
934 unsigned int nb_subconvex2 = 0;
935 unsigned int nb_total = 0;
936 for (
unsigned int i = 0; i < 4; i++ )
937 for (
unsigned int j = i+1; j < 4; j++ )
938 for (
unsigned int k = j+1; k < 4; k++ )
940 auto tri1 = dconv.
makeSimplex({ pts[ i ], pts[ j ], pts[ k ] });
943 nb_subconvex1 += ok1 ? 1 : 0;
944 nb_subconvex2 += ok2 ? 1 : 0;
947 trace.
info() <<
"****** TRIANGLE NOT SUBCONVEX ****" << std::endl;
948 trace.
info() <<
"splx v =" << a << b << c << d << std::endl;
949 trace.
info() <<
"simplex=" << simplex << std::endl;
950 trace.
info() <<
"tri v =" << pts[ i ] << pts[ j ]
951 << pts[ k ] << std::endl;
952 trace.
info() <<
"tri1=" << tri1 << std::endl;
955 trace.
info() <<
"****** TRIANGLE 3D NOT SUBCONVEX ****" << std::endl;
956 trace.
info() <<
"splx v =" << a << b << c << d << std::endl;
957 trace.
info() <<
"simplex=" << simplex << std::endl;
958 trace.
info() <<
"tri v =" << pts[ i ] << pts[ j ]
959 << pts[ k ] << std::endl;
962 nb_ok_tri1 += ( nb_subconvex1 == nb_total ) ? 1 : 0;
963 nb_ok_tri2 += ( nb_subconvex2 == nb_total ) ? 1 : 0;
966 THEN(
"All triangles of a tetrahedron should be subconvex to it." ) {
967 REQUIRE( nb_ok_tri1 == nb_fulldim );
969 THEN(
"All 3D triangles of a tetrahedron should be subconvex to it." ) {
970 REQUIRE( nb_ok_tri2 == nb_fulldim );
976SCENARIO(
"DigitalConvexity< Z3 > full subconvexity of points and triangles",
"[subconvexity][3d]" )
986 DConvexity dconv (
Point( -21, -21, -21 ),
Point( 21, 21, 21 ) );
988 WHEN(
"Computing many tetrahedra" ) {
989 const unsigned int nb = 50;
990 unsigned int nb_total = 0;
991 unsigned int nb_ok_tri = 0;
992 unsigned int nb_subconvex1 = 0;
993 unsigned int nb_subconvex2 = 0;
994 for (
unsigned int l = 0; l < nb; ++l )
996 const Point a { (rand() % 10 - 10), (rand() % 10 - 10), (rand() % 10 - 10) };
997 const Point b { (rand() % 20 ), (rand() % 20 - 10), (rand() % 20 - 10) };
998 const Point c { (rand() % 20 - 10), (rand() % 20 ), (rand() % 20 - 10) };
999 const Point d { (rand() % 20 - 10), (rand() % 20 - 10), (rand() % 20 ) };
1000 const std::vector<Point> pts = { a, b, c, d };
1002 if ( ! fulldim )
continue;
1003 auto simplex = dconv.
makeSimplex( pts.cbegin(), pts.cend() );
1007 for (
unsigned int i = 0; i < 100; i++ )
1009 const Point p { (rand() % 10 - 5), (rand() % 10 - 5), (rand() % 10 - 5) };
1010 const Point q { (rand() % 10 - 5), (rand() % 10 - 5), (rand() % 10 - 5) };
1011 const Point r { (rand() % 10 - 5), (rand() % 10 - 5), (rand() % 10 - 5) };
1013 if ( n == Vector::zero )
continue;
1017 nb_subconvex1 += ok1 ? 1 : 0;
1018 nb_subconvex2 += ok2 ? 1 : 0;
1020 std::cout <<
"***** FULL SUBCONVEXITY ERROR ON TRIANGLE ****" << std::endl;
1021 std::cout <<
"splx v =" << a << b << c << d << std::endl;
1022 std::cout <<
"simplex=" << simplex << std::endl;
1023 std::cout <<
"tri v =" << p << q << r << std::endl;
1024 std::cout <<
"tri1=" << tri1 << std::endl;
1025 std::cout <<
"tri1 is fully subconvex: " << ( ok1 ?
"YES" :
"NO" ) << std::endl;
1026 std::cout <<
"3 points are fully subconvex: " << ( ok2 ?
"YES" :
"NO" ) << std::endl;
1028 nb_ok_tri += ( ok1 == ok2 ) ? 1 : 0;
1033 THEN(
"The number of triangles and point triplets subconvex to it should be equal." ) {
1034 REQUIRE( nb_subconvex1 == nb_subconvex2 );
1036 THEN(
"Full subconvexity should agree on every subset." ) {
1037 REQUIRE( nb_ok_tri == nb_total );
1043SCENARIO(
"DigitalConvexity< Z3 > full covering of segments",
"[full_cover][3d]" )
1053 DConvexity dconv (
Point( -21, -21, -21 ),
Point( 21, 21, 21 ) );
1080SCENARIO(
"DigitalConvexity< Z3 > full covering of triangles",
"[full_cover][3d]" )
1090 DConvexity dconv (
Point( -21, -21, -21 ),
Point( 21, 21, 21 ) );
1122SCENARIO(
"DigitalConvexity< Z3 > full subconvexity and full covering of triangles",
"[subconvexity][3d][full_cover]" )
1132 DConvexity dconv (
Point( -21, -21, -21 ),
Point( 21, 21, 21 ) );
1134 WHEN(
"Computing many tetrahedra" ) {
1135 const unsigned int nb = 50;
1136 unsigned int nb_total = 0;
1137 unsigned int nb_ok_tri = 0;
1138 unsigned int nb_ok_seg = 0;
1139 unsigned int nb_ko_seg = 0;
1140 unsigned int nb_subconvex = 0;
1141 unsigned int nb_covered = 0;
1142 for (
unsigned int l = 0; l < nb; ++l )
1144 const Point a { (rand() % 10 - 10), (rand() % 10 - 10), (rand() % 10 - 10) };
1145 const Point b { (rand() % 20 ), (rand() % 20 - 10), (rand() % 20 - 10) };
1146 const Point c { (rand() % 20 - 10), (rand() % 20 ), (rand() % 20 - 10) };
1147 const Point d { (rand() % 20 - 10), (rand() % 20 - 10), (rand() % 20 ) };
1148 const std::vector<Point> pts = { a, b, c, d };
1150 if ( ! fulldim )
continue;
1151 auto simplex = dconv.
makeSimplex( pts.cbegin(), pts.cend() );
1155 for (
unsigned int i = 0; i < 100; i++ )
1157 const Point p { (rand() % 10 - 5), (rand() % 10 - 5), (rand() % 10 - 5) };
1158 const Point q { (rand() % 10 - 5), (rand() % 10 - 5), (rand() % 10 - 5) };
1159 const Point r { (rand() % 10 - 5), (rand() % 10 - 5), (rand() % 10 - 5) };
1161 if ( n == Vector::zero )
continue;
1169 else nb_ko_seg += 1;
1171 else nb_ko_seg += 1;
1173 else nb_ko_seg += 1;
1176 nb_subconvex += ok1 ? 1 : 0;
1177 nb_covered += ok2 ? 1 : 0;
1178 bool ok = ok1 == ok2;
1181 std::cout <<
"***** FULL SUBCONVEXITY ERROR ON TRIANGLE ****" << std::endl;
1182 std::cout <<
"splx v =" << a << b << c << d << std::endl;
1183 std::cout <<
"simplex=" << simplex << std::endl;
1184 std::cout <<
"tri v =" << p << q << r << std::endl;
1185 std::cout <<
"tri1=" << tri1 << std::endl;
1186 std::cout <<
"3 points are fully subconvex: " << ( ok1 ?
"YES" :
"NO" ) << std::endl;
1187 std::cout <<
"3 points are fully covered by star: " << ( ok2 ?
"YES" :
"NO" ) << std::endl;
1189 nb_ok_tri += ( ok ) ? 1 : 0;
1194 THEN(
"The number of subconvex and covered triangles should be equal." ) {
1195 REQUIRE( nb_subconvex == nb_covered );
1197 THEN(
"Full subconvexity and covering should agree on every subset." ) {
1198 REQUIRE( nb_ok_tri == nb_total );
1200 THEN(
"When a triangle is fully covered, its edges are fully covered also." ) {
1207SCENARIO(
"DigitalConvexity< Z3 > envelope bug",
"[envelope][3d]" )
1215 DConvexity dconv(
Point( -36, -36, -36 ),
Point( 36, 36, 36 ) );
1217 WHEN(
"Using basis B = (1, 0, -2) (1, 0, -1)" ) {
1218 std::vector< Point > b = {
Point( 0, 0, 0),
Point(1, 0, -2),
Point(1, 0, -1) };
1219 const auto [ o,
B ] = Affine::affineBasis( b );
1221 Basis AB(
Point( 0,0 ), b, Basis::Type::ECHELON_REDUCED );
1222 bool parallel = AB.isParallel( e );
1223 const auto [ d,
L, r ] = AB.decomposeVector( e );
1234 WHEN(
"Computing the envelope Z of a digital set X with direct algorithm" ) {
1235 std::vector< Point > X = {
Point(5, 1, 9),
Point(8, 1, 8),
Point(9, 1, 1) };
1237 THEN(
"Z is fully convex" ){
void getPoints(std::vector< Point > &pts) const
static PointRange insidePoints(const LatticePolytope &polytope)
static RationalPolytope makeRationalSimplex(Integer d, PointIterator itB, PointIterator itE)
bool isFullyCovered(const Point &a, const Point &b, const Point &c, const LatticeSet &cells) const
PointRange FC(const PointRange &Z, EnvelopeAlgorithm algo=EnvelopeAlgorithm::DIRECT) const
bool isKConvex(const LatticePolytope &P, const Dimension k) const
static bool isSimplexFullDimensional(PointIterator itB, PointIterator itE)
static LatticePolytope makeSimplex(PointIterator itB, PointIterator itE)
bool isFullyConvexFast(const PointRange &X) const
bool isFullyConvex(const PointRange &X, bool convex0=false) const
PointRange envelope(const PointRange &Z, EnvelopeAlgorithm algo=EnvelopeAlgorithm::DIRECT) const
PointRange relativeEnvelope(const PointRange &Z, const PointRange &Y, EnvelopeAlgorithm algo=EnvelopeAlgorithm::DIRECT) const
LatticeSet CoverCvxH(const Point &a, const Point &b, Dimension axis=dimension) const
bool isFullySubconvex(const PointRange &Y, const LatticeSet &StarX) const
LatticeSet StarCvxH(const PointRange &X, Dimension axis=dimension) const
Size depthLastEnvelope() const
LatticePolytope makePolytope(const PointRange &X, bool make_minkowski_summable=false) const
CellGeometry makeCellCover(PointIterator itB, PointIterator itE, Dimension i=0, Dimension k=KSpace::dimension) const
static SimplexType simplexType(PointIterator itB, PointIterator itE)
Aim: This class is a model of CCellularGridSpaceND. It represents the cubical grid as a cell complex,...
PointRange toPointRange() const
std::vector< Point > PointRange
DigitalPlane::Point Vector
DGtal::int64_t computeAffineDimension(const std::vector< TPoint > &X, const double tolerance=1e-12)
TPoint computeIndependentVector(const std::vector< TPoint > &basis, const double tolerance=1e-12)
DGtal is the top-level namespace which contains all DGtal functions and types.
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.
Aim: Utility class to determine the affine geometry of an input set of points. It provides exact resu...
Aim: Utility class to determine the affine geometry of an input set of points. It provides exact resu...
GIVEN("A cubical complex with random 3-cells")
HyperRectDomain< Space > Domain
REQUIRE(domain.isInside(aPoint))
SCENARIO("UnorderedSetByBlock< PointVector< 2, int > unit tests with 32 bits blocks", "[unorderedsetbyblock][2d]")