DGtal  0.6.devel
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
testObject.cpp
1 
30 
31 #include <cmath>
32 #include <iostream>
33 #include <sstream>
34 #include <queue>
35 #include "DGtal/base/Common.h"
36 #include "DGtal/kernel/SpaceND.h"
37 #include "DGtal/kernel/domains/DomainPredicate.h"
38 #include "DGtal/kernel/domains/HyperRectDomain.h"
39 #include "DGtal/kernel/sets/DigitalSetSelector.h"
40 #include "DGtal/kernel/sets/DigitalSetConverter.h"
41 #include "DGtal/topology/MetricAdjacency.h"
42 #include "DGtal/topology/DomainMetricAdjacency.h"
43 #include "DGtal/topology/DomainAdjacency.h"
44 #include "DGtal/topology/DigitalTopology.h"
45 #include "DGtal/topology/Object.h"
46 #include "DGtal/topology/Expander.h"
47 #include "DGtal/io/boards/Board2D.h"
48 #include "DGtal/io/Color.h"
49 #include "DGtal/io/colormaps/GradientColorMap.h"
50 #include "DGtal/shapes/Shapes.h"
51 #include "DGtal/helpers/StdDefs.h"
53 
54 using namespace std;
55 using namespace DGtal;
56 using namespace LibBoard;
57 
58 #define INBLOCK_TEST(x) \
59  nbok += ( x ) ? 1 : 0; \
60  nb++; \
61  trace.info() << "(" << nbok << "/" << nb << ") " \
62  << #x << std::endl;
63 
64 #define INBLOCK_TEST2(x,y) \
65  nbok += ( x ) ? 1 : 0; \
66  nb++; \
67  trace.info() << "(" << nbok << "/" << nb << ") " \
68  << y << std::endl;
69 
71 // Functions for testing class Object.
73 
77 bool testObject()
78 {
79  unsigned int nbok = 0;
80  unsigned int nb = 0;
81 
82  typedef SpaceND< 2 > Z2;
83  typedef Z2::Point Point;
84  typedef Point::Coordinate Coordinate;
85  typedef HyperRectDomain< Z2 > DomainType;
86  Point p1( -449, -449 );
87  Point p2( 449, 449 );
88  DomainType domain( p1, p2 );
89 
90  // typedef DomainMetricAdjacency< DomainType, 1 > Adj4;
91  // typedef DomainMetricAdjacency< DomainType, 2 > Adj8;
92  typedef MetricAdjacency< Z2, 1 > MetricAdj4;
93  typedef MetricAdjacency< Z2, 2 > MetricAdj8;
96  typedef DigitalTopology< Adj4, Adj8 > DT48;
98  MediumSet;
99 // typedef DigitalSetSelector< DomainType, SMALL_DS >::Type
100 // MediumSet;
101  typedef Object<DT48, MediumSet> ObjectType;
102  typedef ObjectType::SmallSet SmallSet;
103  typedef Object<DT48, SmallSet> SmallObjectType;
104  typedef ObjectType::Size Size;
105 
106  // Adj4 adj4( domain );
107  // Adj8 adj8( domain );
108  MetricAdj4 madj4;
109  MetricAdj8 madj8;
110  Adj4 adj4( domain, madj4 );
111  Adj8 adj8( domain, madj8 );
112  DT48 dt48( adj4, adj8, JORDAN_DT );
113 
114  Coordinate r = 49;
115  double radius = (double) (r+1);
116  Point c( 0, 0 );
117  Point l( r, 0 );
118  MediumSet disk( domain );
119  ostringstream sstr;
120  sstr << "Creating disk( r < " << radius << " ) ...";
121  trace.beginBlock ( sstr.str() );
122  for ( DomainType::ConstIterator it = domain.begin();
123  it != domain.end();
124  ++it )
125  {
126  if ( (*it - c ).norm() < radius ) // 450.0
127  // insertNew is very important for vector container.
128  disk.insertNew( *it );
129  }
130  trace.endBlock();
131 
132  trace.beginBlock ( "Testing Object instanciation and smart copy ..." );
133  ObjectType disk_object( dt48, disk );
134  nbok += disk_object.size() == 7825 ? 1 : 0;
135  nb++;
136  trace.info() << "(" << nbok << "/" << nb << ") "
137  << "Disk (r=450.0) " << disk_object << std::endl;
138  trace.info() << " size=" << disk_object.size() << std::endl;
139  ObjectType disk_object2( disk_object );
140  nbok += disk_object2.size() == 7825 ? 1 : 0;
141  nb++;
142  trace.info() << "(" << nbok << "/" << nb << ") "
143  << "Disk2 (r=450.0) " << disk_object2 << std::endl;
144  trace.info() << " size=" << disk_object2.size() << std::endl;
145  trace.endBlock();
146 
147  trace.beginBlock ( "Testing copy on write system ..." );
148  trace.info() << "Removing center point in Disk." << std::endl;
149  disk_object.pointSet().erase( c );
150  disk_object2.pointSet().insert( c );
151  nbok += disk_object.size() == 7824 ? 1 : 0;
152  nb++;
153  trace.info() << "(" << nbok << "/" << nb << ") "
154  << "Disk - c (r=450.0) " << disk_object << std::endl;
155  trace.info() << " size=" << disk_object.size() << std::endl;
156  nbok += disk_object2.size() == 7825 ? 1 : 0;
157  nb++;
158  trace.info() << "(" << nbok << "/" << nb << ") "
159  << "Disk2 + c (r=450.0) " << disk_object2 << std::endl;
160  trace.info() << " size=" << disk_object2.size() << std::endl;
161  trace.endBlock();
162 
163  trace.beginBlock ( "Testing neighborhoods ..." );
164  Object<DT48, SmallSet> neigh = disk_object.neighborhood( c );
165  nbok += neigh.size() == 4 ? 1 : 0;
166  nb++;
167  trace.info() << "(" << nbok << "/" << nb << ") "
168  << "N_4(Disk, c).size() = " << neigh.size()
169  << " == 4" << std::endl;
170  neigh = disk_object.properNeighborhood( l );
171  nbok += neigh.size() == 3 ? 1 : 0;
172  nb++;
173  trace.info() << "(" << nbok << "/" << nb << ") "
174  << "N*_4(Disk, " << l << ").size() = " << neigh.size()
175  << " == 3" << std::endl;
176  Size size = disk_object.properNeighborhoodSize( l );
177  nbok += size == 3 ? 1 : 0;
178  nb++;
179  trace.info() << "(" << nbok << "/" << nb << ") "
180  << "#N*_4(Disk, " << l << ") = " << size
181  << " == 3" << std::endl;
182 
183  neigh = disk_object2.neighborhood( c );
184  nbok += neigh.size() == 5 ? 1 : 0;
185  nb++;
186  trace.info() << "(" << nbok << "/" << nb << ") "
187  << "N_4(Disk2, c).size() = " << neigh.size()
188  << " == 5" << std::endl;
189  trace.endBlock();
190 
191  trace.beginBlock ( "Testing set converters ..." );
193  ( neigh.pointSet(), disk_object.pointSet() );
194  nbok += neigh.size() == 7824 ? 1 : 0;
195  nb++;
196  trace.info() << "(" << nbok << "/" << nb << ") "
197  << "neigh = disk_object, size() = " << neigh.size()
198  << " == 636100" << std::endl;
199  SmallObjectType neigh2 = disk_object2.neighborhood( c );
201  ( neigh.pointSet(), neigh2.pointSet() );
202  nbok += neigh.size() == 5 ? 1 : 0;
203  nb++;
204  trace.info() << "(" << nbok << "/" << nb << ") "
205  << "neigh = N_4(Disk2, c), size() = " << neigh.size()
206  << " == 5" << std::endl;
207  trace.endBlock();
208 
209  trace.beginBlock ( "Testing border extraction ..." );
210  ObjectType bdisk = disk_object.border();
211  nbok += bdisk.size() == 400 ? 1 : 0;
212  nb++;
213  trace.info() << "(" << nbok << "/" << nb << ") "
214  << "Border(Disk, c), size() = " << bdisk.size()
215  << " == 3372" << std::endl;
216  ObjectType bdisk2 = disk_object2.border();
217  nbok += bdisk2.size() == 392 ? 1 : 0;
218  nb++;
219  trace.info() << "(" << nbok << "/" << nb << ") "
220  << "Border(Disk2, c), size() = " << bdisk2.size()
221  << " == 3364" << std::endl;
222  trace.endBlock();
223 
224  trace.beginBlock ( "Testing expansion by layers on the boundary ..." );
225  typedef Expander< ObjectType > ObjectExpander;
226  ObjectExpander expander( bdisk, *(bdisk.pointSet().begin()) );
227  while ( ! expander.finished() )
228  {
229  nbok += expander.layer().size() <= 2 ? 1 : 0;
230  nb++;
231  trace.info() << "(" << nbok << "/" << nb << ") "
232  << "expander.layer.size() <= 2 "
233  << expander << std::endl;
234  expander.nextLayer();
235  }
236  trace.endBlock();
237 
238  trace.beginBlock ( "Testing expansion by layers on the disk from center..." );
239  ObjectExpander expander2( disk_object2, c );
240  while ( ! expander2.finished() )
241  {
242  trace.info() << expander2 << std::endl;
243  expander2.nextLayer();
244  }
245  nbok += expander2.distance() <= sqrt(2.0)*radius ? 1 : 0;
246  nb++;
247  trace.info() << "(" << nbok << "/" << nb << ") "
248  << "expander.distance() = " << expander2.distance()
249  << " <= " << sqrt(2.0)*radius << std::endl;
250  trace.endBlock();
251 
252  return nbok == nb;
253 }
254 
259 bool testObject3D()
260 {
261  unsigned int nbok = 0;
262  unsigned int nb = 0;
263  typedef SpaceND< 3 > Z3;
267  typedef Z3::Point Point;
268  typedef HyperRectDomain< Z3 > Domain;
269  typedef Domain::ConstIterator DomainConstIterator;
271  typedef Object<DT6_18, DigitalSet> ObjectType;
272  Adj6 adj6;
273  Adj18 adj18;
274  DT6_18 dt6_18( adj6, adj18, JORDAN_DT );
275 
276  Point p1( -50, -50, -50 );
277  Point p2( 50, 50, 50 );
278  Domain domain( p1, p2 );
279  Point c( 0, 0, 0 );
280  Point d( 5, 2, 0 );
281 
282  trace.beginBlock ( "Testing 3D Object instanciation and smart copy ..." );
283  trace.info() << "Creating diamond (r=15)" << endl;
284  // diamond of radius 30
285  DigitalSet diamond_set( domain );
286  for ( DomainConstIterator it = domain.begin(); it != domain.end(); ++it )
287  {
288  if ( (*it - c ).norm1() <= 15 ) diamond_set.insertNew( *it );
289  }
290  ObjectType diamond( dt6_18, diamond_set );
291  trace.info() << "Cloning diamond" << endl;
292  // The following line takes almost no time.
293  ObjectType diamond_clone( diamond );
294  // Since one of the objects is modified, the set is duplicated at the following line
295  trace.info() << "Removing two points " << c << " and " << d << endl;
296  diamond_clone.pointSet().erase( c );
297  diamond_clone.pointSet().erase( d );
298 
299  trace.info() << "Inserting into vector<Object>" << endl;
300  vector<ObjectType> objects;
301  back_insert_iterator< vector< ObjectType > > inserter( objects );
302  *inserter++ = diamond;
303  *inserter++ = diamond_clone;
304 
305  for ( vector<ObjectType>::const_iterator it = objects.begin();
306  it != objects.end();
307  ++it )
308  trace.info() << "- objects[" << (it - objects.begin() ) << "]"
309  << " = " << *it << endl;
310 
311  INBLOCK_TEST( objects[ 0 ].size() == ( objects[ 1 ].size() + 2 ) );
312  INBLOCK_TEST( objects[ 0 ].size() == 4991 );
313  trace.endBlock();
314 
315  trace.beginBlock ( "Testing connected component extraction ..." );
316  // JOL: do like this for output iterators pointing on the same
317  // container as 'this'. Works fine and nearly as fast.
318  //
319  // ObjectType( objects[ 0 ] ).writeComponents( inserter );
320 
321  trace.beginBlock ( "Components of diamond.border() ..." );
322  vector<ObjectType> objects2;
323  back_insert_iterator< vector< ObjectType > > inserter2( objects2 );
324  unsigned int nbc0 = objects[ 0 ].border().writeComponents( inserter2 );
325  INBLOCK_TEST( nbc0 == 1 );
326  INBLOCK_TEST( objects[ 0 ].computeConnectedness() == CONNECTED );
327  trace.endBlock();
328 
329  trace.beginBlock ( "Components of diamond_clone.border() ..." );
330  unsigned int nbc1 = objects[ 1 ].border().writeComponents( inserter2 );
331  INBLOCK_TEST( nbc1 == 3 );
332  trace.endBlock();
333  for ( vector<ObjectType>::const_iterator it = objects2.begin();
334  it != objects2.end();
335  ++it )
336  trace.info() << "- objects2[" << (it - objects2.begin() ) << "]"
337  << " = " << *it << endl;
338  INBLOCK_TEST( objects2[ 0 ].size() == objects2[ 1 ].size() );
339  INBLOCK_TEST( objects2[ 2 ].size() == objects2[ 3 ].size() );
340  INBLOCK_TEST( objects2[ 0 ].size() == 1688 );
341  INBLOCK_TEST( objects2[ 2 ].size() == 18 );
342 
343  trace.endBlock();
344 
345  return nbok == nb;
346 
347 }
348 
353 bool testSimplePoints3D()
354 {
355  unsigned int nbok = 0;
356  unsigned int nb = 0;
357  typedef SpaceND< 3 > Z3;
358  typedef MetricAdjacency< Z3, 1 > Adj6;
359  typedef MetricAdjacency< Z3, 2 > Adj18;
360  typedef DigitalTopology< Adj6, Adj18 > DT6_18;
361  typedef Z3::Point Point;
362  typedef HyperRectDomain< Z3 > Domain;
363  typedef Domain::ConstIterator DomainConstIterator;
365  typedef Object<DT6_18, DigitalSet> ObjectType;
366  typedef Object<DT6_18, DigitalSet>::SmallObject SmallObjectType;
367  typedef Object<DT6_18, DigitalSet>::SmallComplementObject SmallComplementObjectType;
368  Adj6 adj6;
369  Adj18 adj18;
370  DT6_18 dt6_18( adj6, adj18, JORDAN_DT );
371 
372  Point p1( -10, -10, -10 );
373  Point p2( 10, 10, 10 );
374  Domain domain( p1, p2 );
375  Point c( 0, 0, 0 );
376  Point r( 3, 0, 0 );
377 
378  trace.beginBlock ( "Creating Diamond (r=4)" );
379  // diamond of radius 4
380  DigitalSet diamond_set( domain );
381  for ( DomainConstIterator it = domain.begin(); it != domain.end(); ++it )
382  {
383  if ( (*it - c ).norm1() <= 3 ) diamond_set.insertNew( *it );
384  }
385  diamond_set.erase( c );
386  ObjectType diamond( dt6_18, diamond_set );
387  trace.endBlock();
388 
389  trace.beginBlock ( "Geodesic neighborhoods ..." );
390  SmallObjectType geoN6_3 = diamond.geodesicNeighborhood( adj6, r, 3 );
391  SmallObjectType geoN18_2 = diamond.geodesicNeighborhood( adj18, r, 2 );
392  trace.info() << "geoN6_3 = " << geoN6_3 << endl;
393  trace.info() << "geoN18_2 = " << geoN18_2 << endl;
394  SmallComplementObjectType cgeoN6_3 = diamond.geodesicNeighborhoodInComplement( adj6, r, 3 );
395  SmallComplementObjectType cgeoN18_2 = diamond.geodesicNeighborhoodInComplement( adj18, r, 2 );
396  trace.info() << "cgeoN6_3 = " << cgeoN6_3 << endl;
397  trace.info() << "cgeoN18_2 = " << cgeoN18_2 << endl;
398  trace.endBlock();
399 
400  trace.beginBlock ( "Simple points ..." );
401  for ( DigitalSet::ConstIterator it = diamond.pointSet().begin();
402  it != diamond.pointSet().end();
403  ++it )
404  trace.info() << "- " << *it
405  << " " << ( diamond.isSimple( *it ) ? "Simple" : "Not simple" )
406  << endl;
407  trace.endBlock();
408 
409 
410  return nbok == nb;
411 }
412 
413 
414 bool testDraw()
415 {
416  unsigned int nbok = 0;
417  unsigned int nb = 0;
418 
419  trace.beginBlock ( "testDraw(): testing drawing commands." );
420 
421  typedef SpaceND< 2 > Z2;
422  typedef Z2::Point Point;
423  typedef Point::Coordinate Coordinate;
424  typedef HyperRectDomain< Z2 > DomainType;
425  Point p1( -10, -10 );
426  Point p2( 10, 10 );
427  DomainType domain( p1, p2 );
428 
429  // typedef DomainMetricAdjacency< DomainType, 1 > Adj4;
430  // typedef DomainMetricAdjacency< DomainType, 2 > Adj8;
431  typedef MetricAdjacency< Z2, 1 > MetricAdj4;
432  typedef MetricAdjacency< Z2, 2 > MetricAdj8;
435  typedef DigitalTopology< Adj4, Adj8 > DT48;
436  typedef DigitalTopology< Adj8, Adj4 > DT84;
438  MediumSet;
439 // typedef DigitalSetSelector< DomainType, SMALL_DS >::Type
440 // MediumSet;
441  typedef Object<DT48, MediumSet> ObjectType;
442  typedef Object<DT84, MediumSet> ObjectType84;
443 
444  typedef ObjectType::SmallSet SmallSet;
445  typedef Object<DT48, SmallSet> SmallObjectType;
446  typedef ObjectType::Size Size;
447 
448  // Adj4 adj4( domain );
449  // Adj8 adj8( domain );
450  MetricAdj4 madj4;
451  MetricAdj8 madj8;
452  Adj4 adj4( domain, madj4 );
453  Adj8 adj8( domain, madj8 );
454  DT48 dt48( adj4, adj8, JORDAN_DT );
455  DT84 dt84( adj8, adj4, JORDAN_DT );
456 
457  Coordinate r = 5;
458  double radius = (double) (r+1);
459  Point c( 0, 0 );
460  Point l( r, 0 );
461  MediumSet disk( domain );
462  ostringstream sstr;
463  sstr << "Creating disk( r < " << radius << " ) ...";
464  trace.beginBlock ( sstr.str() );
465  for ( DomainType::ConstIterator it = domain.begin();
466  it != domain.end();
467  ++it )
468  {
469  if ( (*it - c ).norm() < radius ) // 450.0
470  // insertNew is very important for vector container.
471  disk.insertNew( *it );
472  }
473  trace.endBlock();
474 
475  trace.beginBlock ( "Testing Object instanciation and smart copy ..." );
476  ObjectType disk_object( dt48, disk );
477  ObjectType84 disk_object2( dt84, disk );
478  trace.endBlock();
479 
480  trace.beginBlock ( "Testing export as SVG with libboard." );
481 
482  Board2D board;
483  board.setUnit(Board::UCentimeter);
484 
485  board << SetMode( domain.className(), "Grid" ) << domain;
486  board << disk_object;
487 
488  board.saveSVG("disk-object.svg");
489 
490  Board2D board2;
491  board2.setUnit(Board::UCentimeter);
492 
493  board2 << SetMode( domain.className(), "Grid" ) << domain;
494  board2 << SetMode( disk_object.className(), "DrawAdjacencies" ) << disk_object;
495 
496  board2.saveSVG("disk-object-adj.svg");
497 
498  Board2D board3;
499  board3.setUnit(Board::UCentimeter);
500 
501  board3 << SetMode( domain.className(), "Grid" ) << domain;
502  board3 << SetMode( disk_object2.className(), "DrawAdjacencies" ) << disk_object2;
503 
504  board3.saveSVG("disk-object-adj-bis.svg");
505  trace.endBlock();
506 
507  trace.endBlock();
508 
509  return nbok == nb;
510 
511 }
512 
514 {
515  virtual void setStyle(Board2D & aboard) const
516  {
517  aboard.setFillColor( Color::Red);
518  aboard.setPenColorRGBi(200,0,0);
520  aboard.setLineWidth( 2 );
521  }
522 };
523 
525 {
528  : myColor( c )
529  {}
530  virtual void setStyle(Board2D & aboard) const
531  {
532  aboard.setFillColor( myColor );
533  aboard.setPenColorRGBi( 0, 0, 0 );
535  aboard.setLineWidth( 1.0 );
536  }
537 };
538 
539 using namespace DGtal::Z2i;
540 
545 bool testSimplePoints2D()
546 {
547  unsigned int nbok = 0;
548  unsigned int nb = 0;
549  typedef DGtal::Z2i::Point Point;
550  typedef Domain::ConstIterator DomainConstIterator;
551 
552  Point p1( -17, -17 );
553  Point p2( 17, 17 );
554  Domain domain( p1, p2 );
555  DigitalSet shape_set( domain );
556  Shapes<Domain>::addNorm1Ball( shape_set, Point( -10, -8 ), 7 );
557  Shapes<Domain>::addNorm1Ball( shape_set, Point( 10, 8 ), 7 );
558  Shapes<Domain>::addNorm1Ball( shape_set, Point( 3, 0 ), 6 );
559  Shapes<Domain>::addNorm1Ball( shape_set, Point( 0, -3 ), 7 );
560  Shapes<Domain>::addNorm1Ball( shape_set, Point( -10, 0 ), 6 );
561  Shapes<Domain>::addNorm1Ball( shape_set, Point( -8, 8 ), 6 );
562  Shapes<Domain>::addNorm1Ball( shape_set, Point( 0, 9 ), 6 );
563  Shapes<Domain>::addNorm1Ball( shape_set, Point( 15, -2 ), 6 );
564  Shapes<Domain>::addNorm1Ball( shape_set, Point( 12, -10 ), 4 );
565  shape_set.erase( Point( 5, 0 ) );
566  shape_set.erase( Point( -1, -2 ) );
567  Object4_8 shape( dt4_8, shape_set );
568  Object8_4 shape2( dt8_4, shape_set );
569 
570  GradientColorMap<int> cmap_grad( 0, 6 );
571  cmap_grad.addColor( Color( 128, 128, 255 ) );
572  cmap_grad.addColor( Color( 255, 255, 128 ) );
573  //cmap_grad.addColor( Color( 220, 130, 25 ) );
574  Board2D board;
575  board.setUnit(Board::UCentimeter);
576  board << SetMode( domain.className(), "Paving" )
577  << domain;
578  Board2D board2;
579  board2.setUnit(Board::UCentimeter);
580  board2 << SetMode( domain.className(), "Grid" )
581  << domain;
582 
583  // Greedy thinning.
584  DGtal::uint64_t nb_simple;
585  trace.beginBlock ( "Greedy homotopic thinning ..." );
586  int layer = 0;
587  do
588  {
589  DigitalSet & S = shape.pointSet();
590  std::queue<DigitalSet::Iterator> Q;
591  for ( DigitalSet::Iterator it = S.begin(); it != S.end(); ++it )
592  if ( shape.isSimple( *it ) )
593  Q.push( it );
594  nb_simple = 0;
595  while ( ! Q.empty() )
596  {
597  DigitalSet::Iterator it = Q.front();
598  Q.pop();
599  if ( shape.isSimple( *it ) )
600  {
601  board << CustomStyle( it->className(),
603  ( cmap_grad( layer ) ) )
604  << *it;
605  S.erase( *it );
606  ++nb_simple;
607  }
608  }
609  ++layer;
610  }
611  while ( nb_simple != 0 );
612  trace.endBlock();
613 
614  // Greedy thinning.
615  trace.beginBlock ( "Greedy homotopic thinning ..." );
616  layer = 0;
617  do
618  {
619  DigitalSet & S = shape2.pointSet();
620  std::queue<DigitalSet::Iterator> Q;
621  for ( DigitalSet::Iterator it = S.begin(); it != S.end(); ++it )
622  if ( shape2.isSimple( *it ) )
623  Q.push( it );
624  nb_simple = 0;
625  while ( ! Q.empty() )
626  {
627  DigitalSet::Iterator it = Q.front();
628  Q.pop();
629  if ( shape2.isSimple( *it ) )
630  {
631  board2 << CustomStyle( it->className(),
633  ( cmap_grad( layer ) ) )
634  << *it;
635  S.erase( *it );
636  ++nb_simple;
637  }
638  }
639  ++layer;
640  }
641  while ( nb_simple != 0 );
642  trace.endBlock();
643 
644  board << CustomStyle( shape.className(), new MyDrawStyleCustomRed )
645  << shape;
646  board.saveSVG( "shape-thinning-4-8.svg");
647  board.clear();
648 
649  board2 << CustomStyle( shape2.className(), new MyDrawStyleCustomRed )
650  << shape2;
651  board2.saveSVG( "shape-thinning-8-4.svg");
652  board2.clear();
653 
654  return nbok == nb;
655 }
656 
657 
658 
659 
661 // Standard services - public :
662 
663 int main( int argc, char** argv )
664 {
665  trace.beginBlock ( "Testing class Object" );
666  trace.info() << "Args:";
667  for ( int i = 0; i < argc; ++i )
668  trace.info() << " " << argv[ i ];
669  trace.info() << endl;
670 
671  bool res = testObject() &&
672  testObject3D() && testDraw()
673  && testSimplePoints3D()
674  && testSimplePoints2D();
675 
676  trace.emphase() << ( res ? "Passed." : "Error." ) << endl;
677  trace.endBlock();
678  return res ? 0 : 1;
679 }
680 // //