DGtal  1.4.beta
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 <DGtal/topology/helpers/Surfaces.h>
54 #include <DGtal/topology/LightImplicitDigitalSurface.h>
55 
56 #include "DGtalCatch.h"
58 
59 using namespace DGtal;
60 using namespace std;
61 
63 
70 template < typename KSpace >
71 void testScan( KSpace const & K,
72  typename KSpace::Point const & low,
73  typename KSpace::Point const & high
74  )
75 {
76  INFO( "Testing uNext & sNext with low = " << low << " & high = " << high );
77 
78  using Point = typename KSpace::Point;
79  using Space = typename KSpace::Space;
80  using PK = typename KSpace::PreCellularGridSpace;
81 
82  const HyperRectDomain< Space > domain( low, high );
83 
84  // Looping through cell topology
85  for ( unsigned int t = 0; t < 1u << KSpace::dimension; ++t )
86  {
87  // Constructing the Khalimsky coordinates
88  Point refPoint;
89  for ( DGtal::Dimension i = 0; i < KSpace::dimension; ++i )
90  refPoint[ i ] = t & (1u << i) ? 1 : 0;
91 
92  INFO( "Current topology is " << refPoint );
93 
94  // Initializing unsigned cells
95  const auto refUCell = PK::uCell( refPoint );
96  auto currUCell = K.uCell( low, refUCell );
97  const auto lowUCell = currUCell;
98  const auto highUCell = K.uCell( high, refUCell );
99  REQUIRE( K.uTopology( currUCell ) == PK::uTopology( refUCell ) );
100 
101  // Initializing signed cells
102  const auto refSCell = PK::sCell( refPoint, PK::POS );
103  auto currSCell = K.sCell( low, refSCell );
104  const auto lowSCell = currSCell;
105  const auto highSCell = K.sCell( high, refSCell );
106  REQUIRE( K.sTopology( currSCell ) == PK::sTopology( refSCell ) );
107 
108  // Spanning the domain
109  bool uCheck = true;
110  bool sCheck = true;
111  for ( Point const & pt : domain )
112  {
113  REQUIRE( uCheck == true );
114  REQUIRE( sCheck == true );
115 
116  REQUIRE( currUCell == K.uCell( pt, refUCell ) );
117  REQUIRE( currSCell == K.sCell( pt, refSCell ) );
118 
119  uCheck = K.uNext( currUCell, lowUCell, highUCell );
120  sCheck = K.sNext( currSCell, lowSCell, highSCell );
121  }
122 
123  // Checking scan end conditions.
124  REQUIRE( uCheck == false );
125  REQUIRE( sCheck == false );
126  }
127 }
128 
130 
138 template < typename KSpace, typename Cells >
139 void cmpUCellsIfInside( KSpace const & K,
140  typename KSpace::Cells const & u,
141  Cells const & v
142  )
143 {
144  REQUIRE( u.size() <= v.size() );
145 
146  std::size_t cnt = 0;
147 
148  // Scanning the lists
149  for( auto const & cell : v )
150  {
151  if ( ! K.uIsInside( cell ) )
152  continue;
153 
154  REQUIRE( std::find( u.cbegin(), u.cend(), K.uCell( cell ) ) != u.cend() );
155 
156  ++cnt;
157  }
158 
159  // Checking counter
160  REQUIRE( u.size() == cnt );
161 }
162 
164 
172 template < typename KSpace, typename Cells >
173 void cmpSCellsIfInside( KSpace const & K,
174  typename KSpace::SCells const & u,
175  Cells const & v
176  )
177 {
178  REQUIRE( u.size() <= v.size() );
179 
180  std::size_t cnt = 0;
181 
182  // Scanning the lists
183  for( auto const & cell : v )
184  {
185  if ( ! K.sIsInside( cell ) )
186  continue;
187 
188  REQUIRE( std::find( u.cbegin(), u.cend(), K.sCell( cell ) ) != u.cend() );
189 
190  ++cnt;
191  }
192 
193  // Checking counter
194  REQUIRE( u.size() == cnt );
195 }
196 
198 
204 template < typename KSpace >
205 void testNeighborhood( KSpace const & K,
206  typename KSpace::Point const & aPoint
207  )
208 {
209  INFO( "Testing (proper) neighborhood around point " << aPoint );
210 
211  using Point = typename KSpace::Point;
212  using PK = typename KSpace::PreCellularGridSpace;
213 
214  // Looping through cell topology
215  for ( unsigned int t = 0; t < 1u << KSpace::dimension; ++t )
216  {
217  // Constructing the Khalimsky coordinates
218  Point refPoint;
219  for ( DGtal::Dimension i = 0; i < KSpace::dimension; ++i )
220  refPoint[ i ] = t & (1u << i) ? 1 : 0;
221 
222  INFO( "Current topology is " << refPoint );
223 
224  // Constructing the unsigned cell
225  const auto refUCell = PK::uCell( refPoint );
226 
227  if ( ! K.uIsInside( PK::uCell( aPoint, refUCell ) ) )
228  continue; // Do not continue if current point is outside space.
229 
230  const auto currUCell = K.uCell( aPoint, refUCell );
231  REQUIRE( K.uTopology( currUCell ) == PK::uTopology( refUCell ) );
232 
233  // Constructing the signed cell
234  const auto refSCell = PK::sCell( refPoint, PK::NEG );
235  const auto currSCell = K.sCell( aPoint, refSCell );
236  REQUIRE( K.sTopology( currSCell ) == PK::sTopology( refSCell ) );
237 
238  // Testing neighbordhoods
239  {
240  const auto currUCells = K.uNeighborhood( currUCell );
241  const auto refUCells = PK::uNeighborhood( currUCell );
242  const auto currSCells = K.sNeighborhood( currSCell );
243  const auto refSCells = PK::sNeighborhood( currSCell );
244 
245  REQUIRE( currUCells.size() == currSCells.size() );
246  REQUIRE( refUCells.size() == refSCells.size() );
247  REQUIRE( refUCells.size() == 2*K.dimension + 1 );
248  cmpUCellsIfInside( K, currUCells, refUCells );
249  cmpSCellsIfInside( K, currSCells, refSCells );
250  }
251 
252  // Testing proper neighbordhoods
253  {
254  const auto currUCells = K.uProperNeighborhood( currUCell );
255  const auto refUCells = PK::uProperNeighborhood( currUCell );
256  const auto currSCells = K.sProperNeighborhood( currSCell );
257  const auto refSCells = PK::sProperNeighborhood( currSCell );
258 
259  REQUIRE( currUCells.size() == currSCells.size() );
260  REQUIRE( refUCells.size() == refSCells.size() );
261  REQUIRE( refUCells.size() == 2*K.dimension );
262  cmpUCellsIfInside( K, currUCells, refUCells );
263  cmpSCellsIfInside( K, currSCells, refSCells );
264  }
265  }
266 }
267 
269 
275 template < typename KSpace >
276 void testFaces( KSpace const & K,
277  typename KSpace::Point const & aPoint
278  )
279 {
280  INFO( "Testing faces and cofaces around point " << aPoint );
281 
282  using Point = typename KSpace::Point;
283  using PK = typename KSpace::PreCellularGridSpace;
284 
285  // Looping through cell topology
286  for ( unsigned int t = 0; t < 1u << KSpace::dimension; ++t )
287  {
288  // Constructing the Khalimsky coordinates
289  Point refPoint;
290  for ( DGtal::Dimension i = 0; i < KSpace::dimension; ++i )
291  refPoint[ i ] = t & (1u << i) ? 1 : 0;
292 
293  INFO( "Current topology is " << refPoint );
294 
295  // Constructing the unsigned cell
296  const auto refUCell = PK::uCell( refPoint );
297 
298  if ( ! K.uIsInside( PK::uCell( aPoint, refUCell ) ) )
299  continue; // Do not test if current point is outside space.
300 
301  const auto currUCell = K.uCell( aPoint, refUCell );
302  REQUIRE( K.uTopology( currUCell ) == PK::uTopology( refUCell ) );
303 
304  // Constructing the signed cell
305  const auto refSCell = PK::sCell( refPoint, PK::NEG );
306  const auto currSCell = K.sCell( aPoint, refSCell );
307  REQUIRE( K.sTopology( currSCell ) == PK::sTopology( refSCell ) );
308 
309  // Testing faces
310  {
311  const auto currUCells = K.uFaces( currUCell );
312  const auto refUCells = PK::uFaces( currUCell );
313 
314  REQUIRE( refUCells.size() == floor( std::pow( 3, K.uDim( currUCell ) ) - 1 ) );
315  cmpUCellsIfInside( K, currUCells, refUCells );
316  }
317 
318  // Testing proper neighbordhoods
319  {
320  const auto currUCells = K.uCoFaces( currUCell );
321  const auto refUCells = PK::uCoFaces( currUCell );
322 
323  cmpUCellsIfInside( K, currUCells, refUCells );
324  }
325  }
326 }
327 
329 
335 template < typename KSpace >
336 void testIncidence( KSpace const & K,
337  typename KSpace::Point const & aPoint
338  )
339 {
340  INFO( "Testing block Incidence in KSpace..." );
341 
342  using SCell = typename KSpace::SCell;
343  using DirIterator = typename KSpace::DirIterator;
344 
345  SCell sspel = K.sSpel( aPoint, K.POS );
346 
347  for ( DirIterator q1 = K.sDirs( sspel ); q1 != 0; ++q1 )
348  for ( DirIterator q2 = K.sDirs( sspel ); q2 != 0; ++q2 )
349  {
350  if ( *q1 != *q2 )
351  {
352  SCell s0 = K.sIncident( sspel, *q1, true );
353  SCell s1 = K.sIncident( sspel, *q2, true );
354  SCell l10 = K.sIncident( s0, *q2, true );
355  SCell l01 = K.sIncident( s1, *q1, true );
356  INFO( "D+_" << *q2 << "(D+_" << *q1 << "(V))=" << l10
357  << " D+_" << *q1 << "(D+_" << *q2 << "(V))=" << l01
358  );
359  REQUIRE( l10 == K.sOpp( l01 ) );
360  }
361  }
362 }
363 
365 
371 template < typename KSpace >
373  typename KSpace::Point const & aPoint
374  )
375 {
376  INFO( "Testing direct Incidence in KSpace..." );
377 
378  using SCell = typename KSpace::SCell;
379  using DirIterator = typename KSpace::DirIterator;
380 
381  SCell sspel = K.sSpel( aPoint, K.POS );
382 
383  for ( DirIterator q1 = K.sDirs( sspel ); q1 != 0; ++q1 )
384  for ( DirIterator q2 = K.sDirs( sspel ); q2 != 0; ++q2 )
385  {
386  if ( *q1 != *q2 )
387  {
388  SCell s0 = K.sDirectIncident( sspel, *q1 );
389  SCell l10 = K.sDirectIncident( s0, *q2 );
390  SCell s1 = K.sDirectIncident( sspel, *q2 );
391  SCell l01 = K.sDirectIncident( s1, *q1 );
392  INFO( "Dd_" << *q2 << "(Dd_" << *q1 << "(V))=" << l10
393  << " Dd_" << *q1 << "(Dd_" << *q2 << "(V))=" << l01
394  );
395 
396  REQUIRE( l10 != l01 );
397  REQUIRE( K.sSign( s0 ) == K.POS );
398  REQUIRE( K.sSign( s1 ) == K.POS );
399  REQUIRE( K.sSign( l10 ) == K.POS );
400  REQUIRE( K.sSign( l01 ) == K.POS );
401  REQUIRE( s0 == K.sIncident( sspel, *q1, K.sDirect( sspel, *q1 ) ) );
402  REQUIRE( s1 == K.sIncident( sspel, *q2, K.sDirect( sspel, *q2 ) ) );
403  REQUIRE( l10 == K.sIncident( s0, *q2, K.sDirect( s0, *q2 ) ) );
404  REQUIRE( l01 == K.sIncident( s1, *q1, K.sDirect( s1, *q1 ) ) );
405  }
406  }
407 }
408 
410 
415 template <typename KSpace>
416 void testSurfelAdjacency( KSpace const & K )
417 {
418  using SCell = typename KSpace::SCell;
419  using Point = typename KSpace::Point;
420  using Integer = typename KSpace::Integer;
421 
422  INFO( "Testing surfel adjacency ..." );
424 
425  INFO( "Testing surfel directness ..." );
426  const SCell sspel = K.sCell( Point::diagonal(1), K.POS );
427 
428  for ( Dimension k = 0; k < K.dimension; ++k )
429  {
430  SCell surfel = K.sIncident( sspel, k, true );
431  SCell innerspel = K.sDirectIncident( surfel, K.sOrthDir( surfel ) );
432  INFO( "spel=" << sspel << " surfel=" << surfel << " innerspel=" << innerspel );
433  REQUIRE( sspel == innerspel );
434 
435  surfel = K.sIncident( sspel, k, false );
436  innerspel = K.sDirectIncident( surfel, K.sOrthDir( surfel ) );
437  INFO( "spel=" << sspel << " surfel=" << surfel << " innerspel=" << innerspel );
438  REQUIRE( sspel == innerspel );
439  }
440 
441  INFO( "Testing surfel neighborhood ..." );
443  SCell surfel = K.sIncident( sspel, 0, false );
444  SN.init( &K, &SAdj, surfel );
445 
446  INFO( "Testing surface tracking ..." );
450 
451  const Point low = Point::diagonal(-3);
452  const Point high = Point::diagonal(3) + Point::base(0, 2);
455 
456  const Domain domain( low, high );
457  DigitalSet shape_set( domain );
458 
459  const Point pcenter = Point::diagonal(0) + Point::base(0);
460  Shapes<Domain>::addNorm1Ball( shape_set, pcenter, 1 );
461 
462  CAPTURE( surfel );
463  SCell other1, other2;
464 
465  SN.getAdjacentOnDigitalSet( other1, shape_set, 1, K.sDirect( surfel, 1 ) );
466  INFO( "directNext = " << other1 );
467 
468  SN.getAdjacentOnDigitalSet( other2, shape_set, 1, !K.sDirect( surfel, 1 ) );
469  INFO( "indirectNext= " << other2 );
470 
471  std::set<SCell> bdry;
472  Surfaces<KSpace>::trackBoundary( bdry, K, SAdj, shape_set, surfel );
473  REQUIRE( bdry.size() == ( 2*K.dimension*(2*K.dimension-1) ) );
474 
475  std::set<SCell> bdry_direct;
476  Surfaces<KSpace>::trackClosedBoundary( bdry_direct, K, SAdj, shape_set, surfel );
477  REQUIRE( bdry_direct.size() == ( 2*K.dimension*(2*K.dimension-1) ) );
478 
479  if ( K.dimension == 2 )
480  {
481  INFO( "Testing Board2D" );
482  Board2D board;
484  board << SetMode( domain.className(), "Paving" ) << domain;
485  for ( typename std::set<SCell>::const_iterator it = bdry_direct.begin(),
486  it_end = bdry_direct.end(); it != it_end; ++it )
487  board << *it;
488  board.saveEPS( "cells-2.eps" );
489  board.saveSVG( "cells-2.svg" );
490  }
491 }
492 
494 
498 template <typename KSpace>
499 void testCellDrawOnBoard( KSpace const & K )
500 {
501  REQUIRE(( K.dimension == 2 ));
502 
503  typedef typename KSpace::Integer Integer;
504  typedef typename KSpace::Cell Cell;
505  typedef typename KSpace::SCell SCell;
506  typedef typename KSpace::Point Point;
507  typedef SpaceND<2, Integer> Z2;
508  typedef HyperRectDomain<Z2> Domain;
509 
510  INFO( "Testing cell draw on digital board ..." );
511 
512  const Point low( -3, -3 );
513  const Point high( 5, 3 );
514 
515  const Domain domain( low, high );
516  Board2D board;
518  board << SetMode( domain.className(), "Paving" )
519  << domain;
520 
521  Cell uspel = K.uCell( Point::diagonal(1) ); // pixel 0,0
522  board << uspel
523  << low << high
524  << K.uIncident( uspel, 0, false )
525  << K.uIncident( uspel, 1, false );
526 
527  const SCell sspel2 = K.sCell( Point( 5, 1 ), K.POS ); // pixel 2,0
528  board << CustomStyle( sspel2.className(),
529  new CustomPen( Color( 200, 0, 0 ),
530  Color( 255, 100, 100 ),
531  2.0,
533  << sspel2
534  << K.sIncident( sspel2, 0, K.sDirect( sspel2, 0 ) )
535  << K.sIncident( sspel2, 1, K.sDirect( sspel2, 0 ) );
536 
537  board.saveEPS( "cells-1.eps" );
538  board.saveSVG( "cells-1.svg" );
539  board.clear();
540 
541  board << domain;
542  const SCell slinel0 = K.sIncident( sspel2, 0, K.sDirect( sspel2, 0 ) );
543  const SCell spointel01 = K.sIncident( slinel0, 1, K.sDirect( slinel0, 1 ) );
544 
545  board << CustomStyle( sspel2.className(),
546  new CustomColors( Color( 200, 0, 0 ),
547  Color( 255, 100, 100 ) ) )
548  << sspel2
549  << CustomStyle( slinel0.className(),
550  new CustomColors( Color( 0, 200, 0 ),
551  Color( 100, 255, 100 ) ) )
552  << slinel0
553  << CustomStyle( spointel01.className(),
554  new CustomColors( Color( 0, 0, 200 ),
555  Color( 100, 100, 255 ) ) )
556  << spointel01;
557 
558  board.saveEPS( "cells-3.eps" );
559  board.saveSVG( "cells-3.svg" );
560 }
561 
562 
564 
568 template <typename KSpace>
569 void testFindABel( KSpace const & K )
570 {
571  REQUIRE(( K.dimension >= 3 ));
572 
573  typedef typename KSpace::Point Point;
577  typedef typename KSpace::SCell SCell;
578 
579  INFO( "Test FindABel" );
580 
581  const Point low = Point::diagonal(-3);
582  const Point high = Point::diagonal(3);
583 
586 
587  const Domain domain( low, high );
588  DigitalSet shape_set( domain );
589 
590  const Point p000 = Point::zero;
591  const Point p001 = Point::base(2);
592  const Point p010 = Point::base(1);
593  const Point p011 = p001 + p010;
594  const Point p100 = Point::base(0);
595  const Point p101 = p100 + p001;
596  const Point p110 = p100 + p010;
597  const Point p111 = Point::diagonal(1);
598 
599  shape_set.insert( p000 );
600  shape_set.insert( p100 );
601 
602  Surfaces<KSpace>::findABel( K, shape_set , p000 , p011 );
603  Surfaces<KSpace>::findABel( K, shape_set , p000 , p110 );
604  Surfaces<KSpace>::findABel( K, shape_set , p000 , p111 );
605  Surfaces<KSpace>::findABel( K, shape_set , p000 , p101 );
606 
607  SCell s010 = Surfaces<KSpace>::findABel( K, shape_set , p000 , p010 );
608  SCell s001 = Surfaces<KSpace>::findABel( K, shape_set , p000 , p001 );
609 
610  REQUIRE( s010 == K.sCell( Point::diagonal(1) + Point::base(1), true ) );
611  REQUIRE( s001 == K.sCell( Point::diagonal(1) + Point::base(2), false ) );
612 }
613 
614 
616 
620 template <typename KSpace>
622 {
623  typedef typename KSpace::Cell Cell;
624  typedef typename KSpace::Point Point;
625  typedef typename KSpace::Cells Cells;
626 
627  const Dimension N = KSpace::dimension;
628 
629  const Point low = Point::diagonal(-1);
630  const Point high = Point::diagonal(1);
633 
634  const Cell vox = K.uSpel( Point::zero );
635  const Cells faces = K.uFaces( vox );
636 
637  // Check that there is no duplicates.
638  INFO( "Check CellularGridSpaceND::uFaces" );
639  for ( Dimension k = 0; k < N; ++k )
640  {
641  CAPTURE( k );
642 
643  DGtal::int64_t nf = 0;
644 
645  for ( auto const & face : faces )
646  if ( K.uDim( face ) == k )
647  {
648  INFO( face );
649  ++nf;
650  }
651 
652  // Number of k-faces of N-cube is binom(n,k)*2^(n-k)
653  DGtal::int64_t exp_nf = (DGtal::int64_t) round( boost::math::binomial_coefficient<double>(N, k) );
654  exp_nf <<= N-k;
655 
656  REQUIRE( nf == exp_nf );
657  }
658 }
659 
661 
665 template <typename KSpace>
667 {
668  typedef typename KSpace::Cell Cell;
669  typedef typename KSpace::Point Point;
670  typedef typename KSpace::Cells Cells;
671 
672  const Dimension N = KSpace::dimension;
673 
674  const Point low = Point::diagonal(-1);
675  const Point high = Point::diagonal(1);
678 
679  const Cell pointel = K.uPointel( Point::zero );
680  const Cells cofaces = K.uCoFaces( pointel );
681 
682  // Check that there is no duplicates.
683  INFO( "Check CellularGridSpaceND::uCoFaces" );
684  for ( Dimension k = 1; k <= N; ++k )
685  {
686  CAPTURE( k );
687 
688  DGtal::int64_t nf = 0;
689 
690  for ( auto const & coface : cofaces )
691  {
692  if ( K.uDim( coface ) == k )
693  {
694  CAPTURE( coface );
695  ++nf;
696  }
697  }
698 
699  CAPTURE( nf );
700 
701  // Number of k-faces of N-cube is binom(n,k)*2^(n-k)
702  DGtal::int64_t exp_nf = (DGtal::int64_t) round( boost::math::binomial_coefficient<double>(N, N-k) );
703  exp_nf <<= k;
704 
705  REQUIRE( nf == exp_nf );
706  }
707 }
708 
710 // Test cases
711 
712 TEST_CASE( "Checking concepts" )
713 {
714  BOOST_CONCEPT_ASSERT(( concepts::CPreCellularGridSpaceND< KhalimskyPreSpaceND<2> > ));
715  BOOST_CONCEPT_ASSERT(( concepts::CPreCellularGridSpaceND< KhalimskyPreSpaceND<3> > ));
716  BOOST_CONCEPT_ASSERT(( concepts::CPreCellularGridSpaceND< KhalimskyPreSpaceND<4> > ));
717 
718  BOOST_CONCEPT_ASSERT(( concepts::CCellularGridSpaceND< KhalimskySpaceND<2> > ));
719  BOOST_CONCEPT_ASSERT(( concepts::CCellularGridSpaceND< KhalimskySpaceND<3> > ));
720  BOOST_CONCEPT_ASSERT(( concepts::CCellularGridSpaceND< KhalimskySpaceND<4> > ));
721 }
722 
723 TEST_CASE( "2D Khalimsky pre-space", "[KPreSpace][2D]" )
724 {
725  const KhalimskyPreSpaceND<2> K{};
726  INFO( "Khalimsky space is " << K );
727 
728  testScan( K, {-1, -2}, {1, 2} );
729  testIncidence( K, {0, 0} );
730  testDirectIncidence( K, {0, 0} );
735 }
736 
737 TEST_CASE( "3D Khalimsky pre-space", "[KPreSpace][3D]" )
738 {
739  const KhalimskyPreSpaceND<3> K{};
740  INFO( "Khalimsky space is " << K );
741 
742  testScan( K, {-2, -3, -4}, {1, 2, 4} );
743  testIncidence( K, {0, 0, 0} );
744  testDirectIncidence( K, {0, 0, 0} );
746  testFindABel( K );
749 }
750 
751 TEST_CASE( "4D Khalimsky pre-space", "[KPreSpace][4D]" )
752 {
753  const KhalimskyPreSpaceND<3> K{};
754  INFO( "Khalimsky space is " << K );
755 
756  testScan( K, {-1, -2, -3, -4}, {1, 0, 1, -1} );
757  testIncidence( K, {0, 0, 0, 0} );
758  testDirectIncidence( K, {0, 0, 0, 0} );
760  testFindABel( K );
763 }
764 
765 TEST_CASE( "3D closed Khalimsky space", "[KSpace][3D][closed]" )
766 {
768  const bool spaceOK = K.init( {-3, -3, -3}, {5, 3, 3}, K.CLOSED );
769  INFO( "Khalimsky space is " << K );
770  REQUIRE( spaceOK == true );
771 
772  testScan( K, {-1, -2, -1}, {1, 2, 2} );
773  testNeighborhood( K, {0, 0, 0} );
774  testNeighborhood( K, {-2, 3, 2} );
775  testFaces( K, {0, 0, 0} );
776  testFaces( K, {-2, 3, -3} );
777  testIncidence( K, {0, 0, 0} );
778  testDirectIncidence( K, {0, 0, 0} );
780  testFindABel( K );
783 }
784 
785 TEST_CASE( "2D closed Khalimsky space", "[KSpace][2D][closed]" )
786 {
788  const bool spaceOK = K.init( {-3, -3}, {5, 3}, K.CLOSED );
789  INFO( "Khalimsky space is " << K );
790  REQUIRE( spaceOK == true );
791 
792  testScan( K, {-1, -2}, {1, 2} );
793  testNeighborhood( K, {0, 0} );
794  testNeighborhood( K, {-2, 3} );
795  testFaces( K, {0, 0} );
796  testFaces( K, {-2, 3} );
797  testIncidence( K, {0, 0} );
798  testDirectIncidence( K, {0, 0} );
803 }
804 
805 TEST_CASE( "4D closed Khalimsky space", "[KSpace][4D][closed]" )
806 {
808  const bool spaceOK = K.init( {-3, -3, -3, -3}, {5, 3, 3, 3}, K.CLOSED );
809  INFO( "Khalimsky space is " << K );
810  REQUIRE( spaceOK == true );
811 
812  testScan( K, {-1, -2, 0, 1}, {1, 2, 1, 2} );
813  testNeighborhood( K, {0, 0, 0, 0} );
814  testNeighborhood( K, {-2, 3, -1, 3} );
815  testFaces( K, {0, 0, 0, 0} );
816  testFaces( K, {-2, 3, -1, 3} );
817  testIncidence( K, {0, 0, 0, 0} );
818  testDirectIncidence( K, {0, 0, 0, 0} );
820  testFindABel( K );
823 }
824 
825 TEST_CASE( "2D open Khalimsky space", "[KSpace][2D][open]" )
826 {
828  const bool spaceOK = K.init( {-3, -3}, {5, 3}, K.OPEN );
829  INFO( "Khalimsky space is " << K );
830  REQUIRE( spaceOK == true );
831 
832  testScan( K, {-1, -2}, {1, 2} );
833  testNeighborhood( K, {0, 0} );
834  testNeighborhood( K, {-2, 3} );
835  testFaces( K, {0, 0} );
836  testFaces( K, {-2, 3} );
837  testIncidence( K, {0, 0} );
838  testDirectIncidence( K, {0, 0} );
843 }
844 
845 TEST_CASE( "3D open Khalimsky space", "[KSpace][3D][open]" )
846 {
848  const bool spaceOK = K.init( {-3, -3, -3}, {5, 3, 3}, K.OPEN );
849  INFO( "Khalimsky space is " << K );
850  REQUIRE( spaceOK == true );
851 
852  testScan( K, {-1, -2, -1}, {1, 2, 2} );
853  testNeighborhood( K, {0, 0, 0} );
854  testNeighborhood( K, {-2, 3, 2} );
855  testFaces( K, {0, 0, 0} );
856  testFaces( K, {-2, 3, -3} );
857  testIncidence( K, {0, 0, 0} );
858  testDirectIncidence( K, {0, 0, 0} );
860  testFindABel( K );
863 }
864 
865 TEST_CASE( "2D periodic Khalimsky space", "[KSpace][2D][periodic]" )
866 {
868  const bool spaceOK = K.init( {-2, -3}, {2, 3}, K.PERIODIC );
869  INFO( "Khalimsky space is " << K );
870  REQUIRE( spaceOK == true );
871 
872  testScan( K, {-1, -2}, {1, 2} );
873  testNeighborhood( K, {0, 0} );
874  testNeighborhood( K, {-2, 3} );
875  testFaces( K, {0, 0} );
876  testFaces( K, {-2, 3} );
877  testIncidence( K, {0, 3} );
878  testDirectIncidence( K, {0, 3} );
883 }
884 
885 TEST_CASE( "3D periodic Khalimsky space", "[KSpace][3D][periodic]" )
886 {
888  const bool spaceOK = K.init( {-3, -3, -3}, {2, 2, 3}, K.PERIODIC );
889  INFO( "Khalimsky space is " << K );
890  REQUIRE( spaceOK == true );
891 
892  testScan( K, {-1, -2, -1}, {1, 2, 2} );
893  testNeighborhood( K, {0, 0, 0} );
894  testNeighborhood( K, {-2, 3, 2} );
895  testFaces( K, {0, 0, 0} );
896  testFaces( K, {-2, 3, -3} );
897  testIncidence( K, {0, 0, 0} );
898  testDirectIncidence( K, {0, 0, 0} );
900  testFindABel( K );
903 }
904 
905 TEST_CASE( "2D mixed Khalimsky space", "[KSpace][2D][closed][periodic]" )
906 {
908  const bool spaceOK = K.init( {-3, -3}, {5, 2}, {{ K.CLOSED, K.PERIODIC }} );
909  INFO( "Khalimsky space is " << K );
910  REQUIRE( spaceOK == true );
911 
912  testScan( K, {-1, 2}, {1, 5} );
913  testNeighborhood( K, {0, 0} );
914  testNeighborhood( K, {-2, 4} );
915  testFaces( K, {0, 0} );
916  testFaces( K, {-2, 4} );
917  testIncidence( K, {0, 3} );
918  testDirectIncidence( K, {0, 3} );
923 }
924 
925 TEST_CASE( "3D mixed Khalimsky space", "[KSpace][3D][closed][periodic][open]" )
926 {
928  const bool spaceOK = K.init( {-3, -3, -3}, {5, 3, 1}, {{ K.CLOSED, K.OPEN, K.PERIODIC }} );
929  INFO( "Khalimsky space is " << K );
930  REQUIRE( spaceOK == true );
931 
932  testScan( K, {-1, -2, -1}, {1, 2, 2} );
933  testNeighborhood( K, {0, 0, 0} );
934  testNeighborhood( K, {-2, 3, 2} );
935  testFaces( K, {0, 0, 0} );
936  testFaces( K, {-2, 3, -3} );
937  testIncidence( K, {0, 0, 0} );
938  testDirectIncidence( K, {0, 0, 0} );
940  testFindABel( K );
943 }
944 
945 
946 TEST_CASE("3D test interior/exterior voxels to a digital surface")
947 {
948  using Point = Z3i::Point;
949  const auto size=10;
950  Z3i::DigitalSet set(Z3i::Domain(Point(0,0,0),Point(size,size,size)));
951  for(auto i=0; i < size*size*size; ++i)
952  set.insertNew(Point(rand() % size, rand()%size, rand()%size));
953  INFO("Inserting " + std::to_string(set.size())+ " voxels") ;
954  REQUIRE(set.isValid());
955  Z3i::KSpace K;
956  Point low( 0, 0, 0 );
957  Point high( 10, 10, 10 );
958  K.init( low, high, true );
959  auto bel = Surfaces<Z3i::KSpace>::findABel(K, set);
961  for(const auto &surfel: surface)
962  {
963  auto voxel = K.interiorVoxel(surfel);
964  REQUIRE(set(voxel));
965  auto voxel2 = K.exteriorVoxel(surfel);
966  REQUIRE(!set(voxel2));
967  }
968 
969 
970 }
971 
972 #ifdef WITH_BIGINTEGER
973 TEST_CASE("with BigInteger")
974 {
975  KhalimskySpaceND<3,BigInteger> K( {0,0,0}, {1000,1000,1000}, true );
976  REQUIRE(true);
977 }
978 #endif
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:68
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,...
Point interiorVoxel(const SCell &c) const
For a given surfel ((n-1)-signed cell), returns its interior voxel (point in Z^d given by the direct ...
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
Point exteriorVoxel(const SCell &c) const
For a given surfel ((n-1)-signed cell), returns its exterior voxel (point in Z^d given by the indirec...
AnyCellCollection< Cell > Cells
Aim: A model of CDigitalSurfaceContainer which defines the digital surface as the boundary of an impl...
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:151
void saveEPS(const char *filename, PageSize size=Board::BoundingBox, double margin=10.0) const
Definition: Board.cpp:804
void saveSVG(const char *filename, PageSize size=Board::BoundingBox, double margin=10.0) const
Definition: Board.cpp:1011
void setUnit(Unit unit)
Definition: Board.cpp:239
Z3i::SCell SCell
Space::Point Point
Definition: StdDefs.h:168
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:136
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))
Z2i::DigitalSet DigitalSet