36 #include "DGtal/base/Common.h" 37 #include "DGtal/kernel/SpaceND.h" 38 #include "DGtal/kernel/domains/HyperRectDomain.h" 40 #include "DGtal/topology/KhalimskySpaceND.h" 41 #include "DGtal/topology/KhalimskyPreSpaceND.h" 43 #include "DGtal/topology/CCellularGridSpaceND.h" 44 #include "DGtal/topology/CPreCellularGridSpaceND.h" 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" 53 #include "DGtalCatch.h" 56 using namespace DGtal;
67 template <
typename KSpace >
73 INFO(
"Testing uNext & sNext with low = " << low <<
" & high = " << high );
77 using PK =
typename KSpace::PreCellularGridSpace;
82 for (
unsigned int t = 0; t < 1u << KSpace::dimension; ++t )
87 refPoint[ i ] = t & (1u << i) ? 1 : 0;
89 INFO(
"Current topology is " << refPoint );
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 ) );
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 ) );
108 for (
Point const & pt : domain )
113 REQUIRE( currUCell == K.uCell( pt, refUCell ) );
114 REQUIRE( currSCell == K.sCell( pt, refSCell ) );
116 uCheck = K.uNext( currUCell, lowUCell, highUCell );
117 sCheck = K.sNext( currSCell, lowSCell, highSCell );
135 template <
typename KSpace,
typename Cells >
137 typename KSpace::Cells
const & u,
141 REQUIRE( u.size() <= v.size() );
146 for(
auto const & cell : v )
148 if ( ! K.uIsInside( cell ) )
151 REQUIRE( std::find( u.cbegin(), u.cend(), K.uCell( cell ) ) != u.cend() );
169 template <
typename KSpace,
typename Cells >
171 typename KSpace::SCells
const & u,
175 REQUIRE( u.size() <= v.size() );
180 for(
auto const & cell : v )
182 if ( ! K.sIsInside( cell ) )
185 REQUIRE( std::find( u.cbegin(), u.cend(), K.sCell( cell ) ) != u.cend() );
201 template <
typename KSpace >
206 INFO(
"Testing (proper) neighborhood around point " << aPoint );
209 using PK =
typename KSpace::PreCellularGridSpace;
212 for (
unsigned int t = 0; t < 1u << KSpace::dimension; ++t )
217 refPoint[ i ] = t & (1u << i) ? 1 : 0;
219 INFO(
"Current topology is " << refPoint );
222 const auto refUCell = PK::uCell( refPoint );
224 if ( ! K.uIsInside( PK::uCell( aPoint, refUCell ) ) )
227 const auto currUCell = K.uCell( aPoint, refUCell );
228 REQUIRE( K.uTopology( currUCell ) == PK::uTopology( refUCell ) );
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 ) );
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 );
242 REQUIRE( currUCells.size() == currSCells.size() );
243 REQUIRE( refUCells.size() == refSCells.size() );
244 REQUIRE( refUCells.size() == 2*K.dimension + 1 );
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 );
256 REQUIRE( currUCells.size() == currSCells.size() );
257 REQUIRE( refUCells.size() == refSCells.size() );
258 REQUIRE( refUCells.size() == 2*K.dimension );
272 template <
typename KSpace >
277 INFO(
"Testing faces and cofaces around point " << aPoint );
280 using PK =
typename KSpace::PreCellularGridSpace;
283 for (
unsigned int t = 0; t < 1u << KSpace::dimension; ++t )
288 refPoint[ i ] = t & (1u << i) ? 1 : 0;
290 INFO(
"Current topology is " << refPoint );
293 const auto refUCell = PK::uCell( refPoint );
295 if ( ! K.uIsInside( PK::uCell( aPoint, refUCell ) ) )
298 const auto currUCell = K.uCell( aPoint, refUCell );
299 REQUIRE( K.uTopology( currUCell ) == PK::uTopology( refUCell ) );
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 ) );
308 const auto currUCells = K.uFaces( currUCell );
309 const auto refUCells = PK::uFaces( currUCell );
311 REQUIRE( refUCells.size() == floor( std::pow( 3, K.uDim( currUCell ) ) - 1 ) );
317 const auto currUCells = K.uCoFaces( currUCell );
318 const auto refUCells = PK::uCoFaces( currUCell );
332 template <
typename KSpace >
337 INFO(
"Testing block Incidence in KSpace..." );
339 using SCell =
typename KSpace::SCell;
340 using DirIterator =
typename KSpace::DirIterator;
342 SCell sspel = K.sSpel( aPoint, K.POS );
344 for ( DirIterator q1 = K.sDirs( sspel ); q1 != 0; ++q1 )
345 for ( DirIterator q2 = K.sDirs( sspel ); q2 != 0; ++q2 )
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
356 REQUIRE( l10 == K.sOpp( l01 ) );
368 template <
typename KSpace >
373 INFO(
"Testing direct Incidence in KSpace..." );
375 using SCell =
typename KSpace::SCell;
376 using DirIterator =
typename KSpace::DirIterator;
378 SCell sspel = K.sSpel( aPoint, K.POS );
380 for ( DirIterator q1 = K.sDirs( sspel ); q1 != 0; ++q1 )
381 for ( DirIterator q2 = K.sDirs( sspel ); q2 != 0; ++q2 )
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
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 ) ) );
412 template <
typename KSpace>
415 using SCell =
typename KSpace::SCell;
417 using Integer =
typename KSpace::Integer;
419 INFO(
"Testing surfel adjacency ..." );
422 INFO(
"Testing surfel directness ..." );
423 const SCell sspel = K.sCell( Point::diagonal(1), K.POS );
425 for (
Dimension k = 0; k < K.dimension; ++k )
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 );
432 surfel = K.sIncident( sspel, k,
false );
433 innerspel = K.sDirectIncident( surfel, K.sOrthDir( surfel ) );
434 INFO(
"spel=" << sspel <<
" surfel=" << surfel <<
" innerspel=" << innerspel );
438 INFO(
"Testing surfel neighborhood ..." );
440 SCell surfel = K.sIncident( sspel, 0,
false );
441 SN.
init( &K, &SAdj, surfel );
443 INFO(
"Testing surface tracking ..." );
448 const Point low = Point::diagonal(-3);
449 const Point high = Point::diagonal(3) + Point::base(0, 2);
450 REQUIRE( K.uIsInside( KSpace::PreCellularGridSpace::uSpel( low ) ) );
451 REQUIRE( K.uIsInside( KSpace::PreCellularGridSpace::uSpel( high ) ) );
454 DigitalSet shape_set( domain );
456 const Point pcenter = Point::diagonal(0) + Point::base(0);
460 SCell other1, other2;
463 INFO(
"directNext = " << other1 );
466 INFO(
"indirectNext= " << other2 );
468 std::set<SCell> bdry;
470 REQUIRE( bdry.size() == ( 2*K.dimension*(2*K.dimension-1) ) );
472 std::set<SCell> bdry_direct;
474 REQUIRE( bdry_direct.size() == ( 2*K.dimension*(2*K.dimension-1) ) );
476 if ( K.dimension == 2 )
478 INFO(
"Testing Board2D" );
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 )
485 board.
saveEPS(
"cells-2.eps" );
486 board.
saveSVG(
"cells-2.svg" );
495 template <
typename KSpace>
500 typedef typename KSpace::Integer Integer;
502 typedef typename KSpace::SCell SCell;
507 INFO(
"Testing cell draw on digital board ..." );
509 const Point low( -3, -3 );
510 const Point high( 5, 3 );
512 const Domain
domain( low, high );
518 Cell uspel = K.uCell( Point::diagonal(1) );
521 << K.uIncident( uspel, 0,
false )
522 << K.uIncident( uspel, 1,
false );
524 const SCell sspel2 = K.sCell(
Point( 5, 1 ), K.POS );
527 Color( 255, 100, 100 ),
531 << K.sIncident( sspel2, 0, K.sDirect( sspel2, 0 ) )
532 << K.sIncident( sspel2, 1, K.sDirect( sspel2, 0 ) );
534 board.
saveEPS(
"cells-1.eps" );
535 board.
saveSVG(
"cells-1.svg" );
539 const SCell slinel0 = K.sIncident( sspel2, 0, K.sDirect( sspel2, 0 ) );
540 const SCell spointel01 = K.sIncident( slinel0, 1, K.sDirect( slinel0, 1 ) );
544 Color( 255, 100, 100 ) ) )
548 Color( 100, 255, 100 ) ) )
552 Color( 100, 100, 255 ) ) )
555 board.
saveEPS(
"cells-3.eps" );
556 board.
saveSVG(
"cells-3.svg" );
565 template <
typename KSpace>
574 typedef typename KSpace::SCell SCell;
576 INFO(
"Test FindABel" );
578 const Point low = Point::diagonal(-3);
579 const Point high = Point::diagonal(3);
581 REQUIRE( K.uIsInside( KSpace::PreCellularGridSpace::uSpel( low ) ) );
582 REQUIRE( K.uIsInside( KSpace::PreCellularGridSpace::uSpel( high ) ) );
584 const Domain
domain( low, high );
585 DigitalSet shape_set( domain );
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);
596 shape_set.insert( p000 );
597 shape_set.insert( p100 );
607 REQUIRE( s010 == K.sCell( Point::diagonal(1) + Point::base(1),
true ) );
608 REQUIRE( s001 == K.sCell( Point::diagonal(1) + Point::base(2),
false ) );
617 template <
typename KSpace>
622 typedef typename KSpace::Cells Cells;
626 const Point low = Point::diagonal(-1);
627 const Point high = Point::diagonal(1);
628 REQUIRE( K.uIsInside( KSpace::PreCellularGridSpace::uSpel( low ) ) );
629 REQUIRE( K.uIsInside( KSpace::PreCellularGridSpace::uSpel( high ) ) );
631 const Cell vox = K.uSpel( Point::zero );
632 const Cells faces = K.uFaces( vox );
635 INFO(
"Check CellularGridSpaceND::uFaces" );
642 for (
auto const & face : faces )
643 if ( K.uDim( face ) == k )
662 template <
typename KSpace>
667 typedef typename KSpace::Cells Cells;
671 const Point low = Point::diagonal(-1);
672 const Point high = Point::diagonal(1);
673 REQUIRE( K.uIsInside( KSpace::PreCellularGridSpace::uSpel( low ) ) );
674 REQUIRE( K.uIsInside( KSpace::PreCellularGridSpace::uSpel( high ) ) );
676 const Cell pointel = K.uPointel( Point::zero );
677 const Cells cofaces = K.uCoFaces( pointel );
680 INFO(
"Check CellularGridSpaceND::uCoFaces" );
687 for (
auto const & coface : cofaces )
689 if ( K.uDim( coface ) == k )
720 TEST_CASE(
"2D Khalimsky pre-space",
"[KPreSpace][2D]" )
723 INFO(
"Khalimsky space is " <<
K );
734 TEST_CASE(
"3D Khalimsky pre-space",
"[KPreSpace][3D]" )
737 INFO(
"Khalimsky space is " <<
K );
748 TEST_CASE(
"4D Khalimsky pre-space",
"[KPreSpace][4D]" )
751 INFO(
"Khalimsky space is " <<
K );
753 testScan(
K, {-1, -2, -3, -4}, {1, 0, 1, -1} );
762 TEST_CASE(
"3D closed Khalimsky space",
"[KSpace][3D][closed]" )
765 const bool spaceOK = K.
init( {-3, -3, -3}, {5, 3, 3}, K.
CLOSED );
766 INFO(
"Khalimsky space is " << K );
769 testScan( K, {-1, -2, -1}, {1, 2, 2} );
782 TEST_CASE(
"2D closed Khalimsky space",
"[KSpace][2D][closed]" )
785 const bool spaceOK = K.
init( {-3, -3}, {5, 3}, K.
CLOSED );
786 INFO(
"Khalimsky space is " << K );
802 TEST_CASE(
"4D closed Khalimsky space",
"[KSpace][4D][closed]" )
805 const bool spaceOK = K.
init( {-3, -3, -3, -3}, {5, 3, 3, 3}, K.
CLOSED );
806 INFO(
"Khalimsky space is " << K );
809 testScan( K, {-1, -2, 0, 1}, {1, 2, 1, 2} );
822 TEST_CASE(
"2D open Khalimsky space",
"[KSpace][2D][open]" )
825 const bool spaceOK = K.
init( {-3, -3}, {5, 3}, K.
OPEN );
826 INFO(
"Khalimsky space is " << K );
842 TEST_CASE(
"3D open Khalimsky space",
"[KSpace][3D][open]" )
845 const bool spaceOK = K.
init( {-3, -3, -3}, {5, 3, 3}, K.
OPEN );
846 INFO(
"Khalimsky space is " << K );
849 testScan( K, {-1, -2, -1}, {1, 2, 2} );
862 TEST_CASE(
"2D periodic Khalimsky space",
"[KSpace][2D][periodic]" )
865 const bool spaceOK = K.
init( {-2, -3}, {2, 3}, K.
PERIODIC );
866 INFO(
"Khalimsky space is " << K );
882 TEST_CASE(
"3D periodic Khalimsky space",
"[KSpace][3D][periodic]" )
885 const bool spaceOK = K.
init( {-3, -3, -3}, {2, 2, 3}, K.
PERIODIC );
886 INFO(
"Khalimsky space is " << K );
889 testScan( K, {-1, -2, -1}, {1, 2, 2} );
902 TEST_CASE(
"2D mixed Khalimsky space",
"[KSpace][2D][closed][periodic]" )
906 INFO(
"Khalimsky space is " << K );
922 TEST_CASE(
"3D mixed Khalimsky space",
"[KSpace][3D][closed][periodic][open]" )
926 INFO(
"Khalimsky space is " << K );
929 testScan( K, {-1, -2, -1}, {1, 2, 2} );
Custom style class redefining the pen attributes. You may use Board2D::Color::None for transparent co...
HyperRectDomain< Space > Domain
Aim: This concept describes an unbounded cellular grid space in nD. In these spaces obtained by carte...
const Domain domain(Point(1, 2), Point(6, 5))
void testCellDrawOnBoard(KSpace const &K)
void testDirectIncidence(KSpace const &K, typename KSpace::Point const &aPoint)
Aim: SpaceND is a utility class that defines the fundamental structure of a Digital Space in ND...
void cmpSCellsIfInside(KSpace const &K, typename KSpace::SCells const &u, Cells const &v)
DGtal::uint32_t Dimension
Custom style class redefining the pen color and the fill color. You may use Board2D::Color::None for ...
Aim: This class is a model of CPreCellularGridSpaceND. It represents the cubical grid as a cell compl...
The dimension is periodic.
static SCell findABel(const KSpace &K, const PointPredicate &pp, unsigned int nbtries=1000)
void saveSVG(const char *filename, PageSize size=Board::BoundingBox, double margin=10.0) const
void testIncidence(KSpace const &K, typename KSpace::Point const &aPoint)
REQUIRE(domain.isInside(aPoint))
static void trackBoundary(SCellSet &surface, const KSpace &K, const SurfelAdjacency< KSpace::dimension > &surfel_adj, const PointPredicate &pp, const SCell &start_surfel)
void testFaces(KSpace const &K, typename KSpace::Point const &aPoint)
void testSurfelAdjacency(KSpace const &K)
bool init(const Point &lower, const Point &upper, bool isClosed)
static void addNorm1Ball(TDigitalSet &aSet, const Point &aCenter, UnsignedInteger aRadius)
void clear(const DGtal::Color &color=DGtal::Color::None)
void init(const KSpace *space, const SurfelAdjacency< KSpace::dimension > *adj, const SCell &aSurfel)
void testCellularGridSpaceNDFaces(KSpace const &K)
void saveEPS(const char *filename, PageSize size=Board::BoundingBox, double margin=10.0) const
TEST_CASE("Checking concepts")
void testCellularGridSpaceNDCoFaces(KSpace const &K)
std::string className() const
DGtal is the top-level namespace which contains all DGtal functions and types.
Aim: A wrapper class around a STL associative container for storing sets of digital points within som...
void cmpUCellsIfInside(KSpace const &K, typename KSpace::Cells const &u, Cells const &v)
Aim: This concept describes a cellular grid space in nD. In these spaces obtained by cartesian produc...
static void trackClosedBoundary(SCellSet &surface, const KSpace &K, const SurfelAdjacency< KSpace::dimension > &surfel_adj, const PointPredicate &pp, const SCell &start_surfel)
Modifier class in a Board2D stream. Useful to choose your own mode for a given class. Realizes the concept CDrawableWithBoard2D.
unsigned int getAdjacentOnDigitalSet(SCell &adj_surfel, const DigitalSet &obj, Dimension track_dir, bool pos) const
Structure representing an RGB triple with alpha component.
void testNeighborhood(KSpace const &K, typename KSpace::Point const &aPoint)
void testScan(KSpace const &K, typename KSpace::Point const &low, typename KSpace::Point const &high)
void testFindABel(KSpace const &K)
boost::int64_t int64_t
signed 94-bit integer.
Aim: This class is a model of CCellularGridSpaceND. It represents the cubical grid as a cell complex...
The dimension is closed and non-periodic.
Aim: This class specializes a 'Board' class so as to display DGtal objects more naturally (with <<)...