DGtalTools  1.5.beta
3dImplicitSurfaceExtractorByThickening.cpp
1 
32 #include <iostream>
33 #include <map>
34 #include "CLI11.hpp"
35 
36 #include "DGtal/base/Common.h"
37 #include "DGtal/base/CountedPtr.h"
38 #include "DGtal/helpers/StdDefs.h"
39 #include "DGtal/math/MPolynomial.h"
40 #include "DGtal/io/readers/MPolynomialReader.h"
41 #include "DGtal/io/DrawWithDisplay3DModifier.h"
42 #include "DGtal/io/viewers/Viewer3D.h"
43 #include "DGtal/topology/KhalimskySpaceND.h"
44 #include "DGtal/topology/CubicalComplex.h"
45 #include "DGtal/topology/CubicalComplexFunctions.h"
46 #include "DGtal/topology/SetOfSurfels.h"
47 #include "DGtal/topology/DigitalSurface.h"
48 #include "DGtal/topology/helpers/Surfaces.h"
49 #include "DGtal/shapes/GaussDigitizer.h"
50 #include "DGtal/shapes/Mesh.h"
51 #include "DGtal/io/boards/Board3D.h"
52 #include "DGtal/shapes/implicit/ImplicitPolynomial3Shape.h"
54 
55 using namespace std;
56 using namespace DGtal;
57 
58 
59 
119 template <typename CellOutputIterator, typename DigitalSurface>
120 void
121 analyzeSurface( CellOutputIterator itSure, CellOutputIterator itUnsure, DigitalSurface surface )
122 {
123  typedef typename DigitalSurface::KSpace KSpace;
124  typedef typename DigitalSurface::Surfel Surfel;
125  typedef typename DigitalSurface::ConstIterator ConstIterator;
126  typedef typename DigitalSurface::DigitalSurfaceContainer Container;
127  typedef typename DigitalSurface::DigitalSurfaceTracker Tracker;
128  typedef typename KSpace::Integer Integer;
129  typedef typename KSpace::Cell Cell;
130  const Dimension t = KSpace::dimension - 1;
131  const Container& C = surface.container();
132  const KSpace& K = surface.container().space();
133  Surfel s2;
134  for ( ConstIterator it = surface.begin(), itE = surface.end(); it != itE; ++it )
135  {
136  Surfel s = *it;
137  Cell is = K.unsigns( s );
138  Integer s_xt = K.sKCoord( s, t );
139  if ( s_xt == 0 ) *itUnsure++ = is;
140  else if ( s_xt == -1 )
141  {
142  CountedPtr<Tracker> tracker( C.newTracker( s ) );
143  if ( tracker->adjacent( s2, t, true ) != 0 )
144  {
145  Integer s2_xt = K.sKCoord( s2, t );
146  Cell ic = K.uIncident( is, t, true );
147  if ( s2_xt > 0 ) *itSure++ = ic;
148  else *itUnsure++ = ic;
149  }
150  }
151  else if ( s_xt == 1 )
152  {
153  CountedPtr<Tracker> tracker( C.newTracker( s ) );
154  if ( tracker->adjacent( s2, t, false ) != 0 )
155  {
156  Integer s2_xt = K.sKCoord( s2, t );
157  Cell ic = K.uIncident( is, t, false );
158  if ( s2_xt < 0 ) *itSure++ = ic;
159  else *itUnsure++ = ic;
160  }
161  }
162  else cout << " " << s_xt;
163  }
164 }
165 
174 template <typename ImplicitSurface, typename RealPoint>
175 RealPoint projectNewton( const ImplicitSurface & is,
176  RealPoint x,
177  typename RealPoint::Coordinate epsilon,
178  unsigned int max_iter )
179 {
180  typedef typename RealPoint::Coordinate Scalar;
181  RealPoint gx;
182  Scalar f, g2;
183  Scalar eps2 = epsilon * epsilon;
184  while ( max_iter-- != 0 )
185  {
186  f = is( x );
187  if ( abs( f ) < epsilon ) return x;
188  gx = is.gradient( x );
189  g2 = gx.dot( gx );
190  if ( g2 < eps2 ) return x;
191  x -= (f/g2) * gx;
192  }
193  return x;
194 }
195 
196 
197 template <typename CubicalComplex3, typename ImplicitShape3,
198  typename ImplicitDigitalShape3>
199 void projectComplex( std::vector< typename ImplicitShape3::RealPoint >& points,
200  const CubicalComplex3& complex3,
201  const ImplicitShape3& shape,
202  const ImplicitDigitalShape3& dshape,
203  double epsilon,
204  unsigned int max_iter,
205  double max_distance )
206 {
207  typedef typename CubicalComplex3::Cell Cell3;
208  typedef typename CubicalComplex3::Point Point3;
209  typedef typename CubicalComplex3::CellMapConstIterator CellMapConstIterator;
210  typedef typename ImplicitShape3::RealPoint RealPoint3;
211  typedef typename ImplicitShape3::Ring Ring;
212  points.clear();
213  for ( CellMapConstIterator it = complex3.begin( 0 ), itE = complex3.end( 0 ); it != itE; ++it )
214  {
215  Cell3 cell = it->first;
216  Point3 dp = complex3.space().uKCoords( cell ) - Point3::diagonal( 1 );
217  RealPoint3 p = dshape->embed( dp ) / 2.0;
218  RealPoint3 q = projectNewton( shape, p, epsilon, max_iter );
219  double d = (p-q).norm();
220  if ( d > max_distance ) q = p + (q-p)*( max_distance / d );
221  points.push_back( q );
222  }
223 }
224 
225 template <typename CubicalComplex3, typename ImplicitShape3,
226  typename ImplicitDigitalShape3>
227 typename ImplicitShape3::Ring
228 getValue( const CubicalComplex3& complex3,
229  const typename CubicalComplex3::Cell& cell,
230  const ImplicitShape3& shape,
231  const ImplicitDigitalShape3& dshape )
232 {
233  typedef typename CubicalComplex3::Cell Cell3;
234  typedef typename CubicalComplex3::Cells Cells3;
235  typedef typename CubicalComplex3::Point Point3;
236  typedef typename ImplicitShape3::RealPoint RealPoint3;
237  typedef typename ImplicitShape3::Ring Ring;
238 
239  Point3 dp = complex3.space().uKCoords( cell ) - Point3::diagonal( 1 );
240  RealPoint3 p = dshape->embed( dp ) / 2.0;
241  Ring v = shape( p );
242  return v;
243 }
244 
245 
246 template <typename CubicalComplex3, typename ImplicitShape3,
247  typename ImplicitDigitalShape3>
248 void doNotProjectComplex( std::vector< typename ImplicitShape3::RealPoint >& points,
249  const CubicalComplex3& complex3,
250  const ImplicitShape3& shape,
251  const ImplicitDigitalShape3& dshape )
252 {
253  typedef typename CubicalComplex3::Cell Cell3;
254  typedef typename CubicalComplex3::Point Point3;
255  typedef typename CubicalComplex3::CellMapConstIterator CellMapConstIterator;
256  typedef typename ImplicitShape3::RealPoint RealPoint3;
257  typedef typename ImplicitShape3::Ring Ring;
258  points.clear();
259  for ( CellMapConstIterator it = complex3.begin( 0 ), itE = complex3.end( 0 ); it != itE; ++it )
260  {
261  Cell3 cell = it->first;
262  Point3 dp = complex3.space().uKCoords( cell );
263  RealPoint3 p = dshape->embed( dp ) / 2.0;
264  points.push_back( p );
265  }
266 }
267 
268 
269 
270 int main( int argc, char** argv )
271 {
272  typedef int Integer;
273  typedef SpaceND<3,Integer> Space3;
274  typedef KhalimskySpaceND<3,Integer> KSpace3;
275  typedef KSpace3::Cell Cell3;
276  typedef std::map<Cell3, CubicalCellData> Map3;
277  // typedef boost::unordered_map<Cell3, CubicalCellData> Map3;
279  typedef Space3::Point Point3;
280  typedef Space3::RealPoint RealPoint3;
281  typedef Space3::RealVector RealVector3;
282  typedef RealPoint3::Coordinate Ring;
283  typedef Ring Scalar;
284  typedef MPolynomial<3, Ring> Polynomial3;
285  typedef MPolynomialReader<3, Ring> Polynomial3Reader;
286  typedef ImplicitPolynomial3Shape<Space3> ImplicitShape3;
288  ImplicitDigitalShape3;
289  typedef ImplicitDigitalShape3::Domain Domain3;
290  typedef CC3::CellMapIterator CellMapIterator;
291  typedef CC3::CellMapConstIterator CellMapConstIterator;
292  typedef CC3::Cells Cells3;
293 
294  // parse command line using CLI ----------------------------------------------
295  CLI::App app;
296  string poly_str;
297  std::string outputFileName {"result.raw"};
298  DGtal::int64_t rescaleInputMin {0};
299  DGtal::int64_t rescaleInputMax {255};
300  Ring min_x {-10.0};
301  Ring max_x {10.0};
302  Ring h {1.0};
303  Ring t {1e-2};
304  std::string project {"Newton"};
305  double epsilon {1e-6};
306  unsigned int max_iter {500};
307  std::string view {"Normal"};
308  std::string OBJexport="";
309 
310  app.description( "Computes the zero level set of the given polynomial. Usage: 3dImplicitSurfaceExtractorByThickening -p <polynomial> [options]\n Example:\n 3dImplicitSurfaceExtractorByThickening -p \"x^2-y*z^2\" -g 0.1 -a -2 -A 2 -v Singular\n - whitney : x^2-y*z^2 \n - 4lines : x*y*(y-x)*(y-z*x) \n - cone : z^2-x^2-y^2 \n - simonU : x^2-z*y^2+x^4+y^4 \n - cayley3 : 4*(x^2 + y^2 + z^2) + 16*x*y*z - 1 \n - crixxi : -0.9*(y^2+z^2-1)^2-(x^2+y^2-1)^3 \n Some other examples (more difficult): \n 3dImplicitSurfaceExtractorByThickening -a -2 -A 2 -p \"((y^2+z^2-1)^2-(x^2+y^2-1)^3)*(y*(x-1)^2-z*(x+1))^2\" -g 0.025 -e 1e-6 -n 50000 -v Singular -t 0.5 -P Newton \n 3dImplicitSurfaceExtractorByThickening -a -2 -A 2 -p \"(x^5-4*z^3*y^2)*((x+y)^2-(z-x)^3)\" -g 0.025 -e 1e-6 -n 50000 -v Singular -t 0.05 -P Newton ");
311  app.add_option("-p,--polynomial,1", poly_str, "the implicit polynomial whose zero-level defines the shape of interest." )
312  ->required();
313  app.add_option("--minAABB,-a",min_x, "the min value of the AABB bounding box (domain)" , true);
314  app.add_option("--maxAABB,-A",max_x, "the max value of the AABB bounding box (domain)" , true);
315  app.add_option("--gridstep,-g", h, "the gridstep that defines the digitization (often called h).", true);
316  app.add_option("--thickness,-t",t, "the thickening parameter for the implicit surface." , true);
317  app.add_option("--project,-P", project, "defines the projection: either No or Newton.", true)
318  -> check(CLI::IsMember({"No", "Newton"}));
319  app.add_option("--epsilon,-e", epsilon, "the maximum precision relative to the implicit surface in the Newton approximation of F=0.", true);
320  app.add_option("--obj,-o", OBJexport, "OBJ export filename.");
321  app.add_option("--max_iter,-n", max_iter, "the maximum number of iteration in the Newton approximation of F=0.", true );
322  app.add_option("--view,-v", view, "specifies if the surface is viewed as is (Normal) or if places close to singularities are highlighted (Singular), or if unsure places should not be displayed (Hide).",true )
323  -> check(CLI::IsMember({"Singular", "Normal", "Hide"}));
324 
325  app.get_formatter()->column_width(40);
326  CLI11_PARSE(app, argc, argv);
327  // END parse command line using CLI ----------------------------------------------
328 
329 
330  //-------------- read polynomial and creating 3d implicit fct -----------------
331  trace.beginBlock( "Reading polynomial and creating 3D implicit function" );
332  Polynomial3 poly;
333  Polynomial3Reader reader;
334  string::const_iterator iter = reader.read( poly, poly_str.begin(), poly_str.end() );
335  if ( iter != poly_str.end() )
336  {
337  trace.error() << "ERROR reading polynomial: I read only <" << poly_str.substr( 0, iter - poly_str.begin() )
338  << ">, and I built P=" << poly << std::endl;
339  return 2;
340  }
341  // Creating implicit shape and storing it with smart pointer for automatic deallocation.
342  CountedPtr<ImplicitShape3> shape( new ImplicitShape3( poly ) );
343 
344  RealPoint3 p1( min_x, min_x, min_x );
345  RealPoint3 p2( max_x, max_x, max_x );
346  // Creating digitized shape and storing it with smart pointer for automatic deallocation.
347  CountedPtr<ImplicitDigitalShape3> dshape( new ImplicitDigitalShape3() );
348  dshape->attach( *shape );
349  dshape->init( p1, p2, RealVector3( h, h, h ) );
350  Domain3 domain3 = dshape->getDomain();
351  KSpace3 K3;
352  K3.init( domain3.lowerBound(), domain3.upperBound(), true );
353  trace.info() << "- domain is " << domain3 << std::endl;
354  trace.endBlock();
355 
356  //-------------- read polynomial and creating 3d implicit fct -----------------
357  trace.beginBlock( "Extracting thickened isosurface [-t,+t] of 3D polynomial. " );
358  CubicalCellData unsure_data( 0 );
359  CubicalCellData sure_data( CC3::FIXED );
360  CC3 complex3( K3 );
361  for ( Domain3::ConstIterator it = domain3.begin(), itE = domain3.end(); it != itE; ++it )
362  {
363  Cell3 spel = K3.uSpel( *it );
364  // RealPoint3 px = dshape->embed( *it );
365  RealPoint3 px = dshape->embed( K3.uKCoords( spel ) - Point3::diagonal( 1 ) ) / 2.0;
366  Ring s = (*shape)( px );
367  if ( (-t <= s ) && ( s <= t ) ) complex3.insertCell( spel, unsure_data );
368  }
369  trace.info() << "- K[-t,+t] = " << complex3 << endl;
370  complex3.close();
371  trace.info() << "- Cl K[-t,+t] = " << complex3 << endl;
372  std::vector<Cell3> separating_cells;
373  std::back_insert_iterator< std::vector<Cell3> > outItSurface( separating_cells );
374  Surfaces<KSpace3>::uWriteBoundary( outItSurface,
375  K3, *dshape, domain3.lowerBound(), domain3.upperBound() );
376  trace.info() << "- separating S = " << separating_cells.size() << " 2-cells." << endl;
377  complex3.insertCells( separating_cells.begin(), separating_cells.end(), sure_data );
378  for ( std::vector<Cell3>::const_iterator it = separating_cells.begin(), itE = separating_cells.end(); it != itE; ++it )
379  {
380  Cells3 bdry = K3.uFaces( *it );
381  for ( Cells3::const_iterator itBdry = bdry.begin(), itBdryE = bdry.end(); itBdry != itBdryE; ++itBdry )
382  complex3.insertCell( *itBdry, sure_data );
383  }
384  separating_cells.clear();
385  trace.info() << "- Cl K[-t,+t] + Cl S = " << complex3 << endl;
386  trace.endBlock();
387 
388  //-------------- Get boundary and inner cells --------------------------------
389  trace.beginBlock( "Get boundary and inner cells. " );
390  std::vector<Cell3> inner;
391  std::vector<Cell3> bdry;
392  functions::filterCellsWithinBounds
393  ( complex3, K3.uKCoords( K3.lowerCell() ), K3.uKCoords( K3.upperCell() ),
394  std::back_inserter( bdry ), std::back_inserter( inner ) );
395  trace.info() << "- there are " << inner.size() << " inner cells." << endl;
396  trace.info() << "- there are " << bdry.size() << " boundary cells." << endl;
397  trace.endBlock();
398 
399  //-------------- Compute priority function -----------------------------------
400  trace.beginBlock( "Compute priority function. " );
401  Dimension d = complex3.dim();
402  for ( Dimension i = 0; i <= d; ++i )
403  {
404  for ( CellMapIterator it = complex3.begin( i ), itE = complex3.end( i ); it != itE; ++it )
405  {
406  Cell3 cell = it->first;
407  Ring v = getValue( complex3, cell, *shape, dshape );
408  v = abs( 10000.0*v );
409  if ( v > 10000000.0 ) v = 10000000.0;
410  it->second.data &= ~CC3::VALUE;
411  it->second.data |= (DGtal::uint32_t) floor( v );
412  // std::cout << " " << it->second.data;
413  }
414  }
415  trace.endBlock();
416 
417  //-------------- Collapse boundary -------------------------------------------
418  trace.beginBlock( "Collapse boundary. " );
419  typename CC3::DefaultCellMapIteratorPriority priority;
420  CC3 bdry_complex3( K3 );
421  for ( std::vector<Cell3>::const_iterator it = bdry.begin(), itE = bdry.end(); it != itE; ++it )
422  {
423  Cell3 cell = *it;
424  Dimension d = K3.uDim( cell );
425  CellMapConstIterator cmIt = complex3.findCell( d, cell );
426  bdry_complex3.insertCell( d, cell, cmIt->second );
427  }
428  trace.info() << "- [before collapse] K_bdry =" << bdry_complex3 << endl;
429  functions::collapse( bdry_complex3, bdry.begin(), bdry.end(), priority, true, true, false );
430  trace.info() << "- [after collapse] K_bdry =" << bdry_complex3 << endl;
431  for ( std::vector<Cell3>::const_iterator it = bdry.begin(), itE = bdry.end(); it != itE; ++it )
432  {
433  Cell3 cell = *it;
434  Dimension d = K3.uDim( cell );
435  CellMapConstIterator cmIt = bdry_complex3.findCell( d, cell );
436  if ( cmIt != bdry_complex3.end( d ) ) {
437  CellMapIterator cmIt2 = complex3.findCell( d, cell );
438  cmIt2->second = sure_data;
439  }
440  }
441  trace.endBlock();
442 
443  //-------------- Collapse all -------------------------------------------
444  trace.beginBlock( "Collapse all. " );
445  std::copy( bdry.begin(), bdry.end(), std::back_inserter( inner ) );
446  functions::collapse( complex3, inner.begin(), inner.end(), priority, true, true, true );
447  trace.info() << "- K = " << complex3 << endl;
448  trace.endBlock();
449 
450  //-------------- Project complex onto surface --------------------------------
451  trace.beginBlock( "Project complex onto surface. " );
452  std::vector<RealPoint3> points;
453  if ( project == "Newton" )
454  projectComplex( points, complex3, *shape, dshape, epsilon, max_iter, h * sqrt(3.0));
455  else
456  doNotProjectComplex( points, complex3, *shape, dshape );
457  trace.endBlock();
458 
459  //-------------- Create Mesh -------------------------------------------
460  trace.beginBlock( "Create Mesh. " );
461  bool highlight = ( view == "Singular" );
462  bool hide = ( view == "Hide" );
463  Mesh<RealPoint3> mesh( true );
464  std::map<Cell3,unsigned int> indices;
465  int idx = 0;
466  for ( CellMapConstIterator it = complex3.begin( 0 ), itE = complex3.end( 0 ); it != itE; ++it, ++idx )
467  {
468  Cell3 cell = it->first;
469  indices[ cell ] = idx;
470  mesh.addVertex( points[ idx ] );
471  }
472  for ( CellMapConstIterator it = complex3.begin( 2 ), itE = complex3.end( 2 ); it != itE; ++it )
473  {
474  Cell3 cell = it->first;
475  bool fixed = it->second.data & CC3::FIXED;
476  Cells3 bdry = complex3.cellBoundary( cell, true );
477  std::vector<unsigned int> face_idx;
478  for ( Cells3::const_iterator itC = bdry.begin(), itCE = bdry.end(); itC != itCE; ++itC )
479  {
480  if ( complex3.dim( *itC ) == 0 )
481  face_idx.push_back( indices[ *itC ] );
482  }
483  if ( ( ! fixed ) && hide ) continue;
484  Color color = highlight
485  ? ( fixed ? Color::White : Color(128,255,128) )
486  : Color::White;
487  RealVector3 diag03 = points[ face_idx[ 0 ] ] - points[ face_idx[ 3 ] ];
488  RealVector3 diag12 = points[ face_idx[ 1 ] ] - points[ face_idx[ 2 ] ];
489  if ( diag03.dot( diag03 ) <= diag12.dot( diag12 ) )
490  {
491  mesh.addTriangularFace( face_idx[ 0 ], face_idx[ 1 ], face_idx[ 3 ], color );
492  mesh.addTriangularFace( face_idx[ 0 ], face_idx[ 3 ], face_idx[ 2 ], color );
493  }
494  else
495  {
496  mesh.addTriangularFace( face_idx[ 0 ], face_idx[ 1 ], face_idx[ 2 ], color );
497  mesh.addTriangularFace( face_idx[ 1 ], face_idx[ 3 ], face_idx[ 2 ], color );
498  }
499  //mesh.addQuadFace( face_idx[ 0 ], face_idx[ 1 ], face_idx[ 3 ], face_idx[ 2 ], color );
500  }
501  trace.endBlock();
502 
503 
504  //-------------- export OBJ -------------------------------------------
505  if (OBJexport != "")
506  {
507  Board3D<Space3,KSpace3> board( K3 );
508  // Display lines that are not in the mesh.
509  board<<mesh;
510  for ( CellMapConstIterator it = complex3.begin( 1 ), itE = complex3.end( 1 ); it != itE; ++it )
511  {
512  Cell3 cell = it->first;
513  bool fixed = it->second.data & CC3::FIXED;
514  std::vector<Cell3> dummy;
515  std::back_insert_iterator< std::vector<Cell3> > outIt( dummy );
516  complex3.directCoFaces( outIt, cell );
517  if ( ! dummy.empty() ) continue;
518 
519  Cells3 bdry = complex3.cellBoundary( cell, true );
520  Cell3 v0 = *(bdry.begin() );
521  Cell3 v1 = *(bdry.begin() + 1);
522  if ( ( ! fixed ) && hide ) continue;
523  Color color = highlight
524  ? ( fixed ? Color::White : Color(128,255,128) )
525  : Color::White;
526  board.setLineColor( color );
527  board.addLine( points[ indices[ v0 ] ], points[ indices[ v1 ] ], h/2.0 );
528  }
529  board.saveOBJ(OBJexport);
530  }
531  //-------------- View surface -------------------------------------------
532  QApplication application(argc,argv);
533  Viewer3D<Space3,KSpace3> viewer( K3 );
534  viewer.setWindowTitle("Implicit surface viewer by thickening");
535  viewer.show();
536  viewer << mesh;
537  // Display lines that are not in the mesh.
538  for ( CellMapConstIterator it = complex3.begin( 1 ), itE = complex3.end( 1 ); it != itE; ++it )
539  {
540  Cell3 cell = it->first;
541  bool fixed = it->second.data & CC3::FIXED;
542  std::vector<Cell3> dummy;
543  std::back_insert_iterator< std::vector<Cell3> > outIt( dummy );
544  complex3.directCoFaces( outIt, cell );
545  if ( ! dummy.empty() ) continue;
546 
547  Cells3 bdry = complex3.cellBoundary( cell, true );
548  Cell3 v0 = *(bdry.begin() );
549  Cell3 v1 = *(bdry.begin() + 1);
550  if ( ( ! fixed ) && hide ) continue;
551  Color color = highlight
552  ? ( fixed ? Color::White : Color(128,255,128) )
553  : Color::White;
554  viewer.setLineColor( color );
555  viewer.addLine( points[ indices[ v0 ] ], points[ indices[ v1 ] ], h/2.0 );
556  }
557  viewer << Viewer3D<Space3,KSpace3>::updateDisplay;
558  return application.exec();
559 }
int main(int argc, char **argv)
ConstIterator end() const
DigitalSurfaceContainer::Surfel Surfel
TDigitalSurfaceContainer DigitalSurfaceContainer
DigitalSurfaceContainer::SurfelConstIterator ConstIterator
ConstIterator begin() const
DigitalSurfaceContainer::DigitalSurfaceTracker DigitalSurfaceTracker
DigitalSurfaceContainer::KSpace KSpace
const DigitalSurfaceContainer & container() const
const Cell & upperCell() const
Cells uFaces(const Cell &c) const
bool init(const Point &lower, const Point &upper, bool isClosed)
Dimension uDim(const Cell &p) const
Integer sKCoord(const SCell &c, Dimension k) const
const Point & uKCoords(const Cell &c) const
Cell unsigns(const SCell &p) const
Cell uIncident(const Cell &c, Dimension k, bool up) const
const Cell & lowerCell() const
Cell uSpel(Point p) const
static const constexpr Dimension dimension
Component Coordinate
Component dot(const Self &v) const
std::ostream & error()
void beginBlock(const std::string &keyword="")
std::ostream & info()
double endBlock()
DGtal::int32_t Integer
T abs(const T &a)
boost::int64_t int64_t
boost::uint32_t uint32_t
Trace trace(traceWriterTerm)
DGtal::uint32_t Dimension