DGtal  0.9.2
DigitalSurface.ih
1 /**
2  * This program is free software: you can redistribute it and/or modify
3  * it under the terms of the GNU Lesser General Public License as
4  * published by the Free Software Foundation, either version 3 of the
5  * License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program. If not, see <http://www.gnu.org/licenses/>.
14  *
15  **/
16 
17 /**
18  * @file DigitalSurface.ih
19  * @author Jacques-Olivier Lachaud (\c jacques-olivier.lachaud@univ-savoie.fr )
20  * Laboratory of Mathematics (CNRS, UMR 5127), University of Savoie, France
21  *
22  * @date 2011/09/01
23  *
24  * Implementation of inline methods defined in DigitalSurface.h
25  *
26  * This file is part of the DGtal library.
27  */
28 
29 
30 //////////////////////////////////////////////////////////////////////////////
31 #include <cstdlib>
32 #include <map>
33 #include "DGtal/graph/CVertexPredicate.h"
34 //////////////////////////////////////////////////////////////////////////////
35 
36 ///////////////////////////////////////////////////////////////////////////////
37 // IMPLEMENTATION of inline methods.
38 ///////////////////////////////////////////////////////////////////////////////
39 
40 ///////////////////////////////////////////////////////////////////////////////
41 // ----------------------- Standard services ------------------------------
42 
43 //-----------------------------------------------------------------------------
44 template <typename TDigitalSurfaceContainer>
45 inline
46 DGtal::DigitalSurface<TDigitalSurfaceContainer>::~DigitalSurface()
47 {
48  if ( myTracker != 0 ) delete myTracker;
49 }
50 //-----------------------------------------------------------------------------
51 template <typename TDigitalSurfaceContainer>
52 inline
53 DGtal::DigitalSurface<TDigitalSurfaceContainer>::DigitalSurface
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
63 DGtal::DigitalSurface<TDigitalSurfaceContainer>::DigitalSurface
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
79 DGtal::DigitalSurface<TDigitalSurfaceContainer>::DigitalSurface
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
95 DGtal::DigitalSurface<TDigitalSurfaceContainer> &
96 DGtal::DigitalSurface<TDigitalSurfaceContainer>::operator=
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 &
112 DGtal::DigitalSurface<TDigitalSurfaceContainer>::container() const
113 {
114  return *myContainer;
115 }
116 //-----------------------------------------------------------------------------
117 template <typename TDigitalSurfaceContainer>
118 inline
119 TDigitalSurfaceContainer &
120 DGtal::DigitalSurface<TDigitalSurfaceContainer>::container()
121 {
122  return *myContainer;
123 }
124 //-----------------------------------------------------------------------------
125 template <typename TDigitalSurfaceContainer>
126 inline
127 typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::ConstIterator
128 DGtal::DigitalSurface<TDigitalSurfaceContainer>::begin() const
129 {
130  return myContainer->begin();
131 }
132 //-----------------------------------------------------------------------------
133 template <typename TDigitalSurfaceContainer>
134 inline
135 typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::ConstIterator
136 DGtal::DigitalSurface<TDigitalSurfaceContainer>::end() const
137 {
138  return myContainer->end();
139 }
140 //-----------------------------------------------------------------------------
141 template <typename TDigitalSurfaceContainer>
142 inline
143 typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::Size
144 DGtal::DigitalSurface<TDigitalSurfaceContainer>::size() const
145 {
146  return myContainer->nbSurfels();
147 }
148 //-----------------------------------------------------------------------------
149 template <typename TDigitalSurfaceContainer>
150 inline
151 typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::Size
152 DGtal::DigitalSurface<TDigitalSurfaceContainer>::bestCapacity() const
153 {
154  return KSpace::dimension*2 - 2;
155 }
156 //-----------------------------------------------------------------------------
157 template <typename TDigitalSurfaceContainer>
158 inline
159 typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::Size
160 DGtal::DigitalSurface<TDigitalSurfaceContainer>::degree
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
181 DGtal::DigitalSurface<TDigitalSurfaceContainer>::
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
201 DGtal::DigitalSurface<TDigitalSurfaceContainer>::
202 writeNeighbors( OutputIterator & it,
203  const Vertex & v,
204  const VertexPredicate & pred ) const
205 {
206  BOOST_CONCEPT_ASSERT(( concepts::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
226 typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::ArcRange
227 DGtal::DigitalSurface<TDigitalSurfaceContainer>::
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
247 typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::ArcRange
248 DGtal::DigitalSurface<TDigitalSurfaceContainer>::
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
269 typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::FaceRange
270 DGtal::DigitalSurface<TDigitalSurfaceContainer>::
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
292 typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::Vertex
293 DGtal::DigitalSurface<TDigitalSurfaceContainer>::
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 ); boost::ignore_unused_variable_warning(code);
300  return s;
301 }
302 //-----------------------------------------------------------------------------
303 template <typename TDigitalSurfaceContainer>
304 inline
305 typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::Vertex
306 DGtal::DigitalSurface<TDigitalSurfaceContainer>::
307 tail( const Arc & a ) const
308 {
309  return a.base;
310 }
311 //-----------------------------------------------------------------------------
312 template <typename TDigitalSurfaceContainer>
313 inline
314 typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::Arc
315 DGtal::DigitalSurface<TDigitalSurfaceContainer>::
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
335 typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::Arc
336 DGtal::DigitalSurface<TDigitalSurfaceContainer>::
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
355 typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::FaceRange
356 DGtal::DigitalSurface<TDigitalSurfaceContainer>::
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
376 typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::VertexRange
377 DGtal::DigitalSurface<TDigitalSurfaceContainer>::
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
392 typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::FaceSet
393 DGtal::DigitalSurface<TDigitalSurfaceContainer>::
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
407 typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::FaceSet
408 DGtal::DigitalSurface<TDigitalSurfaceContainer>::
409 allClosedFaces() const
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
425 typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::FaceSet
426 DGtal::DigitalSurface<TDigitalSurfaceContainer>::
427 allOpenFaces() const
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
444 typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::Face
445 DGtal::DigitalSurface<TDigitalSurfaceContainer>::
446 computeFace( UmbrellaState state ) const
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
482 typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::SCell
483 DGtal::DigitalSurface<TDigitalSurfaceContainer>::
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
501 typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::SCell
502 DGtal::DigitalSurface<TDigitalSurfaceContainer>::
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 
512 ///////////////////////////////////////////////////////////////////////////////
513 // Interface - public :
514 
515 /**
516  * Writes/Displays the object on an output stream.
517  * @param out the output stream where the object is written.
518  */
519 template <typename TDigitalSurfaceContainer>
520 inline
521 void
522 DGtal::DigitalSurface<TDigitalSurfaceContainer>::selfDisplay ( std::ostream & out ) const
523 {
524  out << "[DigitalSurface]";
525 }
526 
527 /**
528  * Checks the validity/consistency of the object.
529  * @return 'true' if the object is valid, 'false' otherwise.
530  */
531 template <typename TDigitalSurfaceContainer>
532 inline
533 bool
534 DGtal::DigitalSurface<TDigitalSurfaceContainer>::isValid() const
535 {
536  return myTracker != 0;
537 }
538 
539 //-----------------------------------------------------------------------------
540 /**
541  Writes/Displays the object on an output stream.
542  @param out the output stream where the object is written.
543 */
544 template <typename TDigitalSurfaceContainer>
545 void
546 DGtal::DigitalSurface<TDigitalSurfaceContainer>::
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
607 DGtal::DigitalSurface<TDigitalSurfaceContainer>::
608 exportEmbeddedSurfaceAs3DOFF
609 ( std::ostream & out,
610  const CellEmbedder & cembedder ) const
611 {
612  BOOST_CONCEPT_ASSERT(( concepts::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
673 DGtal::DigitalSurface<TDigitalSurfaceContainer>::
674 exportEmbeddedSurfaceAs3DNOFF
675 ( std::ostream & out,
676  const CellEmbedder & cembedder ) const
677 {
678  BOOST_CONCEPT_ASSERT(( concepts::CCellEmbedder< CellEmbedder > ));
679  BOOST_CONCEPT_ASSERT(( concepts::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
754 DGtal::DigitalSurface<TDigitalSurfaceContainer>::
755 exportAs3DNOFF
756 ( std::ostream & out,
757  const SCellEmbedderWithGradientMap & scembedder ) const
758 {
759  BOOST_CONCEPT_ASSERT(( concepts::CSCellEmbedder< SCellEmbedderWithGradientMap > ));
760  BOOST_CONCEPT_ASSERT(( concepts::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
834 DGtal::DigitalSurface<TDigitalSurfaceContainer>::
835 exportEmbeddedIteratedSurfaceAs3DNOFF
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 
903 ///////////////////////////////////////////////////////////////////////////////
904 // Implementation of inline functions //
905 
906 template <typename TDigitalSurfaceContainer>
907 inline
908 std::ostream&
909 DGtal::operator<< ( std::ostream & out,
910  const DigitalSurface<TDigitalSurfaceContainer> & object )
911 {
912  object.selfDisplay( out );
913  return out;
914 }
915 
916 // //
917 ///////////////////////////////////////////////////////////////////////////////
918 
919