DGtal  1.2.0
testKhalimskySpaceND.cpp
Go to the documentation of this file.
1 
33 #include <cstddef>
34 #include <algorithm>
35 
36 #include "DGtal/base/Common.h"
37 #include "DGtal/kernel/SpaceND.h"
38 #include "DGtal/kernel/domains/HyperRectDomain.h"
39 
40 #include "DGtal/topology/KhalimskySpaceND.h"
41 #include "DGtal/topology/KhalimskyPreSpaceND.h"
42 
43 #include "DGtal/topology/CCellularGridSpaceND.h"
44 #include "DGtal/topology/CPreCellularGridSpaceND.h"
45 
46 #include "DGtal/topology/SurfelAdjacency.h"
47 #include "DGtal/topology/SurfelNeighborhood.h"
48 #include "DGtal/shapes/Shapes.h"
49 #include "DGtal/topology/helpers/Surfaces.h"
50 #include "DGtal/io/boards/Board2D.h"
51 #include "DGtal/io/Color.h"
52 
53 #include "DGtalCatch.h"
55 
56 using namespace DGtal;
57 using namespace std;
58 
60 
67 template < typename KSpace >
68 void testScan( KSpace const & K,
69  typename KSpace::Point const & low,
70  typename KSpace::Point const & high
71  )
72 {
73  INFO( "Testing uNext & sNext with low = " << low << " & high = " << high );
74 
75  using Point = typename KSpace::Point;
76  using Space = typename KSpace::Space;
77  using PK = typename KSpace::PreCellularGridSpace;
78 
79  const HyperRectDomain< Space > domain( low, high );
80 
81  // Looping through cell topology
82  for ( unsigned int t = 0; t < 1u << KSpace::dimension; ++t )
83  {
84  // Constructing the Khalimsky coordinates
85  Point refPoint;
86  for ( DGtal::Dimension i = 0; i < KSpace::dimension; ++i )
87  refPoint[ i ] = t & (1u << i) ? 1 : 0;
88 
89  INFO( "Current topology is " << refPoint );
90 
91  // Initializing unsigned cells
92  const auto refUCell = PK::uCell( refPoint );
93  auto currUCell = K.uCell( low, refUCell );
94  const auto lowUCell = currUCell;
95  const auto highUCell = K.uCell( high, refUCell );
96  REQUIRE( K.uTopology( currUCell ) == PK::uTopology( refUCell ) );
97 
98  // Initializing signed cells
99  const auto refSCell = PK::sCell( refPoint, PK::POS );
100  auto currSCell = K.sCell( low, refSCell );
101  const auto lowSCell = currSCell;
102  const auto highSCell = K.sCell( high, refSCell );
103  REQUIRE( K.sTopology( currSCell ) == PK::sTopology( refSCell ) );
104 
105  // Spanning the domain
106  bool uCheck = true;
107  bool sCheck = true;
108  for ( Point const & pt : domain )
109  {
110  REQUIRE( uCheck == true );
111  REQUIRE( sCheck == true );
112 
113  REQUIRE( currUCell == K.uCell( pt, refUCell ) );
114  REQUIRE( currSCell == K.sCell( pt, refSCell ) );
115 
116  uCheck = K.uNext( currUCell, lowUCell, highUCell );
117  sCheck = K.sNext( currSCell, lowSCell, highSCell );
118  }
119 
120  // Checking scan end conditions.
121  REQUIRE( uCheck == false );
122  REQUIRE( sCheck == false );
123  }
124 }
125 
127 
135 template < typename KSpace, typename Cells >
136 void cmpUCellsIfInside( KSpace const & K,
137  typename KSpace::Cells const & u,
138  Cells const & v
139  )
140 {
141  REQUIRE( u.size() <= v.size() );
142 
143  std::size_t cnt = 0;
144 
145  // Scanning the lists
146  for( auto const & cell : v )
147  {
148  if ( ! K.uIsInside( cell ) )
149  continue;
150 
151  REQUIRE( std::find( u.cbegin(), u.cend(), K.uCell( cell ) ) != u.cend() );
152 
153  ++cnt;
154  }
155 
156  // Checking counter
157  REQUIRE( u.size() == cnt );
158 }
159 
161 
169 template < typename KSpace, typename Cells >
170 void cmpSCellsIfInside( KSpace const & K,
171  typename KSpace::SCells const & u,
172  Cells const & v
173  )
174 {
175  REQUIRE( u.size() <= v.size() );
176 
177  std::size_t cnt = 0;
178 
179  // Scanning the lists
180  for( auto const & cell : v )
181  {
182  if ( ! K.sIsInside( cell ) )
183  continue;
184 
185  REQUIRE( std::find( u.cbegin(), u.cend(), K.sCell( cell ) ) != u.cend() );
186 
187  ++cnt;
188  }
189 
190  // Checking counter
191  REQUIRE( u.size() == cnt );
192 }
193 
195 
201 template < typename KSpace >
202 void testNeighborhood( KSpace const & K,
203  typename KSpace::Point const & aPoint
204  )
205 {
206  INFO( "Testing (proper) neighborhood around point " << aPoint );
207 
208  using Point = typename KSpace::Point;
209  using PK = typename KSpace::PreCellularGridSpace;
210 
211  // Looping through cell topology
212  for ( unsigned int t = 0; t < 1u << KSpace::dimension; ++t )
213  {
214  // Constructing the Khalimsky coordinates
215  Point refPoint;
216  for ( DGtal::Dimension i = 0; i < KSpace::dimension; ++i )
217  refPoint[ i ] = t & (1u << i) ? 1 : 0;
218 
219  INFO( "Current topology is " << refPoint );
220 
221  // Constructing the unsigned cell
222  const auto refUCell = PK::uCell( refPoint );
223 
224  if ( ! K.uIsInside( PK::uCell( aPoint, refUCell ) ) )
225  continue; // Do not continue if current point is outside space.
226 
227  const auto currUCell = K.uCell( aPoint, refUCell );
228  REQUIRE( K.uTopology( currUCell ) == PK::uTopology( refUCell ) );
229 
230  // Constructing the signed cell
231  const auto refSCell = PK::sCell( refPoint, PK::NEG );
232  const auto currSCell = K.sCell( aPoint, refSCell );
233  REQUIRE( K.sTopology( currSCell ) == PK::sTopology( refSCell ) );
234 
235  // Testing neighbordhoods
236  {
237  const auto currUCells = K.uNeighborhood( currUCell );
238  const auto refUCells = PK::uNeighborhood( currUCell );
239  const auto currSCells = K.sNeighborhood( currSCell );
240  const auto refSCells = PK::sNeighborhood( currSCell );
241 
242  REQUIRE( currUCells.size() == currSCells.size() );
243  REQUIRE( refUCells.size() == refSCells.size() );
244  REQUIRE( refUCells.size() == 2*K.dimension + 1 );
245  cmpUCellsIfInside( K, currUCells, refUCells );
246  cmpSCellsIfInside( K, currSCells, refSCells );
247  }
248 
249  // Testing proper neighbordhoods
250  {
251  const auto currUCells = K.uProperNeighborhood( currUCell );
252  const auto refUCells = PK::uProperNeighborhood( currUCell );
253  const auto currSCells = K.sProperNeighborhood( currSCell );
254  const auto refSCells = PK::sProperNeighborhood( currSCell );
255 
256  REQUIRE( currUCells.size() == currSCells.size() );
257  REQUIRE( refUCells.size() == refSCells.size() );
258  REQUIRE( refUCells.size() == 2*K.dimension );
259  cmpUCellsIfInside( K, currUCells, refUCells );
260  cmpSCellsIfInside( K, currSCells, refSCells );
261  }
262  }
263 }
264 
266 
272 template < typename KSpace >
273 void testFaces( KSpace const & K,
274  typename KSpace::Point const & aPoint
275  )
276 {
277  INFO( "Testing faces and cofaces around point " << aPoint );
278 
279  using Point = typename KSpace::Point;
280  using PK = typename KSpace::PreCellularGridSpace;
281 
282  // Looping through cell topology
283  for ( unsigned int t = 0; t < 1u << KSpace::dimension; ++t )
284  {
285  // Constructing the Khalimsky coordinates
286  Point refPoint;
287  for ( DGtal::Dimension i = 0; i < KSpace::dimension; ++i )
288  refPoint[ i ] = t & (1u << i) ? 1 : 0;
289 
290  INFO( "Current topology is " << refPoint );
291 
292  // Constructing the unsigned cell
293  const auto refUCell = PK::uCell( refPoint );
294 
295  if ( ! K.uIsInside( PK::uCell( aPoint, refUCell ) ) )
296  continue; // Do not test if current point is outside space.
297 
298  const auto currUCell = K.uCell( aPoint, refUCell );
299  REQUIRE( K.uTopology( currUCell ) == PK::uTopology( refUCell ) );
300 
301  // Constructing the signed cell
302  const auto refSCell = PK::sCell( refPoint, PK::NEG );
303  const auto currSCell = K.sCell( aPoint, refSCell );
304  REQUIRE( K.sTopology( currSCell ) == PK::sTopology( refSCell ) );
305 
306  // Testing faces
307  {
308  const auto currUCells = K.uFaces( currUCell );
309  const auto refUCells = PK::uFaces( currUCell );
310 
311  REQUIRE( refUCells.size() == floor( std::pow( 3, K.uDim( currUCell ) ) - 1 ) );
312  cmpUCellsIfInside( K, currUCells, refUCells );
313  }
314 
315  // Testing proper neighbordhoods
316  {
317  const auto currUCells = K.uCoFaces( currUCell );
318  const auto refUCells = PK::uCoFaces( currUCell );
319 
320  cmpUCellsIfInside( K, currUCells, refUCells );
321  }
322  }
323 }
324 
326 
332 template < typename KSpace >
333 void testIncidence( KSpace const & K,
334  typename KSpace::Point const & aPoint
335  )
336 {
337  INFO( "Testing block Incidence in KSpace..." );
338 
339  using SCell = typename KSpace::SCell;
340  using DirIterator = typename KSpace::DirIterator;
341 
342  SCell sspel = K.sSpel( aPoint, K.POS );
343 
344  for ( DirIterator q1 = K.sDirs( sspel ); q1 != 0; ++q1 )
345  for ( DirIterator q2 = K.sDirs( sspel ); q2 != 0; ++q2 )
346  {
347  if ( *q1 != *q2 )
348  {
349  SCell s0 = K.sIncident( sspel, *q1, true );
350  SCell s1 = K.sIncident( sspel, *q2, true );
351  SCell l10 = K.sIncident( s0, *q2, true );
352  SCell l01 = K.sIncident( s1, *q1, true );
353  INFO( "D+_" << *q2 << "(D+_" << *q1 << "(V))=" << l10
354  << " D+_" << *q1 << "(D+_" << *q2 << "(V))=" << l01
355  );
356  REQUIRE( l10 == K.sOpp( l01 ) );
357  }
358  }
359 }
360 
362 
368 template < typename KSpace >
370  typename KSpace::Point const & aPoint
371  )
372 {
373  INFO( "Testing direct Incidence in KSpace..." );
374 
375  using SCell = typename KSpace::SCell;
376  using DirIterator = typename KSpace::DirIterator;
377 
378  SCell sspel = K.sSpel( aPoint, K.POS );
379 
380  for ( DirIterator q1 = K.sDirs( sspel ); q1 != 0; ++q1 )
381  for ( DirIterator q2 = K.sDirs( sspel ); q2 != 0; ++q2 )
382  {
383  if ( *q1 != *q2 )
384  {
385  SCell s0 = K.sDirectIncident( sspel, *q1 );
386  SCell l10 = K.sDirectIncident( s0, *q2 );
387  SCell s1 = K.sDirectIncident( sspel, *q2 );
388  SCell l01 = K.sDirectIncident( s1, *q1 );
389  INFO( "Dd_" << *q2 << "(Dd_" << *q1 << "(V))=" << l10
390  << " Dd_" << *q1 << "(Dd_" << *q2 << "(V))=" << l01
391  );
392 
393  REQUIRE( l10 != l01 );
394  REQUIRE( K.sSign( s0 ) == K.POS );
395  REQUIRE( K.sSign( s1 ) == K.POS );
396  REQUIRE( K.sSign( l10 ) == K.POS );
397  REQUIRE( K.sSign( l01 ) == K.POS );
398  REQUIRE( s0 == K.sIncident( sspel, *q1, K.sDirect( sspel, *q1 ) ) );
399  REQUIRE( s1 == K.sIncident( sspel, *q2, K.sDirect( sspel, *q2 ) ) );
400  REQUIRE( l10 == K.sIncident( s0, *q2, K.sDirect( s0, *q2 ) ) );
401  REQUIRE( l01 == K.sIncident( s1, *q1, K.sDirect( s1, *q1 ) ) );
402  }
403  }
404 }
405 
407 
412 template <typename KSpace>
413 void testSurfelAdjacency( KSpace const & K )
414 {
415  using SCell = typename KSpace::SCell;
416  using Point = typename KSpace::Point;
417  using Integer = typename KSpace::Integer;
418 
419  INFO( "Testing surfel adjacency ..." );
421 
422  INFO( "Testing surfel directness ..." );
423  const SCell sspel = K.sCell( Point::diagonal(1), K.POS );
424 
425  for ( Dimension k = 0; k < K.dimension; ++k )
426  {
427  SCell surfel = K.sIncident( sspel, k, true );
428  SCell innerspel = K.sDirectIncident( surfel, K.sOrthDir( surfel ) );
429  INFO( "spel=" << sspel << " surfel=" << surfel << " innerspel=" << innerspel );
430  REQUIRE( sspel == innerspel );
431 
432  surfel = K.sIncident( sspel, k, false );
433  innerspel = K.sDirectIncident( surfel, K.sOrthDir( surfel ) );
434  INFO( "spel=" << sspel << " surfel=" << surfel << " innerspel=" << innerspel );
435  REQUIRE( sspel == innerspel );
436  }
437 
438  INFO( "Testing surfel neighborhood ..." );
440  SCell surfel = K.sIncident( sspel, 0, false );
441  SN.init( &K, &SAdj, surfel );
442 
443  INFO( "Testing surface tracking ..." );
446  using DigitalSet = typename DigitalSetSelector< Domain, BIG_DS+HIGH_BEL_DS >::Type;
447 
448  const Point low = Point::diagonal(-3);
449  const Point high = Point::diagonal(3) + Point::base(0, 2);
452 
453  const Domain domain( low, high );
454  DigitalSet shape_set( domain );
455 
456  const Point pcenter = Point::diagonal(0) + Point::base(0);
457  Shapes<Domain>::addNorm1Ball( shape_set, pcenter, 1 );
458 
459  CAPTURE( surfel );
460  SCell other1, other2;
461 
462  SN.getAdjacentOnDigitalSet( other1, shape_set, 1, K.sDirect( surfel, 1 ) );
463  INFO( "directNext = " << other1 );
464 
465  SN.getAdjacentOnDigitalSet( other2, shape_set, 1, !K.sDirect( surfel, 1 ) );
466  INFO( "indirectNext= " << other2 );
467 
468  std::set<SCell> bdry;
469  Surfaces<KSpace>::trackBoundary( bdry, K, SAdj, shape_set, surfel );
470  REQUIRE( bdry.size() == ( 2*K.dimension*(2*K.dimension-1) ) );
471 
472  std::set<SCell> bdry_direct;
473  Surfaces<KSpace>::trackClosedBoundary( bdry_direct, K, SAdj, shape_set, surfel );
474  REQUIRE( bdry_direct.size() == ( 2*K.dimension*(2*K.dimension-1) ) );
475 
476  if ( K.dimension == 2 )
477  {
478  INFO( "Testing Board2D" );
479  Board2D board;
481  board << SetMode( domain.className(), "Paving" ) << domain;
482  for ( typename std::set<SCell>::const_iterator it = bdry_direct.begin(),
483  it_end = bdry_direct.end(); it != it_end; ++it )
484  board << *it;
485  board.saveEPS( "cells-2.eps" );
486  board.saveSVG( "cells-2.svg" );
487  }
488 }
489 
491 
495 template <typename KSpace>
496 void testCellDrawOnBoard( KSpace const & K )
497 {
498  REQUIRE(( K.dimension == 2 ));
499 
500  typedef typename KSpace::Integer Integer;
501  typedef typename KSpace::Cell Cell;
502  typedef typename KSpace::SCell SCell;
503  typedef typename KSpace::Point Point;
504  typedef SpaceND<2, Integer> Z2;
505  typedef HyperRectDomain<Z2> Domain;
506 
507  INFO( "Testing cell draw on digital board ..." );
508 
509  const Point low( -3, -3 );
510  const Point high( 5, 3 );
511 
512  const Domain domain( low, high );
513  Board2D board;
515  board << SetMode( domain.className(), "Paving" )
516  << domain;
517 
518  Cell uspel = K.uCell( Point::diagonal(1) ); // pixel 0,0
519  board << uspel
520  << low << high
521  << K.uIncident( uspel, 0, false )
522  << K.uIncident( uspel, 1, false );
523 
524  const SCell sspel2 = K.sCell( Point( 5, 1 ), K.POS ); // pixel 2,0
525  board << CustomStyle( sspel2.className(),
526  new CustomPen( Color( 200, 0, 0 ),
527  Color( 255, 100, 100 ),
528  2.0,
530  << sspel2
531  << K.sIncident( sspel2, 0, K.sDirect( sspel2, 0 ) )
532  << K.sIncident( sspel2, 1, K.sDirect( sspel2, 0 ) );
533 
534  board.saveEPS( "cells-1.eps" );
535  board.saveSVG( "cells-1.svg" );
536  board.clear();
537 
538  board << domain;
539  const SCell slinel0 = K.sIncident( sspel2, 0, K.sDirect( sspel2, 0 ) );
540  const SCell spointel01 = K.sIncident( slinel0, 1, K.sDirect( slinel0, 1 ) );
541 
542  board << CustomStyle( sspel2.className(),
543  new CustomColors( Color( 200, 0, 0 ),
544  Color( 255, 100, 100 ) ) )
545  << sspel2
546  << CustomStyle( slinel0.className(),
547  new CustomColors( Color( 0, 200, 0 ),
548  Color( 100, 255, 100 ) ) )
549  << slinel0
550  << CustomStyle( spointel01.className(),
551  new CustomColors( Color( 0, 0, 200 ),
552  Color( 100, 100, 255 ) ) )
553  << spointel01;
554 
555  board.saveEPS( "cells-3.eps" );
556  board.saveSVG( "cells-3.svg" );
557 }
558 
559 
561 
565 template <typename KSpace>
566 void testFindABel( KSpace const & K )
567 {
568  REQUIRE(( K.dimension >= 3 ));
569 
570  typedef typename KSpace::Point Point;
573  typedef typename DigitalSetSelector< Domain, BIG_DS+HIGH_BEL_DS >::Type DigitalSet;
574  typedef typename KSpace::SCell SCell;
575 
576  INFO( "Test FindABel" );
577 
578  const Point low = Point::diagonal(-3);
579  const Point high = Point::diagonal(3);
580 
583 
584  const Domain domain( low, high );
585  DigitalSet shape_set( domain );
586 
587  const Point p000 = Point::zero;
588  const Point p001 = Point::base(2);
589  const Point p010 = Point::base(1);
590  const Point p011 = p001 + p010;
591  const Point p100 = Point::base(0);
592  const Point p101 = p100 + p001;
593  const Point p110 = p100 + p010;
594  const Point p111 = Point::diagonal(1);
595 
596  shape_set.insert( p000 );
597  shape_set.insert( p100 );
598 
599  Surfaces<KSpace>::findABel( K, shape_set , p000 , p011 );
600  Surfaces<KSpace>::findABel( K, shape_set , p000 , p110 );
601  Surfaces<KSpace>::findABel( K, shape_set , p000 , p111 );
602  Surfaces<KSpace>::findABel( K, shape_set , p000 , p101 );
603 
604  SCell s010 = Surfaces<KSpace>::findABel( K, shape_set , p000 , p010 );
605  SCell s001 = Surfaces<KSpace>::findABel( K, shape_set , p000 , p001 );
606 
607  REQUIRE( s010 == K.sCell( Point::diagonal(1) + Point::base(1), true ) );
608  REQUIRE( s001 == K.sCell( Point::diagonal(1) + Point::base(2), false ) );
609 }
610 
611 
613 
617 template <typename KSpace>
619 {
620  typedef typename KSpace::Cell Cell;
621  typedef typename KSpace::Point Point;
622  typedef typename KSpace::Cells Cells;
623 
624  const Dimension N = KSpace::dimension;
625 
626  const Point low = Point::diagonal(-1);
627  const Point high = Point::diagonal(1);
630 
631  const Cell vox = K.uSpel( Point::zero );
632  const Cells faces = K.uFaces( vox );
633 
634  // Check that there is no duplicates.
635  INFO( "Check CellularGridSpaceND::uFaces" );
636  for ( Dimension k = 0; k < N; ++k )
637  {
638  CAPTURE( k );
639 
640  DGtal::int64_t nf = 0;
641 
642  for ( auto const & face : faces )
643  if ( K.uDim( face ) == k )
644  {
645  INFO( face );
646  ++nf;
647  }
648 
649  // Number of k-faces of N-cube is binom(n,k)*2^(n-k)
650  DGtal::int64_t exp_nf = (DGtal::int64_t) round( boost::math::binomial_coefficient<double>(N, k) );
651  exp_nf <<= N-k;
652 
653  REQUIRE( nf == exp_nf );
654  }
655 }
656 
658 
662 template <typename KSpace>
664 {
665  typedef typename KSpace::Cell Cell;
666  typedef typename KSpace::Point Point;
667  typedef typename KSpace::Cells Cells;
668 
669  const Dimension N = KSpace::dimension;
670 
671  const Point low = Point::diagonal(-1);
672  const Point high = Point::diagonal(1);
675 
676  const Cell pointel = K.uPointel( Point::zero );
677  const Cells cofaces = K.uCoFaces( pointel );
678 
679  // Check that there is no duplicates.
680  INFO( "Check CellularGridSpaceND::uCoFaces" );
681  for ( Dimension k = 1; k <= N; ++k )
682  {
683  CAPTURE( k );
684 
685  DGtal::int64_t nf = 0;
686 
687  for ( auto const & coface : cofaces )
688  {
689  if ( K.uDim( coface ) == k )
690  {
691  CAPTURE( coface );
692  ++nf;
693  }
694  }
695 
696  CAPTURE( nf );
697 
698  // Number of k-faces of N-cube is binom(n,k)*2^(n-k)
699  DGtal::int64_t exp_nf = (DGtal::int64_t) round( boost::math::binomial_coefficient<double>(N, N-k) );
700  exp_nf <<= k;
701 
702  REQUIRE( nf == exp_nf );
703  }
704 }
705 
707 // Test cases
708 
709 TEST_CASE( "Checking concepts" )
710 {
711  BOOST_CONCEPT_ASSERT(( concepts::CPreCellularGridSpaceND< KhalimskyPreSpaceND<2> > ));
712  BOOST_CONCEPT_ASSERT(( concepts::CPreCellularGridSpaceND< KhalimskyPreSpaceND<3> > ));
713  BOOST_CONCEPT_ASSERT(( concepts::CPreCellularGridSpaceND< KhalimskyPreSpaceND<4> > ));
714 
715  BOOST_CONCEPT_ASSERT(( concepts::CCellularGridSpaceND< KhalimskySpaceND<2> > ));
716  BOOST_CONCEPT_ASSERT(( concepts::CCellularGridSpaceND< KhalimskySpaceND<3> > ));
717  BOOST_CONCEPT_ASSERT(( concepts::CCellularGridSpaceND< KhalimskySpaceND<4> > ));
718 }
719 
720 TEST_CASE( "2D Khalimsky pre-space", "[KPreSpace][2D]" )
721 {
722  const KhalimskyPreSpaceND<2> K{};
723  INFO( "Khalimsky space is " << K );
724 
725  testScan( K, {-1, -2}, {1, 2} );
726  testIncidence( K, {0, 0} );
727  testDirectIncidence( K, {0, 0} );
732 }
733 
734 TEST_CASE( "3D Khalimsky pre-space", "[KPreSpace][3D]" )
735 {
736  const KhalimskyPreSpaceND<3> K{};
737  INFO( "Khalimsky space is " << K );
738 
739  testScan( K, {-2, -3, -4}, {1, 2, 4} );
740  testIncidence( K, {0, 0, 0} );
741  testDirectIncidence( K, {0, 0, 0} );
743  testFindABel( K );
746 }
747 
748 TEST_CASE( "4D Khalimsky pre-space", "[KPreSpace][4D]" )
749 {
750  const KhalimskyPreSpaceND<3> K{};
751  INFO( "Khalimsky space is " << K );
752 
753  testScan( K, {-1, -2, -3, -4}, {1, 0, 1, -1} );
754  testIncidence( K, {0, 0, 0, 0} );
755  testDirectIncidence( K, {0, 0, 0, 0} );
757  testFindABel( K );
760 }
761 
762 TEST_CASE( "3D closed Khalimsky space", "[KSpace][3D][closed]" )
763 {
765  const bool spaceOK = K.init( {-3, -3, -3}, {5, 3, 3}, K.CLOSED );
766  INFO( "Khalimsky space is " << K );
767  REQUIRE( spaceOK == true );
768 
769  testScan( K, {-1, -2, -1}, {1, 2, 2} );
770  testNeighborhood( K, {0, 0, 0} );
771  testNeighborhood( K, {-2, 3, 2} );
772  testFaces( K, {0, 0, 0} );
773  testFaces( K, {-2, 3, -3} );
774  testIncidence( K, {0, 0, 0} );
775  testDirectIncidence( K, {0, 0, 0} );
777  testFindABel( K );
780 }
781 
782 TEST_CASE( "2D closed Khalimsky space", "[KSpace][2D][closed]" )
783 {
785  const bool spaceOK = K.init( {-3, -3}, {5, 3}, K.CLOSED );
786  INFO( "Khalimsky space is " << K );
787  REQUIRE( spaceOK == true );
788 
789  testScan( K, {-1, -2}, {1, 2} );
790  testNeighborhood( K, {0, 0} );
791  testNeighborhood( K, {-2, 3} );
792  testFaces( K, {0, 0} );
793  testFaces( K, {-2, 3} );
794  testIncidence( K, {0, 0} );
795  testDirectIncidence( K, {0, 0} );
800 }
801 
802 TEST_CASE( "4D closed Khalimsky space", "[KSpace][4D][closed]" )
803 {
805  const bool spaceOK = K.init( {-3, -3, -3, -3}, {5, 3, 3, 3}, K.CLOSED );
806  INFO( "Khalimsky space is " << K );
807  REQUIRE( spaceOK == true );
808 
809  testScan( K, {-1, -2, 0, 1}, {1, 2, 1, 2} );
810  testNeighborhood( K, {0, 0, 0, 0} );
811  testNeighborhood( K, {-2, 3, -1, 3} );
812  testFaces( K, {0, 0, 0, 0} );
813  testFaces( K, {-2, 3, -1, 3} );
814  testIncidence( K, {0, 0, 0, 0} );
815  testDirectIncidence( K, {0, 0, 0, 0} );
817  testFindABel( K );
820 }
821 
822 TEST_CASE( "2D open Khalimsky space", "[KSpace][2D][open]" )
823 {
825  const bool spaceOK = K.init( {-3, -3}, {5, 3}, K.OPEN );
826  INFO( "Khalimsky space is " << K );
827  REQUIRE( spaceOK == true );
828 
829  testScan( K, {-1, -2}, {1, 2} );
830  testNeighborhood( K, {0, 0} );
831  testNeighborhood( K, {-2, 3} );
832  testFaces( K, {0, 0} );
833  testFaces( K, {-2, 3} );
834  testIncidence( K, {0, 0} );
835  testDirectIncidence( K, {0, 0} );
840 }
841 
842 TEST_CASE( "3D open Khalimsky space", "[KSpace][3D][open]" )
843 {
845  const bool spaceOK = K.init( {-3, -3, -3}, {5, 3, 3}, K.OPEN );
846  INFO( "Khalimsky space is " << K );
847  REQUIRE( spaceOK == true );
848 
849  testScan( K, {-1, -2, -1}, {1, 2, 2} );
850  testNeighborhood( K, {0, 0, 0} );
851  testNeighborhood( K, {-2, 3, 2} );
852  testFaces( K, {0, 0, 0} );
853  testFaces( K, {-2, 3, -3} );
854  testIncidence( K, {0, 0, 0} );
855  testDirectIncidence( K, {0, 0, 0} );
857  testFindABel( K );
860 }
861 
862 TEST_CASE( "2D periodic Khalimsky space", "[KSpace][2D][periodic]" )
863 {
865  const bool spaceOK = K.init( {-2, -3}, {2, 3}, K.PERIODIC );
866  INFO( "Khalimsky space is " << K );
867  REQUIRE( spaceOK == true );
868 
869  testScan( K, {-1, -2}, {1, 2} );
870  testNeighborhood( K, {0, 0} );
871  testNeighborhood( K, {-2, 3} );
872  testFaces( K, {0, 0} );
873  testFaces( K, {-2, 3} );
874  testIncidence( K, {0, 3} );
875  testDirectIncidence( K, {0, 3} );
880 }
881 
882 TEST_CASE( "3D periodic Khalimsky space", "[KSpace][3D][periodic]" )
883 {
885  const bool spaceOK = K.init( {-3, -3, -3}, {2, 2, 3}, K.PERIODIC );
886  INFO( "Khalimsky space is " << K );
887  REQUIRE( spaceOK == true );
888 
889  testScan( K, {-1, -2, -1}, {1, 2, 2} );
890  testNeighborhood( K, {0, 0, 0} );
891  testNeighborhood( K, {-2, 3, 2} );
892  testFaces( K, {0, 0, 0} );
893  testFaces( K, {-2, 3, -3} );
894  testIncidence( K, {0, 0, 0} );
895  testDirectIncidence( K, {0, 0, 0} );
897  testFindABel( K );
900 }
901 
902 TEST_CASE( "2D mixed Khalimsky space", "[KSpace][2D][closed][periodic]" )
903 {
905  const bool spaceOK = K.init( {-3, -3}, {5, 2}, {{ K.CLOSED, K.PERIODIC }} );
906  INFO( "Khalimsky space is " << K );
907  REQUIRE( spaceOK == true );
908 
909  testScan( K, {-1, 2}, {1, 5} );
910  testNeighborhood( K, {0, 0} );
911  testNeighborhood( K, {-2, 4} );
912  testFaces( K, {0, 0} );
913  testFaces( K, {-2, 4} );
914  testIncidence( K, {0, 3} );
915  testDirectIncidence( K, {0, 3} );
920 }
921 
922 TEST_CASE( "3D mixed Khalimsky space", "[KSpace][3D][closed][periodic][open]" )
923 {
925  const bool spaceOK = K.init( {-3, -3, -3}, {5, 3, 1}, {{ K.CLOSED, K.OPEN, K.PERIODIC }} );
926  INFO( "Khalimsky space is " << K );
927  REQUIRE( spaceOK == true );
928 
929  testScan( K, {-1, -2, -1}, {1, 2, 2} );
930  testNeighborhood( K, {0, 0, 0} );
931  testNeighborhood( K, {-2, 3, 2} );
932  testFaces( K, {0, 0, 0} );
933  testFaces( K, {-2, 3, -3} );
934  testIncidence( K, {0, 0, 0} );
935  testDirectIncidence( K, {0, 0, 0} );
937  testFindABel( K );
940 }
941 
Aim: This class specializes a 'Board' class so as to display DGtal objects more naturally (with <<)....
Definition: Board2D.h:71
Structure representing an RGB triple with alpha component.
Definition: Color.h:67
Aim: A wrapper class around a STL associative container for storing sets of digital points within som...
std::string className() const
Aim: This class is a model of CPreCellularGridSpaceND. It represents the cubical grid as a cell compl...
static Cell uSpel(Point p)
From the digital coordinates of a point in Zn, builds the corresponding pre-spel (pre-cell of maximal...
Aim: This class is a model of CCellularGridSpaceND. It represents the cubical grid as a cell complex,...
bool sNext(SCell &p, const SCell &lower, const SCell &upper) const
Increment the cell [p] to its next position (as classically done in a scanning).
Cell uSpel(Point p) const
From the digital coordinates of a point in Zn, builds the corresponding spel (cell of maximal dimensi...
bool uIsInside(const PreCell &p, Dimension k) const
Useful to check if you are going out of the space.
Cell uIncident(const Cell &c, Dimension k, bool up) const
Return the forward or backward unsigned cell incident to [c] along axis [k], depending on [up].
Cells uCoFaces(const Cell &c) const
Return the proper cofaces of [c] (chain of upper incidence) that belong to the space.
TInteger Integer
Arithmetic ring induced by (+,-,*) and Integer numbers.
bool init(const Point &lower, const Point &upper, bool isClosed)
Specifies the upper and lower bounds for the maximal cells in this space.
Dimension sOrthDir(const SCell &s) const
Given a signed surfel [s], returns its orthogonal direction (ie, the coordinate where the surfel is c...
static constexpr const Sign POS
DirIterator sDirs(const SCell &p) const
Given a signed cell [p], returns an iterator to iterate over each coordinate the cell spans.
Cells uFaces(const Cell &c) const
Return the proper faces of [c] (chain of lower incidence) that belong to the space.
Cells uNeighborhood(const Cell &cell) const
Computes the 1-neighborhood of the cell [c] and returns it.
SCell sOpp(const SCell &p) const
Creates the signed cell with the inverse sign of [p].
bool uNext(Cell &p, const Cell &lower, const Cell &upper) const
Increment the cell [p] to its next position (as classically done in a scanning).
static constexpr const Dimension dimension
Cell uPointel(Point p) const
From the digital coordinates of a point in Zn, builds the corresponding pointel (cell of dimension 0)...
bool sDirect(const SCell &p, Dimension k) const
Return 'true' if the direct orientation of [p] along [k] is in the positive coordinate direction.
Integer sTopology(const SCell &p) const
Return the topology word of [p].
SCell sCell(const SPreCell &c) const
From a signed cell, returns a signed cell lying into this Khalismky space.
SCells sProperNeighborhood(const SCell &cell) const
Computes the proper 1-neighborhood of the cell [c] and returns it.
Integer uTopology(const Cell &p) const
Return the topology word of [p].
Cells uProperNeighborhood(const Cell &cell) const
Computes the proper 1-neighborhood of the cell [c] and returns it.
SCell sSpel(Point p, Sign sign=POS) const
From the digital coordinates of a point in Zn, builds the corresponding spel (cell of maximal dimensi...
Cell uCell(const PreCell &c) const
From an unsigned cell, returns an unsigned cell lying into this Khalismky space.
SCell sDirectIncident(const SCell &p, Dimension k) const
Return the direct incident cell of [p] along [k] (the incident cell along [k])
@ CLOSED
The dimension is closed and non-periodic.
@ OPEN
The dimension is open.
@ PERIODIC
The dimension is periodic.
SCells sNeighborhood(const SCell &cell) const
Computes the 1-neighborhood of the cell [c] and returns it.
bool sIsInside(const SPreCell &p, Dimension k) const
Useful to check if you are going out of the space.
AnyCellCollection< SCell > SCells
Sign sSign(const SCell &c) const
Return its sign.
Dimension uDim(const Cell &p) const
Return the dimension of the cell [p].
SCell sIncident(const SCell &c, Dimension k, bool up) const
Return the forward or backward signed cell incident to [c] along axis [k], depending on [up].
typename PreCellularGridSpace::DirIterator DirIterator
AnyCellCollection< Cell > Cells
static void addNorm1Ball(TDigitalSet &aSet, const Point &aCenter, UnsignedInteger aRadius)
static void trackClosedBoundary(SCellSet &surface, const KSpace &K, const SurfelAdjacency< KSpace::dimension > &surfel_adj, const PointPredicate &pp, const SCell &start_surfel)
static void trackBoundary(SCellSet &surface, const KSpace &K, const SurfelAdjacency< KSpace::dimension > &surfel_adj, const PointPredicate &pp, const SCell &start_surfel)
static SCell findABel(const KSpace &K, const PointPredicate &pp, unsigned int nbtries=1000)
void init(const KSpace *space, const SurfelAdjacency< KSpace::dimension > *adj, const SCell &aSurfel)
unsigned int getAdjacentOnDigitalSet(SCell &adj_surfel, const DigitalSet &obj, Dimension track_dir, bool pos) const
void clear(const DGtal::Color &color=DGtal::Color::None)
Definition: Board.cpp:152
void saveEPS(const char *filename, PageSize size=Board::BoundingBox, double margin=10.0) const
Definition: Board.cpp:805
void saveSVG(const char *filename, PageSize size=Board::BoundingBox, double margin=10.0) const
Definition: Board.cpp:1012
void setUnit(Unit unit)
Definition: Board.cpp:240
DGtal is the top-level namespace which contains all DGtal functions and types.
boost::int64_t int64_t
signed 94-bit integer.
Definition: BasicTypes.h:74
DGtal::uint32_t Dimension
Definition: Common.h:137
Custom style class redefining the pen color and the fill color. You may use Board2D::Color::None for ...
Definition: Board2D.h:279
Custom style class redefining the pen attributes. You may use Board2D::Color::None for transparent co...
Definition: Board2D.h:374
Modifier class in a Board2D stream. Useful to choose your own mode for a given class....
Definition: Board2D.h:247
Represents a signed cell in a cellular grid space by its Khalimsky coordinates and a boolean value.
std::string className() const
Return the style name used for drawing this object.
Aim: This concept describes a cellular grid space in nD. In these spaces obtained by cartesian produc...
Aim: This concept describes an unbounded cellular grid space in nD. In these spaces obtained by carte...
MyPointD Point
Definition: testClone2.cpp:383
CAPTURE(thicknessHV)
KSpace K
KSpace::Cell Cell
void testCellularGridSpaceNDCoFaces(KSpace const &K)
void testCellularGridSpaceNDFaces(KSpace const &K)
void cmpSCellsIfInside(KSpace const &K, typename KSpace::SCells const &u, Cells const &v)
void cmpUCellsIfInside(KSpace const &K, typename KSpace::Cells const &u, Cells const &v)
void testSurfelAdjacency(KSpace const &K)
void testScan(KSpace const &K, typename KSpace::Point const &low, typename KSpace::Point const &high)
void testCellDrawOnBoard(KSpace const &K)
void testDirectIncidence(KSpace const &K, typename KSpace::Point const &aPoint)
void testFaces(KSpace const &K, typename KSpace::Point const &aPoint)
void testNeighborhood(KSpace const &K, typename KSpace::Point const &aPoint)
void testFindABel(KSpace const &K)
TEST_CASE("Checking concepts")
void testIncidence(KSpace const &K, typename KSpace::Point const &aPoint)
Domain domain
const Point aPoint(3, 4)
HyperRectDomain< Space > Domain
REQUIRE(domain.isInside(aPoint))