DGtal 1.3.0
Loading...
Searching...
No Matches
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//-----------------------------------------------------------------------------
44template <typename TDigitalSurfaceContainer>
45inline
46DGtal::DigitalSurface<TDigitalSurfaceContainer>::~DigitalSurface()
47{
48 if ( myTracker != 0 ) delete myTracker;
49}
50//-----------------------------------------------------------------------------
51template <typename TDigitalSurfaceContainer>
52inline
53DGtal::DigitalSurface<TDigitalSurfaceContainer>::DigitalSurface
54( const DigitalSurface & other )
55 : myContainer( other.myContainer ),
56 myTracker( new DigitalSurfaceTracker( *other.myTracker ) ),
57 myUmbrellaComputer( other.myUmbrellaComputer )
58{
59}
60//-----------------------------------------------------------------------------
61template <typename TDigitalSurfaceContainer>
62inline
63DGtal::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//-----------------------------------------------------------------------------
77template <typename TDigitalSurfaceContainer>
78inline
79DGtal::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//-----------------------------------------------------------------------------
93template <typename TDigitalSurfaceContainer>
94inline
95DGtal::DigitalSurface<TDigitalSurfaceContainer> &
96DGtal::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//-----------------------------------------------------------------------------
109template <typename TDigitalSurfaceContainer>
110inline
111const TDigitalSurfaceContainer &
112DGtal::DigitalSurface<TDigitalSurfaceContainer>::container() const
113{
114 return *myContainer;
115}
116//-----------------------------------------------------------------------------
117template <typename TDigitalSurfaceContainer>
118inline
119TDigitalSurfaceContainer &
120DGtal::DigitalSurface<TDigitalSurfaceContainer>::container()
121{
122 return *myContainer;
123}
124//-----------------------------------------------------------------------------
125template <typename TDigitalSurfaceContainer>
126inline
127typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::ConstIterator
128DGtal::DigitalSurface<TDigitalSurfaceContainer>::begin() const
129{
130 return myContainer->begin();
131}
132//-----------------------------------------------------------------------------
133template <typename TDigitalSurfaceContainer>
134inline
135typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::ConstIterator
136DGtal::DigitalSurface<TDigitalSurfaceContainer>::end() const
137{
138 return myContainer->end();
139}
140//-----------------------------------------------------------------------------
141template <typename TDigitalSurfaceContainer>
142inline
143typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::Size
144DGtal::DigitalSurface<TDigitalSurfaceContainer>::size() const
145{
146 return myContainer->nbSurfels();
147}
148//-----------------------------------------------------------------------------
149template <typename TDigitalSurfaceContainer>
150inline
151typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::Size
152DGtal::DigitalSurface<TDigitalSurfaceContainer>::bestCapacity() const
153{
154 return KSpace::dimension*2 - 2;
155}
156//-----------------------------------------------------------------------------
157template <typename TDigitalSurfaceContainer>
158inline
159typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::Size
160DGtal::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//-----------------------------------------------------------------------------
177template <typename TDigitalSurfaceContainer>
178template <typename OutputIterator>
179inline
180void
181DGtal::DigitalSurface<TDigitalSurfaceContainer>::
182writeNeighbors( 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//-----------------------------------------------------------------------------
197template <typename TDigitalSurfaceContainer>
198template <typename OutputIterator, typename VertexPredicate>
199inline
200void
201DGtal::DigitalSurface<TDigitalSurfaceContainer>::
202writeNeighbors( 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//-----------------------------------------------------------------------------
224template <typename TDigitalSurfaceContainer>
225inline
226typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::ArcRange
227DGtal::DigitalSurface<TDigitalSurfaceContainer>::
228outArcs( 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//-----------------------------------------------------------------------------
245template <typename TDigitalSurfaceContainer>
246inline
247typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::ArcRange
248DGtal::DigitalSurface<TDigitalSurfaceContainer>::
249inArcs( 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//-----------------------------------------------------------------------------
267template <typename TDigitalSurfaceContainer>
268inline
269typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::FaceRange
270DGtal::DigitalSurface<TDigitalSurfaceContainer>::
271facesAroundVertex( 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//-----------------------------------------------------------------------------
312template <typename TDigitalSurfaceContainer>
313inline
314typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::Vertex
315DGtal::DigitalSurface<TDigitalSurfaceContainer>::
316head( 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//-----------------------------------------------------------------------------
325template <typename TDigitalSurfaceContainer>
326inline
327typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::Vertex
328DGtal::DigitalSurface<TDigitalSurfaceContainer>::
329tail( const Arc & a ) const
330{
331 return a.base;
332}
333//-----------------------------------------------------------------------------
334template <typename TDigitalSurfaceContainer>
335inline
336typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::Arc
337DGtal::DigitalSurface<TDigitalSurfaceContainer>::
338opposite( 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//-----------------------------------------------------------------------------
355template <typename TDigitalSurfaceContainer>
356inline
357typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::Arc
358DGtal::DigitalSurface<TDigitalSurfaceContainer>::
359arc( 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//-----------------------------------------------------------------------------
384template <typename TDigitalSurfaceContainer>
385inline
386typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::FaceRange
387DGtal::DigitalSurface<TDigitalSurfaceContainer>::
388facesAroundArc( 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//-----------------------------------------------------------------------------
405template <typename TDigitalSurfaceContainer>
406inline
407typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::VertexRange
408DGtal::DigitalSurface<TDigitalSurfaceContainer>::
409verticesAroundFace( 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//-----------------------------------------------------------------------------
421template <typename TDigitalSurfaceContainer>
422inline
423typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::FaceSet
424DGtal::DigitalSurface<TDigitalSurfaceContainer>::
425allFaces() 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//-----------------------------------------------------------------------------
436template <typename TDigitalSurfaceContainer>
437inline
438typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::FaceSet
439DGtal::DigitalSurface<TDigitalSurfaceContainer>::
440allClosedFaces() 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//-----------------------------------------------------------------------------
454template <typename TDigitalSurfaceContainer>
455inline
456typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::FaceSet
457DGtal::DigitalSurface<TDigitalSurfaceContainer>::
458allOpenFaces() 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//-----------------------------------------------------------------------------
473template <typename TDigitalSurfaceContainer>
474inline
475typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::Face
476DGtal::DigitalSurface<TDigitalSurfaceContainer>::
477computeFace( 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//-----------------------------------------------------------------------------
511template <typename TDigitalSurfaceContainer>
512inline
513typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::SCell
514DGtal::DigitalSurface<TDigitalSurfaceContainer>::
515separator( 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//-----------------------------------------------------------------------------
530template <typename TDigitalSurfaceContainer>
531inline
532typename DGtal::DigitalSurface<TDigitalSurfaceContainer>::SCell
533DGtal::DigitalSurface<TDigitalSurfaceContainer>::
534pivot( 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 */
550template <typename TDigitalSurfaceContainer>
551inline
552void
553DGtal::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 */
562template <typename TDigitalSurfaceContainer>
563inline
564bool
565DGtal::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*/
575template <typename TDigitalSurfaceContainer>
576void
577DGtal::DigitalSurface<TDigitalSurfaceContainer>::
578exportSurfaceAs3DOFF ( 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//-----------------------------------------------------------------------------
635template <typename TDigitalSurfaceContainer>
636template <typename CellEmbedder>
637void
638DGtal::DigitalSurface<TDigitalSurfaceContainer>::
639exportEmbeddedSurfaceAs3DOFF
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//-----------------------------------------------------------------------------
701template <typename TDigitalSurfaceContainer>
702template <typename CellEmbedder>
703void
704DGtal::DigitalSurface<TDigitalSurfaceContainer>::
705exportEmbeddedSurfaceAs3DNOFF
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//-----------------------------------------------------------------------------
782template <typename TDigitalSurfaceContainer>
783template <typename SCellEmbedderWithGradientMap>
784void
785DGtal::DigitalSurface<TDigitalSurfaceContainer>::
786exportAs3DNOFF
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//-----------------------------------------------------------------------------
862template <typename TDigitalSurfaceContainer>
863template <typename CellEmbedder>
864void
865DGtal::DigitalSurface<TDigitalSurfaceContainer>::
866exportEmbeddedIteratedSurfaceAs3DNOFF
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
937template <typename TDigitalSurfaceContainer>
938inline
939std::ostream&
940DGtal::operator<< ( std::ostream & out,
941 const DigitalSurface<TDigitalSurfaceContainer> & object )
942{
943 object.selfDisplay( out );
944 return out;
945}
946
947// //
948///////////////////////////////////////////////////////////////////////////////
949
950