DGtal  0.6.devel
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
DigitalSurface.ih
1 
30 
31 #include <cstdlib>
32 #include <map>
33 #include "DGtal/topology/CVertexPredicate.h"
35 
37 // IMPLEMENTATION of inline methods.
39 
41 // ----------------------- Standard services ------------------------------
42 
43 //-----------------------------------------------------------------------------
44 template <typename TDigitalSurfaceContainer>
45 inline
47 {
48  if ( myTracker != 0 ) delete myTracker;
49 }
50 //-----------------------------------------------------------------------------
51 template <typename TDigitalSurfaceContainer>
52 inline
54 ( const DigitalSurface & other )
55  : myContainer( other.myContainer ),
56  myTracker( new DigitalSurfaceTracker( *other.myTracker ) ),
57  myUmbrellaComputer( other.myUmbrellaComputer )
58 {
59 }
60 //-----------------------------------------------------------------------------
61 template <typename TDigitalSurfaceContainer>
62 inline
64 ( const TDigitalSurfaceContainer & aContainer )
65  : myContainer( new DigitalSurfaceContainer( aContainer ) )
66 {
67  if ( ! myContainer->empty() )
68  {
69  Surfel s = *( myContainer->begin() );
70  myTracker = myContainer->newTracker( s );
71  myUmbrellaComputer.init( *myTracker, 0, false, 1 );
72  }
73  else
74  myTracker = 0;
75 }
76 //-----------------------------------------------------------------------------
77 template <typename TDigitalSurfaceContainer>
78 inline
80 ( TDigitalSurfaceContainer* containerPtr )
81  : myContainer( containerPtr )
82 {
83  if ( ! myContainer->empty() )
84  {
85  Surfel s = *( myContainer->begin() );
86  myTracker = myContainer->newTracker( s );
87  myUmbrellaComputer.init( *myTracker, 0, false, 1 );
88  }
89  else
90  myTracker = 0;
91 }
92 //-----------------------------------------------------------------------------
93 template <typename TDigitalSurfaceContainer>
94 inline
97 ( const DigitalSurface & other )
98 {
99  if ( this != &other )
100  {
101  myContainer = other.myContainer;
102  if ( myTracker != 0 ) delete myTracker;
103  myTracker = new DigitalSurfaceTracker( *other.myTracker );
104  myUmbrellaComputer = other.myUmbrellaComputer;
105  }
106  return *this;
107 }
108 //-----------------------------------------------------------------------------
109 template <typename TDigitalSurfaceContainer>
110 inline
111 const TDigitalSurfaceContainer &
113 {
114  return *myContainer;
115 }
116 //-----------------------------------------------------------------------------
117 template <typename TDigitalSurfaceContainer>
118 inline
119 TDigitalSurfaceContainer &
121 {
122  return *myContainer;
123 }
124 //-----------------------------------------------------------------------------
125 template <typename TDigitalSurfaceContainer>
126 inline
129 {
130  return myContainer->begin();
131 }
132 //-----------------------------------------------------------------------------
133 template <typename TDigitalSurfaceContainer>
134 inline
137 {
138  return myContainer->end();
139 }
140 //-----------------------------------------------------------------------------
141 template <typename TDigitalSurfaceContainer>
142 inline
145 {
146  return myContainer->nbSurfels();
147 }
148 //-----------------------------------------------------------------------------
149 template <typename TDigitalSurfaceContainer>
150 inline
153 {
154  return KSpace::dimension*2 - 2;
155 }
156 //-----------------------------------------------------------------------------
157 template <typename TDigitalSurfaceContainer>
158 inline
161 ( const Vertex & v ) const
162 {
163  Size d = 0;
164  Vertex s;
165  myTracker->move( v );
166  for ( typename KSpace::DirIterator q = container().space().sDirs( v );
167  q != 0; ++q )
168  {
169  if ( myTracker->adjacent( s, *q, true ) )
170  ++d;
171  if ( myTracker->adjacent( s, *q, false ) )
172  ++d;
173  }
174  return d;
175 }
176 //-----------------------------------------------------------------------------
177 template <typename TDigitalSurfaceContainer>
178 template <typename OutputIterator>
179 inline
180 void
182 writeNeighbors( OutputIterator & it,
183  const Vertex & v ) const
184 {
185  Vertex s;
186  myTracker->move( v );
187  for ( typename KSpace::DirIterator q = container().space().sDirs( v );
188  q != 0; ++q )
189  {
190  if ( myTracker->adjacent( s, *q, true ) )
191  *it++ = s;
192  if ( myTracker->adjacent( s, *q, false ) )
193  *it++ = s;
194  }
195 }
196 //-----------------------------------------------------------------------------
197 template <typename TDigitalSurfaceContainer>
198 template <typename OutputIterator, typename VertexPredicate>
199 inline
200 void
202 writeNeighbors( OutputIterator & it,
203  const Vertex & v,
204  const VertexPredicate & pred ) const
205 {
206  BOOST_CONCEPT_ASSERT(( CVertexPredicate< VertexPredicate > ));
207  Vertex s;
208  myTracker->move( v );
209  for ( typename KSpace::DirIterator q = container().space().sDirs( v );
210  q != 0; ++q )
211  {
212  if ( myTracker->adjacent( s, *q, true ) )
213  {
214  if ( pred( s ) ) *it++ = s;
215  }
216  if ( myTracker->adjacent( s, *q, false ) )
217  {
218  if ( pred( s ) ) *it++ = s;
219  }
220  }
221 }
222 
223 //-----------------------------------------------------------------------------
224 template <typename TDigitalSurfaceContainer>
225 inline
228 outArcs( const Vertex & v ) const
229 {
230  ArcRange arcs;
231  Vertex s;
232  myTracker->move( v );
233  for ( typename KSpace::DirIterator q = container().space().sDirs( v );
234  q != 0; ++q )
235  {
236  Dimension i = *q;
237  if ( myTracker->adjacent( s, i, true ) )
238  arcs.push_back( Arc( v, i, true ) );
239  if ( myTracker->adjacent( s, i, false ) )
240  arcs.push_back( Arc( v, i, false ) );
241  }
242  return arcs;
243 }
244 //-----------------------------------------------------------------------------
245 template <typename TDigitalSurfaceContainer>
246 inline
249 inArcs( const Vertex & v ) const
250 {
251  ArcRange arcs;
252  Vertex s;
253  myTracker->move( v );
254  for ( typename KSpace::DirIterator q = container().space().sDirs( v );
255  q != 0; ++q )
256  {
257  Dimension i = *q;
258  if ( myTracker->adjacent( s, i, true ) )
259  arcs.push_back( opposite( Arc( v, i, true ) ) );
260  if ( myTracker->adjacent( s, i, false ) )
261  arcs.push_back( opposite( Arc( v, i, false ) ) );
262  }
263  return arcs;
264 }
265 
266 //-----------------------------------------------------------------------------
267 template <typename TDigitalSurfaceContainer>
268 inline
271 facesAroundVertex( const Vertex & v ) const
272 {
273  typedef typename ArcRange::const_iterator ArcRangeConstIterator;
274  // std::cerr << " - facesAroundVertex(" << v << ")" << std::endl;
275  ArcRange arcs = outArcs( v );
276  FaceRange faces;
277  std::back_insert_iterator<FaceRange> output_it = std::back_inserter( faces );
278  for ( ArcRangeConstIterator it = arcs.begin(), it_end = arcs.end();
279  it != it_end; ++it )
280  {
281  // std::cerr << " + arc " << tail( *it )
282  // << " -> " << head( *it ) << std::endl;
283  FaceRange faces_of_arc = facesAroundArc( *it );
284  output_it =
285  std::copy( faces_of_arc.begin(), faces_of_arc.end(), output_it );
286  }
287  return faces;
288 }
289 //-----------------------------------------------------------------------------
290 template <typename TDigitalSurfaceContainer>
291 inline
294 head( const Arc & a ) const
295 {
296  Vertex s;
297  myTracker->move( a.base );
298  uint8_t code = myTracker->adjacent( s, a.k, a.epsilon );
299  ASSERT( code != 0 );
300  return s;
301 }
302 //-----------------------------------------------------------------------------
303 template <typename TDigitalSurfaceContainer>
304 inline
307 tail( const Arc & a ) const
308 {
309  return a.base;
310 }
311 //-----------------------------------------------------------------------------
312 template <typename TDigitalSurfaceContainer>
313 inline
316 opposite( const Arc & a ) const
317 {
318  Vertex s;
319  myTracker->move( a.base );
320  uint8_t code = myTracker->adjacent( s, a.k, a.epsilon );
321  ASSERT( code != 0 );
322  if ( code == 2 ) return Arc( s, a.k, ! a.epsilon );
323  else
324  {
325  bool orientation = container().space().sDirect( a.base, a.k );
326  unsigned int i = myTracker->orthDir();
327  return Arc( s, i,
328  ( orientation == a.epsilon )
329  == container().space().sDirect( s, i ) );
330  }
331 }
332 //-----------------------------------------------------------------------------
333 template <typename TDigitalSurfaceContainer>
334 inline
337 arc( const Vertex & t, const Vertex & h ) const
338 {
339  const KSpace & K = container().space();
340  Point p1 = K.sKCoords( t );
341  Point p2 = K.sKCoords( h );
342  p2 -= p1;
343  for ( typename KSpace::DirIterator q = K.sDirs( h );
344  q != 0; ++q )
345  {
346  Dimension i = *q;
347  if ( p1[ i ] != 0 ) return Arc( t, i, p1[ i ] > 0 );
348  }
349  ASSERT( false && "DGtal::DigitalSurface<TDigitalSurfaceContainer>::arc( tail, head ): tail and head are not adjacent." );
350  return Arc( t, 0, true );
351 }
352 //-----------------------------------------------------------------------------
353 template <typename TDigitalSurfaceContainer>
354 inline
357 facesAroundArc( const Arc & a ) const
358 {
359  FaceRange faces;
360  UmbrellaState state( a.base, a.k, a.epsilon, 0 );
361  myUmbrellaComputer.setState( state );
362  SCell sep = myUmbrellaComputer.separator();
363  // Faces are to be found along direction spanned by the separator.
364  for ( typename KSpace::DirIterator q = container().space().sDirs( sep );
365  q != 0; ++q )
366  {
367  state.j = *q;
368  faces.push_back( computeFace( state ) );
369  }
370  return faces;
371 
372 }
373 //-----------------------------------------------------------------------------
374 template <typename TDigitalSurfaceContainer>
375 inline
378 verticesAroundFace( const Face & f ) const
379 {
380  VertexRange vertices;
381  myUmbrellaComputer.setState( f.state );
382  for ( unsigned int i = 0; i < f.nbVertices; ++i )
383  {
384  vertices.push_back( myUmbrellaComputer.surfel() );
385  myUmbrellaComputer.previous();
386  }
387  return vertices;
388 }
389 //-----------------------------------------------------------------------------
390 template <typename TDigitalSurfaceContainer>
391 inline
394 allFaces() const
395 {
396  FaceSet all_faces;
397  for ( ConstIterator it = begin(), it_end = end(); it != it_end; ++it )
398  {
399  FaceRange local_faces = facesAroundVertex( *it );
400  all_faces.insert( local_faces.begin(), local_faces.end() );
401  }
402  return all_faces;
403 }
404 //-----------------------------------------------------------------------------
405 template <typename TDigitalSurfaceContainer>
406 inline
410 {
411  FaceSet all_faces;
412  for ( ConstIterator it = begin(), it_end = end(); it != it_end; ++it )
413  {
414  FaceRange local_faces = facesAroundVertex( *it );
415  for ( typename FaceRange::const_iterator lit = local_faces.begin(),
416  lit_end = local_faces.end(); lit != lit_end; ++lit )
417  if ( lit->isClosed() )
418  all_faces.insert( *lit );
419  }
420  return all_faces;
421 }
422 //-----------------------------------------------------------------------------
423 template <typename TDigitalSurfaceContainer>
424 inline
428 {
429  FaceSet all_faces;
430  for ( ConstIterator it = begin(), it_end = end(); it != it_end; ++it )
431  {
432  FaceRange local_faces = facesAroundVertex( *it );
433  for ( typename FaceRange::const_iterator lit = local_faces.begin(),
434  lit_end = local_faces.end(); lit != lit_end; ++lit )
435  if ( ! lit->isClosed() )
436  all_faces.insert( *lit );
437  }
438  return all_faces;
439 }
440 
441 //-----------------------------------------------------------------------------
442 template <typename TDigitalSurfaceContainer>
443 inline
447 {
448  myUmbrellaComputer.setState( state );
449  Surfel start = state.surfel;
450  unsigned int nb = 0;
451  unsigned int code;
452  do
453  {
454  // std::cerr << " + s/surf "
455  // << myUmbrellaComputer.state().surfel<< std::endl;
456  ++nb;
457  code = myUmbrellaComputer.previous();
458  if ( code == 0 ) break; // face is open
459  if ( myUmbrellaComputer.state() < state )
460  state = myUmbrellaComputer.state();
461  }
462  while ( myUmbrellaComputer.surfel() != start );
463  if ( code == 0 ) // open face
464  { // Going back to count the number of incident vertices.
465  nb = 0;
466  do
467  {
468  // std::cerr << " + c/surf "
469  // << myUmbrellaComputer.state().surfel<< std::endl;
470  ++nb;
471  code = myUmbrellaComputer.next();
472  }
473  while ( code != 0 );
474  return Face( myUmbrellaComputer.state(), nb, false );
475  }
476  else // closed face
477  return Face( state, nb, true );
478 }
479 //-----------------------------------------------------------------------------
480 template <typename TDigitalSurfaceContainer>
481 inline
484 separator( const Arc & a ) const
485 {
486  return container().space().sIncident( a.base, a.k, a.epsilon );
487 }
488 //-----------------------------------------------------------------------------
489 // template <typename TDigitalSurfaceContainer>
490 // inline
491 // typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::SCell
492 // DGtal::DigitalSurface<TDigitalSurfaceContainer>::
493 // separator( const Face & f ) const
494 // {
495 // return container().space().sIncident( f.state.surfel, f.state.k,
496 // f.state.epsilon );
497 // }
498 //-----------------------------------------------------------------------------
499 template <typename TDigitalSurfaceContainer>
500 inline
503 pivot( const Face & f ) const
504 {
505  SCell sep = container().space().sIncident( f.state.surfel, f.state.k,
506  f.state.epsilon );
507  return container().space().sDirectIncident( sep, f.state.j );
508 }
509 
510 
511 
513 // Interface - public :
514 
519 template <typename TDigitalSurfaceContainer>
520 inline
521 void
523 {
524  out << "[DigitalSurface]";
525 }
526 
531 template <typename TDigitalSurfaceContainer>
532 inline
533 bool
535 {
536  return myTracker != 0;
537 }
538 
539 //-----------------------------------------------------------------------------
544 template <typename TDigitalSurfaceContainer>
545 void
547 exportSurfaceAs3DOFF ( std::ostream & out ) const
548 {
549  typedef DGtal::uint64_t Number;
550  // Numbers all vertices.
551  std::map<Vertex, Number> index;
552  Number nbv = 0;
553  for ( ConstIterator it = begin(), it_end = end();
554  it != it_end; ++it )
555  index[ *it ] = nbv++;
556  // Get faces
557  // std::cerr << "- " << nbv << " vertices." << std::endl;
558  FaceSet faces = allClosedFaces();
559  // Compute the number of edges and faces.
560  Number nbe = 0;
561  Number nbf = 0;
562  for ( typename FaceSet::const_iterator
563  itf = faces.begin(), itf_end = faces.end();
564  itf != itf_end; ++itf )
565  {
566  if ( itf->isClosed() )
567  { nbe += itf->nbVertices; ++nbf; }
568  else
569  { nbe += itf->nbVertices - 1; }
570  }
571  // std::cerr << "- " << nbf << " faces." << std::endl;
572  // Outputs OFF header.
573  out << "OFF" << std::endl
574  << "# Generated by DGtal::DigitalSurface." << std::endl
575  << nbv << " " << nbf << " " << ( nbe / 2 ) << std::endl;
576  // Outputs vertex coordinates (the 3 first ones).
577  const KSpace & K = container().space();
578  for ( ConstIterator it = begin(), it_end = end();
579  it != it_end; ++it )
580  {
581  Point p = K.sKCoords( *it );
582  out << p[ 0 ] << " " << p[ 1 ] << " " << p[ 2 ] << std::endl;
583  // double areaD = NumberTraits<Coordinate>::castToDouble(area)*2.0;
584  }
585  // Outputs closed faces.
586  for ( typename FaceSet::const_iterator
587  itf = faces.begin(), itf_end = faces.end();
588  itf != itf_end; ++itf )
589  {
590  if ( itf->isClosed() )
591  {
592  out << itf->nbVertices;
593  VertexRange vtcs = verticesAroundFace( *itf );
594  for ( typename VertexRange::const_iterator
595  itv = vtcs.begin(), itv_end = vtcs.end();
596  itv != itv_end; ++itv )
597  out << " " << index[ *itv ];
598  out << std::endl;
599  }
600  }
601 }
602 
603 //-----------------------------------------------------------------------------
604 template <typename TDigitalSurfaceContainer>
605 template <typename CellEmbedder>
606 void
609 ( std::ostream & out,
610  const CellEmbedder & cembedder ) const
611 {
612  BOOST_CONCEPT_ASSERT(( CCellEmbedder< CellEmbedder > ));
613 
614  typedef DGtal::uint64_t Number;
615  // Numbers all vertices.
616  std::map<Vertex, Number> index;
617  Number nbv = 0;
618  for ( ConstIterator it = begin(), it_end = end();
619  it != it_end; ++it )
620  index[ *it ] = nbv++;
621  // Get faces
622  // std::cerr << "- " << nbv << " vertices." << std::endl;
623  FaceSet faces = allClosedFaces();
624  // Compute the number of edges and faces.
625  Number nbe = 0;
626  Number nbf = 0;
627  for ( typename FaceSet::const_iterator
628  itf = faces.begin(), itf_end = faces.end();
629  itf != itf_end; ++itf )
630  {
631  if ( itf->isClosed() )
632  { nbe += itf->nbVertices; ++nbf; }
633  else
634  { nbe += itf->nbVertices - 1; }
635  }
636  // std::cerr << "- " << nbf << " faces." << std::endl;
637  // Outputs OFF header.
638  out << "OFF" << std::endl
639  << "# Generated by DGtal::DigitalSurface." << std::endl
640  << nbv << " " << nbf << " " << ( nbe / 2 ) << std::endl;
641  // Outputs vertex coordinates (the 3 first ones).
642  typedef typename CellEmbedder::RealPoint RealPoint;
643  const KSpace & K = container().space();
644  for ( ConstIterator it = begin(), it_end = end();
645  it != it_end; ++it )
646  {
647  RealPoint p( cembedder( K.unsigns( *it ) ) );
648  out << p[ 0 ] << " " << p[ 1 ] << " " << p[ 2 ] << std::endl;
649  // double areaD = NumberTraits<Coordinate>::castToDouble(area)*2.0;
650  }
651  // Outputs closed faces.
652  for ( typename FaceSet::const_iterator
653  itf = faces.begin(), itf_end = faces.end();
654  itf != itf_end; ++itf )
655  {
656  if ( itf->isClosed() )
657  {
658  out << itf->nbVertices;
659  VertexRange vtcs = verticesAroundFace( *itf );
660  for ( typename VertexRange::const_iterator
661  itv = vtcs.begin(), itv_end = vtcs.end();
662  itv != itv_end; ++itv )
663  out << " " << index[ *itv ];
664  out << std::endl;
665  }
666  }
667 }
668 
669 //-----------------------------------------------------------------------------
670 template <typename TDigitalSurfaceContainer>
671 template <typename CellEmbedder>
672 void
675 ( std::ostream & out,
676  const CellEmbedder & cembedder ) const
677 {
678  BOOST_CONCEPT_ASSERT(( CCellEmbedder< CellEmbedder > ));
679  BOOST_CONCEPT_ASSERT(( CWithGradientMap< CellEmbedder > ));
680 
681  typedef typename CellEmbedder::GradientMap GradientMap;
682  typedef typename CellEmbedder::Cell MyCell;
683  typedef typename CellEmbedder::RealPoint RealPoint;
684  typedef typename CellEmbedder::RealVector RealVector;
685  typedef DGtal::uint64_t Number;
686 
687  // Gets the gradient map.
688  GradientMap gradMap = cembedder.gradientMap();
689  // Numbers all vertices.
690  std::map<Vertex, Number> index;
691  Number nbv = 0;
692  for ( ConstIterator it = begin(), it_end = end();
693  it != it_end; ++it )
694  index[ *it ] = nbv++;
695  // Get faces
696  // std::cerr << "- " << nbv << " vertices." << std::endl;
697  FaceSet faces = allClosedFaces();
698  // Compute the number of edges and faces.
699  Number nbe = 0;
700  Number nbf = 0;
701  for ( typename FaceSet::const_iterator
702  itf = faces.begin(), itf_end = faces.end();
703  itf != itf_end; ++itf )
704  {
705  if ( itf->isClosed() )
706  { nbe += itf->nbVertices; ++nbf; }
707  else
708  { nbe += itf->nbVertices - 1; }
709  }
710  // std::cerr << "- " << nbf << " faces." << std::endl;
711  // Outputs OFF header.
712  out << "NOFF" << std::endl
713  << "# Generated by DGtal::DigitalSurface." << std::endl
714  << nbv << " " << nbf << " " << ( nbe / 2 ) << std::endl;
715  // Outputs vertex coordinates (the 3 first ones).
716  const KSpace & K = container().space();
717  RealPoint p;
718  RealVector v;
719  for ( ConstIterator it = begin(), it_end = end();
720  it != it_end; ++it )
721  {
722  MyCell c = K.unsigns( *it );
723  p = cembedder( c );
724  v = gradMap( c );
725  //cembedder.embedSCell( *it, p, v );
726  double norm = v.norm();
727  if ( norm != 0.0 ) v /= norm;
728  out << p[ 0 ] << " " << p[ 1 ] << " " << p[ 2 ] << " "
729  << v[ 0 ] << " " << v[ 1 ] << " " << v[ 2 ] << std::endl;
730  // double areaD = NumberTraits<Coordinate>::castToDouble(area)*2.0;
731  }
732  // Outputs closed faces.
733  for ( typename FaceSet::const_iterator
734  itf = faces.begin(), itf_end = faces.end();
735  itf != itf_end; ++itf )
736  {
737  if ( itf->isClosed() )
738  {
739  out << itf->nbVertices;
740  VertexRange vtcs = verticesAroundFace( *itf );
741  for ( typename VertexRange::const_iterator
742  itv = vtcs.begin(), itv_end = vtcs.end();
743  itv != itv_end; ++itv )
744  out << " " << index[ *itv ];
745  out << std::endl;
746  }
747  }
748 }
749 
750 //-----------------------------------------------------------------------------
751 template <typename TDigitalSurfaceContainer>
752 template <typename SCellEmbedderWithGradientMap>
753 void
756 ( std::ostream & out,
757  const SCellEmbedderWithGradientMap & scembedder ) const
758 {
759  BOOST_CONCEPT_ASSERT(( CSCellEmbedder< SCellEmbedderWithGradientMap > ));
760  BOOST_CONCEPT_ASSERT(( CWithGradientMap< SCellEmbedderWithGradientMap > ));
761 
762  typedef typename SCellEmbedderWithGradientMap::GradientMap GradientMap;
763  typedef typename SCellEmbedderWithGradientMap::SCell MySCell;
764  typedef typename SCellEmbedderWithGradientMap::RealPoint RealPoint;
765  typedef typename SCellEmbedderWithGradientMap::RealVector RealVector;
766  typedef DGtal::uint64_t Number;
767 
768  // Gets the gradient map.
769  GradientMap gradMap = scembedder.gradientMap();
770  // Numbers all vertices.
771  std::map<Vertex, Number> index;
772  Number nbv = 0;
773  for ( ConstIterator it = begin(), it_end = end();
774  it != it_end; ++it )
775  index[ *it ] = nbv++;
776  // Get faces
777  // std::cerr << "- " << nbv << " vertices." << std::endl;
778  FaceSet faces = allClosedFaces();
779  // Compute the number of edges and faces.
780  Number nbe = 0;
781  Number nbf = 0;
782  for ( typename FaceSet::const_iterator
783  itf = faces.begin(), itf_end = faces.end();
784  itf != itf_end; ++itf )
785  {
786  if ( itf->isClosed() )
787  { nbe += itf->nbVertices; ++nbf; }
788  else
789  { nbe += itf->nbVertices - 1; }
790  }
791  // std::cerr << "- " << nbf << " faces." << std::endl;
792  // Outputs OFF header.
793  out << "NOFF" << std::endl
794  << "# Generated by DGtal::DigitalSurface." << std::endl
795  << nbv << " " << nbf << " " << ( nbe / 2 ) << std::endl;
796  // Outputs vertex coordinates (the 3 first ones).
797  RealPoint p;
798  RealVector v;
799  for ( ConstIterator it = begin(), it_end = end();
800  it != it_end; ++it )
801  {
802  MySCell c = *it;
803  p = scembedder( c );
804  v = gradMap( c );
805  //cembedder.embedSCell( *it, p, v );
806  double norm = v.norm();
807  if ( norm != 0.0 ) v /= norm;
808  out << p[ 0 ] << " " << p[ 1 ] << " " << p[ 2 ] << " "
809  << v[ 0 ] << " " << v[ 1 ] << " " << v[ 2 ] << std::endl;
810  // double areaD = NumberTraits<Coordinate>::castToDouble(area)*2.0;
811  }
812  // Outputs closed faces.
813  for ( typename FaceSet::const_iterator
814  itf = faces.begin(), itf_end = faces.end();
815  itf != itf_end; ++itf )
816  {
817  if ( itf->isClosed() )
818  {
819  out << itf->nbVertices;
820  VertexRange vtcs = verticesAroundFace( *itf );
821  for ( typename VertexRange::const_iterator
822  itv = vtcs.begin(), itv_end = vtcs.end();
823  itv != itv_end; ++itv )
824  out << " " << index[ *itv ];
825  out << std::endl;
826  }
827  }
828 }
829 
830 //-----------------------------------------------------------------------------
831 template <typename TDigitalSurfaceContainer>
832 template <typename CellEmbedder>
833 void
836 ( std::ostream & out,
837  const CellEmbedder & cembedder ) const
838 {
839  typedef DGtal::uint64_t Number;
840  // Numbers all vertices.
841  std::map<Vertex, Number> index;
842  Number nbv = 0;
843  for ( ConstIterator it = begin(), it_end = end();
844  it != it_end; ++it )
845  index[ *it ] = nbv++;
846  // Get faces
847  // std::cerr << "- " << nbv << " vertices." << std::endl;
848  FaceSet faces = allClosedFaces();
849  // Compute the number of edges and faces.
850  Number nbe = 0;
851  Number nbf = 0;
852  for ( typename FaceSet::const_iterator
853  itf = faces.begin(), itf_end = faces.end();
854  itf != itf_end; ++itf )
855  {
856  if ( itf->isClosed() )
857  { nbe += itf->nbVertices; ++nbf; }
858  else
859  { nbe += itf->nbVertices - 1; }
860  }
861  // std::cerr << "- " << nbf << " faces." << std::endl;
862  // Outputs OFF header.
863  out << "NOFF" << std::endl
864  << "# Generated by DGtal::DigitalSurface." << std::endl
865  << nbv << " " << nbf << " " << ( nbe / 2 ) << std::endl;
866  // Outputs vertex coordinates (the 3 first ones).
867  typedef typename CellEmbedder::RealPoint RealPoint;
868  typedef typename CellEmbedder::RealVector RealVector;
869  const KSpace & K = container().space();
870  RealPoint p;
871  RealVector v;
872  for ( ConstIterator it = begin(), it_end = end();
873  it != it_end; ++it )
874  {
875  cembedder.embedSurfel( it, p, v );
876  double norm = v.norm();
877  if ( norm != 0.0 ) v /= norm;
878  out << p[ 0 ] << " " << p[ 1 ] << " " << p[ 2 ] << " "
879  << v[ 0 ] << " " << v[ 1 ] << " " << v[ 2 ] << std::endl;
880  // double areaD = NumberTraits<Coordinate>::castToDouble(area)*2.0;
881  }
882  // Outputs closed faces.
883  for ( typename FaceSet::const_iterator
884  itf = faces.begin(), itf_end = faces.end();
885  itf != itf_end; ++itf )
886  {
887  if ( itf->isClosed() )
888  {
889  out << itf->nbVertices;
890  VertexRange vtcs = verticesAroundFace( *itf );
891  for ( typename VertexRange::const_iterator
892  itv = vtcs.begin(), itv_end = vtcs.end();
893  itv != itv_end; ++itv )
894  out << " " << index[ *itv ];
895  out << std::endl;
896  }
897  }
898 }
899 
900 
901 
902 
904 // Implementation of inline functions //
905 
906 template <typename TDigitalSurfaceContainer>
907 inline
908 std::ostream&
909 DGtal::operator<< ( std::ostream & out,
911 {
912  object.selfDisplay( out );
913  return out;
914 }
915 
916 // //
918 
919