DGtal  0.9.4.1
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( t );
344  q != 0; ++q )
345  {
346  Dimension i = *q;
347  if ( p2[ i ] != 0 ) return Arc( t, i, p2[ 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  // // JOL 2017/07/4: bad test.
352  // for ( typename KSpace::DirIterator q = K.sDirs( h );
353  // q != 0; ++q )
354  // {
355  // Dimension i = *q;
356  // if ( p1[ i ] != 0 ) return Arc( t, i, p1[ i ] > 0 );
357  // }
358  // ASSERT( false && "DGtal::DigitalSurface<TDigitalSurfaceContainer>::arc( tail, head ): tail and head are not adjacent." );
359  // return Arc( t, 0, true );
360 }
361 //-----------------------------------------------------------------------------
362 template <typename TDigitalSurfaceContainer>
363 inline
364 typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::FaceRange
365 DGtal::DigitalSurface<TDigitalSurfaceContainer>::
366 facesAroundArc( const Arc & a ) const
367 {
368  FaceRange faces;
369  UmbrellaState state( a.base, a.k, a.epsilon, 0 );
370  myUmbrellaComputer.setState( state );
371  SCell sep = myUmbrellaComputer.separator();
372  // Faces are to be found along direction spanned by the separator.
373  for ( typename KSpace::DirIterator q = container().space().sDirs( sep );
374  q != 0; ++q )
375  {
376  state.j = *q;
377  faces.push_back( computeFace( state ) );
378  }
379  return faces;
380 
381 }
382 //-----------------------------------------------------------------------------
383 template <typename TDigitalSurfaceContainer>
384 inline
385 typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::VertexRange
386 DGtal::DigitalSurface<TDigitalSurfaceContainer>::
387 verticesAroundFace( const Face & f ) const
388 {
389  VertexRange vertices;
390  myUmbrellaComputer.setState( f.state );
391  for ( unsigned int i = 0; i < f.nbVertices; ++i )
392  {
393  vertices.push_back( myUmbrellaComputer.surfel() );
394  myUmbrellaComputer.previous();
395  }
396  return vertices;
397 }
398 //-----------------------------------------------------------------------------
399 template <typename TDigitalSurfaceContainer>
400 inline
401 typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::FaceSet
402 DGtal::DigitalSurface<TDigitalSurfaceContainer>::
403 allFaces() const
404 {
405  FaceSet all_faces;
406  for ( ConstIterator it = begin(), it_end = end(); it != it_end; ++it )
407  {
408  FaceRange local_faces = facesAroundVertex( *it );
409  all_faces.insert( local_faces.begin(), local_faces.end() );
410  }
411  return all_faces;
412 }
413 //-----------------------------------------------------------------------------
414 template <typename TDigitalSurfaceContainer>
415 inline
416 typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::FaceSet
417 DGtal::DigitalSurface<TDigitalSurfaceContainer>::
418 allClosedFaces() const
419 {
420  FaceSet all_faces;
421  for ( ConstIterator it = begin(), it_end = end(); it != it_end; ++it )
422  {
423  FaceRange local_faces = facesAroundVertex( *it );
424  for ( typename FaceRange::const_iterator lit = local_faces.begin(),
425  lit_end = local_faces.end(); lit != lit_end; ++lit )
426  if ( lit->isClosed() )
427  all_faces.insert( *lit );
428  }
429  return all_faces;
430 }
431 //-----------------------------------------------------------------------------
432 template <typename TDigitalSurfaceContainer>
433 inline
434 typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::FaceSet
435 DGtal::DigitalSurface<TDigitalSurfaceContainer>::
436 allOpenFaces() const
437 {
438  FaceSet all_faces;
439  for ( ConstIterator it = begin(), it_end = end(); it != it_end; ++it )
440  {
441  FaceRange local_faces = facesAroundVertex( *it );
442  for ( typename FaceRange::const_iterator lit = local_faces.begin(),
443  lit_end = local_faces.end(); lit != lit_end; ++lit )
444  if ( ! lit->isClosed() )
445  all_faces.insert( *lit );
446  }
447  return all_faces;
448 }
449 
450 //-----------------------------------------------------------------------------
451 template <typename TDigitalSurfaceContainer>
452 inline
453 typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::Face
454 DGtal::DigitalSurface<TDigitalSurfaceContainer>::
455 computeFace( UmbrellaState state ) const
456 {
457  myUmbrellaComputer.setState( state );
458  Surfel start = state.surfel;
459  unsigned int nb = 0;
460  unsigned int code;
461  do
462  {
463  // std::cerr << " + s/surf "
464  // << myUmbrellaComputer.state().surfel<< std::endl;
465  ++nb;
466  code = myUmbrellaComputer.previous();
467  if ( code == 0 ) break; // face is open
468  if ( myUmbrellaComputer.state() < state )
469  state = myUmbrellaComputer.state();
470  }
471  while ( myUmbrellaComputer.surfel() != start );
472  if ( code == 0 ) // open face
473  { // Going back to count the number of incident vertices.
474  nb = 0;
475  do
476  {
477  // std::cerr << " + c/surf "
478  // << myUmbrellaComputer.state().surfel<< std::endl;
479  ++nb;
480  code = myUmbrellaComputer.next();
481  }
482  while ( code != 0 );
483  return Face( myUmbrellaComputer.state(), nb, false );
484  }
485  else // closed face
486  return Face( state, nb, true );
487 }
488 //-----------------------------------------------------------------------------
489 template <typename TDigitalSurfaceContainer>
490 inline
491 typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::SCell
492 DGtal::DigitalSurface<TDigitalSurfaceContainer>::
493 separator( const Arc & a ) const
494 {
495  return container().space().sIncident( a.base, a.k, a.epsilon );
496 }
497 //-----------------------------------------------------------------------------
498 // template <typename TDigitalSurfaceContainer>
499 // inline
500 // typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::SCell
501 // DGtal::DigitalSurface<TDigitalSurfaceContainer>::
502 // separator( const Face & f ) const
503 // {
504 // return container().space().sIncident( f.state.surfel, f.state.k,
505 // f.state.epsilon );
506 // }
507 //-----------------------------------------------------------------------------
508 template <typename TDigitalSurfaceContainer>
509 inline
510 typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::SCell
511 DGtal::DigitalSurface<TDigitalSurfaceContainer>::
512 pivot( const Face & f ) const
513 {
514  SCell sep = container().space().sIncident( f.state.surfel, f.state.k,
515  f.state.epsilon );
516  return container().space().sDirectIncident( sep, f.state.j );
517 }
518 
519 
520 
521 ///////////////////////////////////////////////////////////////////////////////
522 // Interface - public :
523 
524 /**
525  * Writes/Displays the object on an output stream.
526  * @param out the output stream where the object is written.
527  */
528 template <typename TDigitalSurfaceContainer>
529 inline
530 void
531 DGtal::DigitalSurface<TDigitalSurfaceContainer>::selfDisplay ( std::ostream & out ) const
532 {
533  out << "[DigitalSurface]";
534 }
535 
536 /**
537  * Checks the validity/consistency of the object.
538  * @return 'true' if the object is valid, 'false' otherwise.
539  */
540 template <typename TDigitalSurfaceContainer>
541 inline
542 bool
543 DGtal::DigitalSurface<TDigitalSurfaceContainer>::isValid() const
544 {
545  return myTracker != 0;
546 }
547 
548 //-----------------------------------------------------------------------------
549 /**
550  Writes/Displays the object on an output stream.
551  @param out the output stream where the object is written.
552 */
553 template <typename TDigitalSurfaceContainer>
554 void
555 DGtal::DigitalSurface<TDigitalSurfaceContainer>::
556 exportSurfaceAs3DOFF ( std::ostream & out ) const
557 {
558  typedef DGtal::uint64_t Number;
559  // Numbers all vertices.
560  std::map<Vertex, Number> index;
561  Number nbv = 0;
562  for ( ConstIterator it = begin(), it_end = end();
563  it != it_end; ++it )
564  index[ *it ] = nbv++;
565  // Get faces
566  // std::cerr << "- " << nbv << " vertices." << std::endl;
567  FaceSet faces = allClosedFaces();
568  // Compute the number of edges and faces.
569  Number nbe = 0;
570  Number nbf = 0;
571  for ( typename FaceSet::const_iterator
572  itf = faces.begin(), itf_end = faces.end();
573  itf != itf_end; ++itf )
574  {
575  if ( itf->isClosed() )
576  { nbe += itf->nbVertices; ++nbf; }
577  else
578  { nbe += itf->nbVertices - 1; }
579  }
580  // std::cerr << "- " << nbf << " faces." << std::endl;
581  // Outputs OFF header.
582  out << "OFF" << std::endl
583  << "# Generated by DGtal::DigitalSurface." << std::endl
584  << nbv << " " << nbf << " " << ( nbe / 2 ) << std::endl;
585  // Outputs vertex coordinates (the 3 first ones).
586  const KSpace & K = container().space();
587  for ( ConstIterator it = begin(), it_end = end();
588  it != it_end; ++it )
589  {
590  Point p = K.sKCoords( *it );
591  out << p[ 0 ] << " " << p[ 1 ] << " " << p[ 2 ] << std::endl;
592  // double areaD = NumberTraits<Coordinate>::castToDouble(area)*2.0;
593  }
594  // Outputs closed faces.
595  for ( typename FaceSet::const_iterator
596  itf = faces.begin(), itf_end = faces.end();
597  itf != itf_end; ++itf )
598  {
599  if ( itf->isClosed() )
600  {
601  out << itf->nbVertices;
602  VertexRange vtcs = verticesAroundFace( *itf );
603  for ( typename VertexRange::const_iterator
604  itv = vtcs.begin(), itv_end = vtcs.end();
605  itv != itv_end; ++itv )
606  out << " " << index[ *itv ];
607  out << std::endl;
608  }
609  }
610 }
611 
612 //-----------------------------------------------------------------------------
613 template <typename TDigitalSurfaceContainer>
614 template <typename CellEmbedder>
615 void
616 DGtal::DigitalSurface<TDigitalSurfaceContainer>::
617 exportEmbeddedSurfaceAs3DOFF
618 ( std::ostream & out,
619  const CellEmbedder & cembedder ) const
620 {
621  BOOST_CONCEPT_ASSERT(( concepts::CCellEmbedder< CellEmbedder > ));
622 
623  typedef DGtal::uint64_t Number;
624  // Numbers all vertices.
625  std::map<Vertex, Number> index;
626  Number nbv = 0;
627  for ( ConstIterator it = begin(), it_end = end();
628  it != it_end; ++it )
629  index[ *it ] = nbv++;
630  // Get faces
631  // std::cerr << "- " << nbv << " vertices." << std::endl;
632  FaceSet faces = allClosedFaces();
633  // Compute the number of edges and faces.
634  Number nbe = 0;
635  Number nbf = 0;
636  for ( typename FaceSet::const_iterator
637  itf = faces.begin(), itf_end = faces.end();
638  itf != itf_end; ++itf )
639  {
640  if ( itf->isClosed() )
641  { nbe += itf->nbVertices; ++nbf; }
642  else
643  { nbe += itf->nbVertices - 1; }
644  }
645  // std::cerr << "- " << nbf << " faces." << std::endl;
646  // Outputs OFF header.
647  out << "OFF" << std::endl
648  << "# Generated by DGtal::DigitalSurface." << std::endl
649  << nbv << " " << nbf << " " << ( nbe / 2 ) << std::endl;
650  // Outputs vertex coordinates (the 3 first ones).
651  typedef typename CellEmbedder::RealPoint RealPoint;
652  const KSpace & K = container().space();
653  for ( ConstIterator it = begin(), it_end = end();
654  it != it_end; ++it )
655  {
656  RealPoint p( cembedder( K.unsigns( *it ) ) );
657  out << p[ 0 ] << " " << p[ 1 ] << " " << p[ 2 ] << std::endl;
658  // double areaD = NumberTraits<Coordinate>::castToDouble(area)*2.0;
659  }
660  // Outputs closed faces.
661  for ( typename FaceSet::const_iterator
662  itf = faces.begin(), itf_end = faces.end();
663  itf != itf_end; ++itf )
664  {
665  if ( itf->isClosed() )
666  {
667  out << itf->nbVertices;
668  VertexRange vtcs = verticesAroundFace( *itf );
669  for ( typename VertexRange::const_iterator
670  itv = vtcs.begin(), itv_end = vtcs.end();
671  itv != itv_end; ++itv )
672  out << " " << index[ *itv ];
673  out << std::endl;
674  }
675  }
676 }
677 
678 //-----------------------------------------------------------------------------
679 template <typename TDigitalSurfaceContainer>
680 template <typename CellEmbedder>
681 void
682 DGtal::DigitalSurface<TDigitalSurfaceContainer>::
683 exportEmbeddedSurfaceAs3DNOFF
684 ( std::ostream & out,
685  const CellEmbedder & cembedder ) const
686 {
687  BOOST_CONCEPT_ASSERT(( concepts::CCellEmbedder< CellEmbedder > ));
688  BOOST_CONCEPT_ASSERT(( concepts::CWithGradientMap< CellEmbedder > ));
689 
690  typedef typename CellEmbedder::GradientMap GradientMap;
691  typedef typename CellEmbedder::Cell MyCell;
692  typedef typename CellEmbedder::RealPoint RealPoint;
693  typedef typename CellEmbedder::RealVector RealVector;
694  typedef DGtal::uint64_t Number;
695 
696  // Gets the gradient map.
697  GradientMap gradMap = cembedder.gradientMap();
698  // Numbers all vertices.
699  std::map<Vertex, Number> index;
700  Number nbv = 0;
701  for ( ConstIterator it = begin(), it_end = end();
702  it != it_end; ++it )
703  index[ *it ] = nbv++;
704  // Get faces
705  // std::cerr << "- " << nbv << " vertices." << std::endl;
706  FaceSet faces = allClosedFaces();
707  // Compute the number of edges and faces.
708  Number nbe = 0;
709  Number nbf = 0;
710  for ( typename FaceSet::const_iterator
711  itf = faces.begin(), itf_end = faces.end();
712  itf != itf_end; ++itf )
713  {
714  if ( itf->isClosed() )
715  { nbe += itf->nbVertices; ++nbf; }
716  else
717  { nbe += itf->nbVertices - 1; }
718  }
719  // std::cerr << "- " << nbf << " faces." << std::endl;
720  // Outputs OFF header.
721  out << "NOFF" << std::endl
722  << "# Generated by DGtal::DigitalSurface." << std::endl
723  << nbv << " " << nbf << " " << ( nbe / 2 ) << std::endl;
724  // Outputs vertex coordinates (the 3 first ones).
725  const KSpace & K = container().space();
726  RealPoint p;
727  RealVector v;
728  for ( ConstIterator it = begin(), it_end = end();
729  it != it_end; ++it )
730  {
731  MyCell c = K.unsigns( *it );
732  p = cembedder( c );
733  v = gradMap( c );
734  //cembedder.embedSCell( *it, p, v );
735  double norm = v.norm();
736  if ( norm != 0.0 ) v /= norm;
737  out << p[ 0 ] << " " << p[ 1 ] << " " << p[ 2 ] << " "
738  << v[ 0 ] << " " << v[ 1 ] << " " << v[ 2 ] << std::endl;
739  // double areaD = NumberTraits<Coordinate>::castToDouble(area)*2.0;
740  }
741  // Outputs closed faces.
742  for ( typename FaceSet::const_iterator
743  itf = faces.begin(), itf_end = faces.end();
744  itf != itf_end; ++itf )
745  {
746  if ( itf->isClosed() )
747  {
748  out << itf->nbVertices;
749  VertexRange vtcs = verticesAroundFace( *itf );
750  for ( typename VertexRange::const_iterator
751  itv = vtcs.begin(), itv_end = vtcs.end();
752  itv != itv_end; ++itv )
753  out << " " << index[ *itv ];
754  out << std::endl;
755  }
756  }
757 }
758 
759 //-----------------------------------------------------------------------------
760 template <typename TDigitalSurfaceContainer>
761 template <typename SCellEmbedderWithGradientMap>
762 void
763 DGtal::DigitalSurface<TDigitalSurfaceContainer>::
764 exportAs3DNOFF
765 ( std::ostream & out,
766  const SCellEmbedderWithGradientMap & scembedder ) const
767 {
768  BOOST_CONCEPT_ASSERT(( concepts::CSCellEmbedder< SCellEmbedderWithGradientMap > ));
769  BOOST_CONCEPT_ASSERT(( concepts::CWithGradientMap< SCellEmbedderWithGradientMap > ));
770 
771  typedef typename SCellEmbedderWithGradientMap::GradientMap GradientMap;
772  typedef typename SCellEmbedderWithGradientMap::SCell MySCell;
773  typedef typename SCellEmbedderWithGradientMap::RealPoint RealPoint;
774  typedef typename SCellEmbedderWithGradientMap::RealVector RealVector;
775  typedef DGtal::uint64_t Number;
776 
777  // Gets the gradient map.
778  GradientMap gradMap = scembedder.gradientMap();
779  // Numbers all vertices.
780  std::map<Vertex, Number> index;
781  Number nbv = 0;
782  for ( ConstIterator it = begin(), it_end = end();
783  it != it_end; ++it )
784  index[ *it ] = nbv++;
785  // Get faces
786  // std::cerr << "- " << nbv << " vertices." << std::endl;
787  FaceSet faces = allClosedFaces();
788  // Compute the number of edges and faces.
789  Number nbe = 0;
790  Number nbf = 0;
791  for ( typename FaceSet::const_iterator
792  itf = faces.begin(), itf_end = faces.end();
793  itf != itf_end; ++itf )
794  {
795  if ( itf->isClosed() )
796  { nbe += itf->nbVertices; ++nbf; }
797  else
798  { nbe += itf->nbVertices - 1; }
799  }
800  // std::cerr << "- " << nbf << " faces." << std::endl;
801  // Outputs OFF header.
802  out << "NOFF" << std::endl
803  << "# Generated by DGtal::DigitalSurface." << std::endl
804  << nbv << " " << nbf << " " << ( nbe / 2 ) << std::endl;
805  // Outputs vertex coordinates (the 3 first ones).
806  RealPoint p;
807  RealVector v;
808  for ( ConstIterator it = begin(), it_end = end();
809  it != it_end; ++it )
810  {
811  MySCell c = *it;
812  p = scembedder( c );
813  v = gradMap( c );
814  //cembedder.embedSCell( *it, p, v );
815  double norm = v.norm();
816  if ( norm != 0.0 ) v /= norm;
817  out << p[ 0 ] << " " << p[ 1 ] << " " << p[ 2 ] << " "
818  << v[ 0 ] << " " << v[ 1 ] << " " << v[ 2 ] << std::endl;
819  // double areaD = NumberTraits<Coordinate>::castToDouble(area)*2.0;
820  }
821  // Outputs closed faces.
822  for ( typename FaceSet::const_iterator
823  itf = faces.begin(), itf_end = faces.end();
824  itf != itf_end; ++itf )
825  {
826  if ( itf->isClosed() )
827  {
828  out << itf->nbVertices;
829  VertexRange vtcs = verticesAroundFace( *itf );
830  for ( typename VertexRange::const_iterator
831  itv = vtcs.begin(), itv_end = vtcs.end();
832  itv != itv_end; ++itv )
833  out << " " << index[ *itv ];
834  out << std::endl;
835  }
836  }
837 }
838 
839 //-----------------------------------------------------------------------------
840 template <typename TDigitalSurfaceContainer>
841 template <typename CellEmbedder>
842 void
843 DGtal::DigitalSurface<TDigitalSurfaceContainer>::
844 exportEmbeddedIteratedSurfaceAs3DNOFF
845 ( std::ostream & out,
846  const CellEmbedder & cembedder ) const
847 {
848  typedef DGtal::uint64_t Number;
849  // Numbers all vertices.
850  std::map<Vertex, Number> index;
851  Number nbv = 0;
852  for ( ConstIterator it = begin(), it_end = end();
853  it != it_end; ++it )
854  index[ *it ] = nbv++;
855  // Get faces
856  // std::cerr << "- " << nbv << " vertices." << std::endl;
857  FaceSet faces = allClosedFaces();
858  // Compute the number of edges and faces.
859  Number nbe = 0;
860  Number nbf = 0;
861  for ( typename FaceSet::const_iterator
862  itf = faces.begin(), itf_end = faces.end();
863  itf != itf_end; ++itf )
864  {
865  if ( itf->isClosed() )
866  { nbe += itf->nbVertices; ++nbf; }
867  else
868  { nbe += itf->nbVertices - 1; }
869  }
870  // std::cerr << "- " << nbf << " faces." << std::endl;
871  // Outputs OFF header.
872  out << "NOFF" << std::endl
873  << "# Generated by DGtal::DigitalSurface." << std::endl
874  << nbv << " " << nbf << " " << ( nbe / 2 ) << std::endl;
875  // Outputs vertex coordinates (the 3 first ones).
876  typedef typename CellEmbedder::RealPoint RealPoint;
877  typedef typename CellEmbedder::RealVector RealVector;
878  const KSpace & K = container().space();
879  RealPoint p;
880  RealVector v;
881  for ( ConstIterator it = begin(), it_end = end();
882  it != it_end; ++it )
883  {
884  cembedder.embedSurfel( it, p, v );
885  double norm = v.norm();
886  if ( norm != 0.0 ) v /= norm;
887  out << p[ 0 ] << " " << p[ 1 ] << " " << p[ 2 ] << " "
888  << v[ 0 ] << " " << v[ 1 ] << " " << v[ 2 ] << std::endl;
889  // double areaD = NumberTraits<Coordinate>::castToDouble(area)*2.0;
890  }
891  // Outputs closed faces.
892  for ( typename FaceSet::const_iterator
893  itf = faces.begin(), itf_end = faces.end();
894  itf != itf_end; ++itf )
895  {
896  if ( itf->isClosed() )
897  {
898  out << itf->nbVertices;
899  VertexRange vtcs = verticesAroundFace( *itf );
900  for ( typename VertexRange::const_iterator
901  itv = vtcs.begin(), itv_end = vtcs.end();
902  itv != itv_end; ++itv )
903  out << " " << index[ *itv ];
904  out << std::endl;
905  }
906  }
907 }
908 
909 
910 
911 
912 ///////////////////////////////////////////////////////////////////////////////
913 // Implementation of inline functions //
914 
915 template <typename TDigitalSurfaceContainer>
916 inline
917 std::ostream&
918 DGtal::operator<< ( std::ostream & out,
919  const DigitalSurface<TDigitalSurfaceContainer> & object )
920 {
921  object.selfDisplay( out );
922  return out;
923 }
924 
925 // //
926 ///////////////////////////////////////////////////////////////////////////////
927 
928