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