DGtal  0.9.2
testObject-benchmark.cpp
1 
30 #include <cmath>
32 #include <iostream>
33 #include <sstream>
34 #include "DGtal/base/Common.h"
35 #include "DGtal/kernel/SpaceND.h"
36 #include "DGtal/kernel/domains/DomainPredicate.h"
37 #include "DGtal/kernel/domains/HyperRectDomain.h"
38 #include "DGtal/kernel/sets/DigitalSetSelector.h"
39 #include "DGtal/kernel/sets/DigitalSetConverter.h"
40 #include "DGtal/topology/MetricAdjacency.h"
41 #include "DGtal/topology/DomainMetricAdjacency.h"
42 #include "DGtal/topology/DomainAdjacency.h"
43 #include "DGtal/topology/DigitalTopology.h"
44 #include "DGtal/topology/Object.h"
45 #include "DGtal/graph/Expander.h"
46 #include "DGtal/io/boards/Board2D.h"
48 
49 using namespace std;
50 using namespace DGtal;
51 using namespace LibBoard;
52 
53 #define INBLOCK_TEST(x) \
54  nbok += ( x ) ? 1 : 0; \
55  nb++; \
56  trace.info() << "(" << nbok << "/" << nb << ") " \
57  << #x << std::endl;
58 
59 #define INBLOCK_TEST2(x,y) \
60  nbok += ( x ) ? 1 : 0; \
61  nb++; \
62  trace.info() << "(" << nbok << "/" << nb << ") " \
63  << y << std::endl;
64 
66 // Functions for testing class Object.
68 
72 bool testObject()
73 {
74  unsigned int nbok = 0;
75  unsigned int nb = 0;
76 
77  typedef SpaceND< 2 > Z2;
78  typedef Z2::Point Point;
79  typedef Point::Coordinate Coordinate;
80  typedef HyperRectDomain< Z2 > DomainType;
81  Point p1( -449, -449 );
82  Point p2( 449, 449 );
83  DomainType domain( p1, p2 );
84 
85  // typedef DomainMetricAdjacency< DomainType, 1 > Adj4;
86  // typedef DomainMetricAdjacency< DomainType, 2 > Adj8;
87  typedef MetricAdjacency< Z2, 1 > MetricAdj4;
88  typedef MetricAdjacency< Z2, 2 > MetricAdj8;
91  typedef DigitalTopology< Adj4, Adj8 > DT48;
93  MediumSet;
94 // typedef DigitalSetSelector< DomainType, SMALL_DS >::Type
95 // MediumSet;
96  typedef Object<DT48, MediumSet> ObjectType;
97  typedef ObjectType::SmallSet SmallSet;
98  typedef Object<DT48, SmallSet> SmallObjectType;
99  typedef ObjectType::Size Size;
100 
101  // Adj4 adj4( domain );
102  // Adj8 adj8( domain );
103  MetricAdj4 madj4;
104  MetricAdj8 madj8;
105  Adj4 adj4( domain, madj4 );
106  Adj8 adj8( domain, madj8 );
107  DT48 dt48( adj4, adj8, JORDAN_DT );
108 
109  Coordinate r = 449;
110  double radius = (double) (r + 1);
111  Point c( 0, 0 );
112  Point l( r, 0 );
113  MediumSet disk( domain );
114  ostringstream sstr;
115  sstr << "Creating disk( r < " << radius << " ) ...";
116  trace.beginBlock ( sstr.str() );
117  for ( DomainType::ConstIterator it = domain.begin();
118  it != domain.end();
119  ++it )
120  {
121  if ( (*it - c ).norm() < radius ) // 450.0
122  // insertNew is very important for vector container.
123  disk.insertNew( *it );
124  }
125  trace.endBlock();
126 
127  trace.beginBlock ( "Testing Object instanciation and smart copy ..." );
128  ObjectType disk_object( dt48, disk );
129  nbok += disk_object.size() == 636101 ? 1 : 0;
130  nb++;
131  trace.info() << "(" << nbok << "/" << nb << ") "
132  << "Disk (r=450.0) " << disk_object << std::endl;
133  trace.info() << " size=" << disk_object.size() << std::endl;
134  ObjectType disk_object2( disk_object );
135  nbok += disk_object2.size() == 636101 ? 1 : 0;
136  nb++;
137  trace.info() << "(" << nbok << "/" << nb << ") "
138  << "Disk2 (r=450.0) " << disk_object2 << std::endl;
139  trace.info() << " size=" << disk_object2.size() << std::endl;
140  trace.endBlock();
141 
142  trace.beginBlock ( "Testing copy on write system ..." );
143  trace.info() << "Removing center point in Disk." << std::endl;
144  disk_object.pointSet().erase( c );
145  disk_object2.pointSet().insert( c );
146  nbok += disk_object.size() == 636100 ? 1 : 0;
147  nb++;
148  trace.info() << "(" << nbok << "/" << nb << ") "
149  << "Disk - c (r=450.0) " << disk_object << std::endl;
150  trace.info() << " size=" << disk_object.size() << std::endl;
151  nbok += disk_object2.size() == 636101 ? 1 : 0;
152  nb++;
153  trace.info() << "(" << nbok << "/" << nb << ") "
154  << "Disk2 + c (r=450.0) " << disk_object2 << std::endl;
155  trace.info() << " size=" << disk_object2.size() << std::endl;
156  trace.endBlock();
157 
158  trace.beginBlock ( "Testing neighborhoods ..." );
159  Object<DT48, SmallSet> neigh = disk_object.neighborhood( c );
160  nbok += neigh.size() == 4 ? 1 : 0;
161  nb++;
162  trace.info() << "(" << nbok << "/" << nb << ") "
163  << "N_4(Disk, c).size() = " << neigh.size()
164  << " == 4" << std::endl;
165  neigh = disk_object.properNeighborhood( l );
166  nbok += neigh.size() == 3 ? 1 : 0;
167  nb++;
168  trace.info() << "(" << nbok << "/" << nb << ") "
169  << "N*_4(Disk, " << l << ").size() = " << neigh.size()
170  << " == 3" << std::endl;
171  Size size = disk_object.properNeighborhoodSize( l );
172  nbok += size == 3 ? 1 : 0;
173  nb++;
174  trace.info() << "(" << nbok << "/" << nb << ") "
175  << "#N*_4(Disk, " << l << ") = " << size
176  << " == 3" << std::endl;
177 
178  neigh = disk_object2.neighborhood( c );
179  nbok += neigh.size() == 5 ? 1 : 0;
180  nb++;
181  trace.info() << "(" << nbok << "/" << nb << ") "
182  << "N_4(Disk2, c).size() = " << neigh.size()
183  << " == 5" << std::endl;
184  trace.endBlock();
185 
186  trace.beginBlock ( "Testing set converters ..." );
188  ( neigh.pointSet(), disk_object.pointSet() );
189  nbok += neigh.size() == 636100 ? 1 : 0;
190  nb++;
191  trace.info() << "(" << nbok << "/" << nb << ") "
192  << "neigh = disk_object, size() = " << neigh.size()
193  << " == 636100" << std::endl;
194  SmallObjectType neigh2 = disk_object2.neighborhood( c );
196  ( neigh.pointSet(), neigh2.pointSet() );
197  nbok += neigh.size() == 5 ? 1 : 0;
198  nb++;
199  trace.info() << "(" << nbok << "/" << nb << ") "
200  << "neigh = N_4(Disk2, c), size() = " << neigh.size()
201  << " == 5" << std::endl;
202  trace.endBlock();
203 
204  trace.beginBlock ( "Testing border extraction ..." );
205  ObjectType bdisk = disk_object.border();
206  nbok += bdisk.size() == 3372 ? 1 : 0;
207  nb++;
208  trace.info() << "(" << nbok << "/" << nb << ") "
209  << "Border(Disk, c), size() = " << bdisk.size()
210  << " == 3372" << std::endl;
211  ObjectType bdisk2 = disk_object2.border();
212  nbok += bdisk2.size() == 3364 ? 1 : 0;
213  nb++;
214  trace.info() << "(" << nbok << "/" << nb << ") "
215  << "Border(Disk2, c), size() = " << bdisk2.size()
216  << " == 3364" << std::endl;
217  trace.endBlock();
218 
219  trace.beginBlock ( "Testing expansion by layers on the boundary ..." );
220  typedef Expander< ObjectType > ObjectExpander;
221  ObjectExpander expander( bdisk, *(bdisk.pointSet().begin()) );
222  while ( ! expander.finished() )
223  {
224  nbok += expander.layer().size() <= 2 ? 1 : 0;
225  nb++;
226  trace.info() << "(" << nbok << "/" << nb << ") "
227  << "expander.layer.size() <= 2 "
228  << expander << std::endl;
229  expander.nextLayer();
230  }
231  trace.endBlock();
232 
233  trace.beginBlock ( "Testing expansion by layers on the disk from center..." );
234  ObjectExpander expander2( disk_object2, c );
235  while ( ! expander2.finished() )
236  {
237  trace.info() << expander2 << std::endl;
238  expander2.nextLayer();
239  }
240  nbok += expander2.distance() <= sqrt(2.0) * radius ? 1 : 0;
241  nb++;
242  trace.info() << "(" << nbok << "/" << nb << ") "
243  << "expander.distance() = " << expander2.distance()
244  << " <= " << sqrt(2.0)*radius << std::endl;
245  trace.endBlock();
246 
247  return nbok == nb;
248 }
249 
254 bool testObject3D()
255 {
256  unsigned int nbok = 0;
257  unsigned int nb = 0;
258  typedef SpaceND< 3 > Z3;
262  typedef Z3::Point Point;
264  typedef Domain::ConstIterator DomainConstIterator;
266  typedef Object<DT6_18, DigitalSet> ObjectType;
267  Adj6 adj6;
268  Adj18 adj18;
269  DT6_18 dt6_18( adj6, adj18, JORDAN_DT );
270 
271  Point p1( -50, -50, -50 );
272  Point p2( 50, 50, 50 );
273  Domain domain( p1, p2 );
274  Point c( 0, 0, 0 );
275  Point d( 10, 2, 0 );
276 
277  trace.beginBlock ( "Testing 3D Object instanciation and smart copy ..." );
278  trace.info() << "Creating diamond (r=45)" << endl;
279  // diamond of radius 30
280  DigitalSet diamond_set( domain );
281  for ( DomainConstIterator it = domain.begin(); it != domain.end(); ++it )
282  {
283  if ( (*it - c ).norm1() <= 45 )
284  diamond_set.insertNew( *it );
285  }
286  ObjectType diamond( dt6_18, diamond_set );
287  trace.info() << "Cloning diamond" << endl;
288  // The following line takes almost no time.
289  ObjectType diamond_clone( diamond );
290  // Since one of the objects is modified, the set is duplicated at the following line
291  trace.info() << "Removing two points " << c << " and " << d << endl;
292  diamond_clone.pointSet().erase( c );
293  diamond_clone.pointSet().erase( d );
294 
295  trace.info() << "Inserting into vector<Object>" << endl;
296  vector<ObjectType> objects;
297  back_insert_iterator< vector< ObjectType > > inserter( objects );
298  *inserter++ = diamond;
299  *inserter++ = diamond_clone;
300 
301  for ( vector<ObjectType>::const_iterator it = objects.begin();
302  it != objects.end();
303  ++it )
304  trace.info() << "- objects[" << (it - objects.begin() ) << "]"
305  << " = " << *it << endl;
306 
307  INBLOCK_TEST( objects[ 0 ].size() == ( objects[ 1 ].size() + 2 ) );
308  INBLOCK_TEST( objects[ 0 ].size() == 125671 );
309  trace.endBlock();
310 
311  trace.beginBlock ( "Testing connected component extraction ..." );
312  // JOL: do like this for output iterators pointing on the same
313  // container as 'this'. Works fine and nearly as fast.
314  //
315  // ObjectType( objects[ 0 ] ).writeComponents( inserter );
316 
317  trace.beginBlock ( "Components of diamond.border() ..." );
318  vector<ObjectType> objects2;
319  back_insert_iterator< vector< ObjectType > > inserter2( objects2 );
320  unsigned int nbc0 = objects[ 0 ].border().writeComponents( inserter2 );
321  INBLOCK_TEST( nbc0 == 1 );
322  INBLOCK_TEST( objects[ 0 ].computeConnectedness() == CONNECTED );
323  trace.endBlock();
324 
325  trace.beginBlock ( "Components of diamond_clone.border() ..." );
326  unsigned int nbc1 = objects[ 1 ].border().writeComponents( inserter2 );
327  INBLOCK_TEST( nbc1 == 3 );
328  trace.endBlock();
329  for ( vector<ObjectType>::const_iterator it = objects2.begin();
330  it != objects2.end();
331  ++it )
332  trace.info() << "- objects2[" << (it - objects2.begin() ) << "]"
333  << " = " << *it << endl;
334  INBLOCK_TEST( objects2[ 0 ].size() == objects2[ 1 ].size() );
335  INBLOCK_TEST( objects2[ 2 ].size() == objects2[ 3 ].size() );
336  INBLOCK_TEST( objects2[ 0 ].size() == 15848 );
337  INBLOCK_TEST( objects2[ 2 ].size() == 18 );
338 
339  trace.endBlock();
340 
341  return nbok == nb;
342 
343 }
344 
349 bool testSimplePoints3D()
350 {
351  unsigned int nbok = 0;
352  unsigned int nb = 0;
353  typedef SpaceND< 3 > Z3;
354  typedef MetricAdjacency< Z3, 1 > Adj6;
355  typedef MetricAdjacency< Z3, 2 > Adj18;
356  typedef DigitalTopology< Adj6, Adj18 > DT6_18;
357  typedef Z3::Point Point;
358  typedef HyperRectDomain< Z3 > Domain;
359  typedef Domain::ConstIterator DomainConstIterator;
361  typedef Object<DT6_18, DigitalSet> ObjectType;
362  typedef Object<DT6_18, DigitalSet>::SmallObject SmallObjectType;
363  typedef Object<DT6_18, DigitalSet>::SmallComplementObject SmallComplementObjectType;
364  Adj6 adj6;
365  Adj18 adj18;
366  DT6_18 dt6_18( adj6, adj18, JORDAN_DT );
367 
368  Point p1( -10, -10, -10 );
369  Point p2( 10, 10, 10 );
370  Domain domain( p1, p2 );
371  Point c( 0, 0, 0 );
372  Point r( 3, 0, 0 );
373 
374  trace.beginBlock ( "Creating Diamond (r=4)" );
375  // diamond of radius 4
376  DigitalSet diamond_set( domain );
377  for ( DomainConstIterator it = domain.begin(); it != domain.end(); ++it )
378  {
379  if ( (*it - c ).norm1() <= 3 )
380  diamond_set.insertNew( *it );
381  }
382  diamond_set.erase( c );
383  ObjectType diamond( dt6_18, diamond_set );
384  trace.endBlock();
385 
386  trace.beginBlock ( "Geodesic neighborhoods ..." );
387  SmallObjectType geoN6_3 = diamond.geodesicNeighborhood( adj6, r, 3 );
388  SmallObjectType geoN18_2 = diamond.geodesicNeighborhood( adj18, r, 2 );
389  trace.info() << "geoN6_3 = " << geoN6_3 << endl;
390  trace.info() << "geoN18_2 = " << geoN18_2 << endl;
391  SmallComplementObjectType cgeoN6_3 = diamond.geodesicNeighborhoodInComplement( adj6, r, 3 );
392  SmallComplementObjectType cgeoN18_2 = diamond.geodesicNeighborhoodInComplement( adj18, r, 2 );
393  trace.info() << "cgeoN6_3 = " << cgeoN6_3 << endl;
394  trace.info() << "cgeoN18_2 = " << cgeoN18_2 << endl;
395  trace.endBlock();
396 
397  trace.beginBlock ( "Simple points ..." );
398  for ( DigitalSet::ConstIterator it = diamond.pointSet().begin();
399  it != diamond.pointSet().end();
400  ++it )
401  trace.info() << "- " << *it
402  << " " << ( diamond.isSimple( *it ) ? "Simple" : "Not simple" )
403  << endl;
404  trace.endBlock();
405 
406 
407  return nbok == nb;
408 }
409 
410 
411 bool testDraw()
412 {
413  unsigned int nbok = 0;
414  unsigned int nb = 0;
415 
416  trace.beginBlock ( "testDraw(): testing drawing commands." );
417 
418  typedef SpaceND< 2 > Z2;
419  typedef Z2::Point Point;
420  typedef Point::Coordinate Coordinate;
421  typedef HyperRectDomain< Z2 > DomainType;
422  Point p1( -10, -10 );
423  Point p2( 10, 10 );
424  DomainType domain( p1, p2 );
425 
426  // typedef DomainMetricAdjacency< DomainType, 1 > Adj4;
427  // typedef DomainMetricAdjacency< DomainType, 2 > Adj8;
428  typedef MetricAdjacency< Z2, 1 > MetricAdj4;
429  typedef MetricAdjacency< Z2, 2 > MetricAdj8;
432  typedef DigitalTopology< Adj4, Adj8 > DT48;
433  typedef DigitalTopology< Adj8, Adj4 > DT84;
435  MediumSet;
436 // typedef DigitalSetSelector< DomainType, SMALL_DS >::Type
437 // MediumSet;
438  typedef Object<DT48, MediumSet> ObjectType;
439  typedef Object<DT84, MediumSet> ObjectType84;
440 
441  //typedef ObjectType::SmallSet SmallSet;
442  //typedef Object<DT48, SmallSet> SmallObjectType;
443  //typedef ObjectType::Size Size;
444 
445  // Adj4 adj4( domain );
446  // Adj8 adj8( domain );
447  MetricAdj4 madj4;
448  MetricAdj8 madj8;
449  Adj4 adj4( domain, madj4 );
450  Adj8 adj8( domain, madj8 );
451  DT48 dt48( adj4, adj8, JORDAN_DT );
452  DT84 dt84( adj8, adj4, JORDAN_DT );
453 
454  Coordinate r = 5;
455  double radius = (double) (r + 1);
456  Point c( 0, 0 );
457  Point l( r, 0 );
458  MediumSet disk( domain );
459  ostringstream sstr;
460  sstr << "Creating disk( r < " << radius << " ) ...";
461  trace.beginBlock ( sstr.str() );
462  for ( DomainType::ConstIterator it = domain.begin();
463  it != domain.end();
464  ++it )
465  {
466  if ( (*it - c ).norm() < radius ) // 450.0
467  // insertNew is very important for vector container.
468  disk.insertNew( *it );
469  }
470  trace.endBlock();
471 
472  trace.beginBlock ( "Testing Object instanciation and smart copy ..." );
473  ObjectType disk_object( dt48, disk );
474  ObjectType84 disk_object2( dt84, disk );
475  trace.endBlock();
476 
477  trace.beginBlock ( "Testing export as SVG with libboard." );
478 
479  Board2D board;
480  board.setUnit(Board::UCentimeter);
481 
482  board << SetMode( domain.className(), "Grid" ) << domain;
483  board << disk_object;
484 
485  board.saveSVG("disk-object.svg");
486 
487  Board2D board2;
488  board2.setUnit(Board::UCentimeter);
489 
490  board2 << SetMode( domain.className(), "Grid" ) << domain;
491  board2 << SetMode( disk_object.className(), "DrawAdjacencies" ) << disk_object;
492 
493  board2.saveSVG("disk-object-adj.svg");
494 
495  Board2D board3;
496  board3.setUnit( Board::UCentimeter );
497 
498  board3 << SetMode( domain.className(), "Grid" ) << domain;
499  board3 << SetMode( disk_object2.className(), "DrawAdjacencies" ) << disk_object2;
500 
501  board3.saveSVG("disk-object-adj-bis.svg");
502  trace.endBlock();
503 
504  trace.endBlock();
505 
506  return nbok == nb;
507 
508 }
509 
511 // Standard services - public :
512 
513 int main( int argc, char** argv )
514 {
515  trace.beginBlock ( "Testing class Object" );
516  trace.info() << "Args:";
517  for ( int i = 0; i < argc; ++i )
518  trace.info() << " " << argv[ i ];
519  trace.info() << endl;
520 
521  bool res = testObject() &&
522  testObject3D() && testDraw()
523  && testSimplePoints3D();
524 
525  trace.emphase() << ( res ? "Passed." : "Error." ) << endl;
526  trace.endBlock();
527  return res ? 0 : 1;
528 }
529 // //
Aim: An object (or digital object) represents a set in some digital space associated with a digital t...
Definition: Object.h:119
void beginBlock(const std::string &keyword="")
DigitalSetSelector< Domain, BIG_DS+HIGH_BEL_DS >::Type DigitalSet
Definition: StdDefs.h:100
const ConstIterator & begin() const
const ConstIterator & end() const
DigitalTopology< Adj6, Adj18 > DT6_18
Definition: StdDefs.h:164
MetricAdjacency< Space, 2 > Adj8
Definition: StdDefs.h:92
Trace trace
Definition: Common.h:130
Aim: SpaceND is a utility class that defines the fundamental structure of a Digital Space in ND...
Definition: SpaceND.h:95
Aim: Parallelepidec region of a digital space, model of a 'CDomain'.
STL namespace.
double endBlock()
Space Z3
Definition: StdDefs.h:145
MetricAdjacency< Space, 1 > Adj4
Definition: StdDefs.h:90
const DigitalSet & pointSet() const
Aim: Describes digital adjacencies in digital spaces that are defined with the 1-norm and the infinit...
Struct representing a 2D point.
Definition: Point.h:27
std::string className() const
SmallObject neighborhood(const Point &p) const
SmallObject properNeighborhood(const Point &p) const
Aim: This class is useful to visit an object by adjacencies, layer by layer.
Definition: Expander.h:97
Aim: Represents a digital topology as a couple of adjacency relations.
MetricAdjacency< Space, 1 > Adj6
Definition: StdDefs.h:159
std::ostream & emphase()
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...
Size size() const
Space Z2
Definition: StdDefs.h:76
void saveSVG(const char *filename, PageSize size=Board::BoundingBox, double margin=10.0) const
Definition: Board.cpp:1012
std::ostream & info()
Modifier class in a Board2D stream. Useful to choose your own mode for a given class. Realizes the concept CDrawableWithBoard2D.
Definition: Board2D.h:247
void setUnit(Unit unit)
Definition: Board.cpp:240
Aim: Utility class to convert between types of sets.
Aim: Given a domain and an adjacency, limits the given adjacency to the specified domain for all adja...
MetricAdjacency< Space, 2 > Adj18
Definition: StdDefs.h:161
Aim: This class specializes a 'Board' class so as to display DGtal objects more naturally (with <<)...
Definition: Board2D.h:70