1 // Copyright (c) 1997-2000  Max-Planck-Institute Saarbruecken (Germany).
2 // All rights reserved.
3 //
4 // This file is part of CGAL (www.cgal.org).
5 //
6 // $URL: https://github.com/CGAL/cgal/blob/v5.3/Nef_2/include/CGAL/Nef_2/PM_const_decorator.h $
7 // $Id: PM_const_decorator.h 4e519a3 2021-05-05T13:15:37+02:00 Sébastien Loriot
8 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
9 //
10 //
11 // Author(s)     : Michael Seel <seel@mpi-sb.mpg.de>
12 
13 #ifndef CGAL_PM_CONST_DECORATOR_H
14 #define CGAL_PM_CONST_DECORATOR_H
15 
16 #include <CGAL/license/Nef_2.h>
17 
18 
19 #include <CGAL/basic.h>
20 #include <CGAL/Unique_hash_map.h>
21 #include <string>
22 #include <list>
23 #include <sstream>
24 #include <CGAL/Nef_2/Object_index.h>
25 #include <CGAL/Nef_2/iterator_tools.h>
26 #undef CGAL_NEF_DEBUG
27 #define CGAL_NEF_DEBUG 7
28 #include <CGAL/Nef_2/debug.h>
29 
30 #ifndef CGAL_I_DO_WANT_TO_USE_GENINFO
31 #include <boost/any.hpp>
32 #endif
33 
34 #include <CGAL/use.h>
35 
36 namespace CGAL {
37 
38 template <typename Iter, typename Move>
39 inline CGAL::Circulator_tag
query_circulator_or_iterator(const CircFromIt<Iter,Move> &)40 query_circulator_or_iterator(const CircFromIt<Iter,Move>& )
41 { return CGAL::Circulator_tag(); }
42 
43 
44 template <typename HE>
45 class move_halfedge_around_vertex {
46 public:
forward(HE & e)47   void forward(HE& e) const  { e = (e->prev()->opposite()); }
backward(HE & e)48   void backward(HE& e) const { e = (e->opposite()->next()); }
49 };
50 
51 template <typename HE>
52 struct move_halfedge_around_face {
forwardmove_halfedge_around_face53   void forward(HE& e)  const { e = (e->next()); }
backwardmove_halfedge_around_face54   void backward(HE& e) const { e = (e->prev()); }
55 };
56 
57 
58 /*{\Moptions print_title=yes}*/
59 /*{\Moptions constref=yes}*/
60 /*{\Msubst
61 PM_const_decorator#PMConstDecorator
62 PM_decorator#PMDecorator
63 }*/
64 /*{\Moptions outfile=PMConstDecorator.man }*/
65 /*{\Manpage {PMConstDecorator}{}{Topological plane map exploration}{D}}*/
66 
67 template <typename HDS> class PM_decorator;
68 
69 template <typename HDS>
70 class PM_const_decorator
71 { typedef PM_const_decorator<HDS> Self;
72 /*{\Mdefinition An instance |\Mvar| of the data type |\Mname| is a
73 decorator for interfacing the topological structure of a plane map |P|
74 (read-only).
75 
76 A plane map |P| consists of a triple $(V, E, F)$ of vertices, edges, and
77 faces. We collectively call them objects. An edge |e| is a pair of
78 vertices |(v,w)| with incidence operations |v = source(e)|, |w =
79 target(e)|. The list of all edges with source |v| is called the
80 adjacency list |A(v)|.
81 
82 Edges are paired into twins. For each edge |e = (v,w)| there's an edge
83 |twin(e) = (w,v)| and |twin(twin(e)) == e|\cgalFootnote{The existence of
84 the edge pairs makes |P| a bidirected graph, the |twin| links make
85 |P| a map.}.
86 
87 An edge |e = (v,w)| knows two adjacent edges |en = next(e)| and |ep
88 = previous(e)| where |source(en) = w|, |previous(en) = e| and
89 |target(ep) = v| and |next(ep) = e|. By this symmetric |previous-next|
90 relationship all edges are partitioned into face cycles.  Two edges
91 $e$ and $e'$ are in the same face cycle if $e = |next|^*(e')$.  All
92 edges |e| in the same face cycle have the same incident face $f =
93 |face|(e)$. The cyclic order on the adjacency list of a vertex |v =
94 source(e)| is given by |cyclic_adj_succ(e) = twin(previous(e))| and
95 |cyclic_adj_pred(e) = next(twin(e))|.
96 
97 A vertex |v| is embedded via coordinates |point(v)|. By the
98 embedding of its source and target an edge corresponds to a
99 segment. |P| has the property that the embedding is always
100 \emph{order-preserving}.  This means a ray fixed in |point(v)| of a
101 vertex |v| and swept around counterclockwise meets the embeddings of
102 |target(e)| ($e \in A(v)$) in the cyclic order defined by the list
103 order of |A|.
104 
105 The embedded face cycles partition the plane into maximal connected
106 subsets of points. Each such set corresponds to a face. A face is
107 bounded by its incident face cycles. For all the edges in the
108 non-trivial face cycles it holds that the face is left of the edges.
109 There can also be trivial face cycles in form of isolated vertices in
110 the interior of a face. Each such vertex |v| knows its surrounding
111 face |f = face(v)|.
112 
113 We call the embedded map |(V,E)| also the $1$-skeleton of |P|.
114 
115 Plane maps are attributed. To each object $u \in V \cup E \cup F$
116 we attribute a value |mark(u)| of type |Mark|. |Mark| fits the
117 concepts assignable, default-constructible, and equal-comparable.}*/
118 
119 protected:
120 HDS* phds;
121 friend class PM_decorator<HDS>;
122 
123 public:
124 /*{\Mtypes 6}*/
125 typedef HDS Plane_map;
126 /*{\Mtypemember The underlying plane map type}*/
127 
128 typedef typename HDS::Traits Traits;
129 
130 typedef typename Traits::Point  Point;
131 /*{\Mtypemember The point type of vertices.}*/
132 typedef typename Traits::Mark   Mark;
133 /*{\Mtypemember All objects (vertices, edges, faces) are attributed by a
134 |Mark| object.}*/
135 typedef size_t Size_type;
136 #ifdef CGAL_I_DO_WANT_TO_USE_GENINFO
137 /*{\Mtypemember The size type.}*/
138 typedef void*  GenPtr;
139 #else
140 typedef boost::any GenPtr;
141 #endif
142 
143 
144 
145 typedef typename HDS::Vertex                  Vertex;
146 typedef typename HDS::Vertex_base             Vertex_base;
147 typedef typename HDS::Vertex_handle           Vertex_handle;
148 typedef typename HDS::Vertex_const_handle     Vertex_const_handle;
149 typedef typename HDS::Vertex_const_iterator   Vertex_const_iterator;
150 typedef typename HDS::Halfedge                Halfedge ;
151 typedef typename HDS::Halfedge_base           Halfedge_base ;
152 typedef typename HDS::Halfedge_handle         Halfedge_handle;
153 typedef typename HDS::Halfedge_const_handle   Halfedge_const_handle;
154 typedef typename HDS::Halfedge_const_iterator Halfedge_const_iterator;
155 typedef typename HDS::Face                    Face;
156 typedef typename HDS::Face_base               Face_base;
157 typedef typename HDS::Face_handle             Face_handle;
158 typedef typename HDS::Face_const_handle       Face_const_handle;
159 typedef typename HDS::Face_const_iterator     Face_const_iterator;
160 
161 
162 /*{\Mtext Local types are handles, iterators and circulators of the
163 following kind: |Vertex_const_handle|,
164 |Vertex_const_iterator|, |Halfedge_const_handle|,
165 |Halfedge_const_iterator|, |Face_const_handle|, |Face_\-const_\-ite\-rator|.
166 Additionally the following circulators are defined.}*/
167 
168 typedef CircFromIt<
169         Halfedge_const_iterator,
170         move_halfedge_around_vertex<Halfedge_const_iterator> >
171         Halfedge_around_vertex_const_circulator;
172 /*{\Mtypemember circulating the outgoing halfedges in $A(v)$.}*/
173 
174 typedef CircFromIt<
175         Halfedge_const_iterator,
176         move_halfedge_around_face<Halfedge_const_iterator> >
177         Halfedge_around_face_const_circulator;
178 /*{\Mtypemember circulating the halfedges in the face cycle of a
179 face |f|.}*/
180 
181 typedef typename Face::Hole_const_iterator Hole_const_iterator;
182 /*{\Mtypemember iterating all holes of a face |f|. The type is
183 convertible to |Halfedge_const_handle|.}*/
184 
185 typedef typename Face::Isolated_vertex_const_iterator
186         Isolated_vertex_const_iterator;
187 /*{\Mtypemember iterating all isolated vertices of a face |f|.
188 The type generalizes |Vertex_const_handle|.}*/
189 
190 typedef PntItFromVertIt<Vertex_const_iterator,Point>
191   Point_const_iterator;
192 
193 /*{\Mcreation 3}*/
194 
PM_const_decorator()195 PM_const_decorator() : phds(0) {}
PM_const_decorator(const PM_const_decorator<HDS> & D)196 PM_const_decorator(const PM_const_decorator<HDS>& D) :
197     phds(D.phds) {}
198 PM_const_decorator& operator=(
199   const PM_const_decorator<HDS>& D)
200 { phds=D.phds; return *this; }
201 
PM_const_decorator(const Plane_map & P)202 PM_const_decorator(const Plane_map& P)
203 /*{\Mcreate constructs a plane map decorator exploring |P|.}*/
204  : phds(const_cast<HDS*>(&P)) {}
205 
206 /*{\Moperations 4 4}*/
207 
source(Halfedge_const_handle e)208 Vertex_const_handle source(Halfedge_const_handle e) const
209 /*{\Mop returns the source of |e|.}*/
210 { return e->opposite()->vertex(); }
211 
target(Halfedge_const_handle e)212 Vertex_const_handle target(Halfedge_const_handle e) const
213 /*{\Mop returns the target of |e|.}*/
214 { return e->vertex(); }
215 
twin(Halfedge_const_handle e)216 Halfedge_const_handle twin(Halfedge_const_handle e) const
217 /*{\Mop returns the twin of |e|.}*/
218 { return e->opposite(); }
219 
is_isolated(Vertex_const_handle v)220 bool is_isolated(Vertex_const_handle v) const
221 /*{\Mop returns |true| iff $A(v) = \emptyset$.}*/
222 { return v->is_isolated(); }
223 
first_out_edge(Vertex_const_handle v)224 Halfedge_const_handle first_out_edge(Vertex_const_handle v) const
225 /*{\Mop returns one halfedge with source |v|. It's the starting point for
226   the circular iteration over the halfedges with source |v|.
227   \precond |!is_isolated(v)|.}*/
228 { return v->halfedge()->opposite(); }
229 
last_out_edge(Vertex_const_handle v)230 Halfedge_const_handle last_out_edge(Vertex_const_handle v) const
231 /*{\Mop returns the halfedge with source |v| that is the last
232   in the circular iteration before encountering |first_out_edge(v)|
233   again. \precond |!is_isolated(v)|.}*/
234 { return v->halfedge()->next(); }
235 
cyclic_adj_succ(Halfedge_const_handle e)236 Halfedge_const_handle cyclic_adj_succ(
237                         Halfedge_const_handle e) const
238 /*{\Mop returns the edge after |e| in the cyclic ordered adjacency list of
239   |source(e)|.}*/
240 { return e->prev()->opposite(); }
241 
cyclic_adj_pred(Halfedge_const_handle e)242 Halfedge_const_handle cyclic_adj_pred(
243                         Halfedge_const_handle e) const
244 /*{\Mop returns the edge before |e| in the cyclic ordered adjacency list of
245   |source(e)|.}*/
246 { return e->opposite()->next(); }
247 
248 
next(Halfedge_const_handle e)249 Halfedge_const_handle next(Halfedge_const_handle e) const
250 /*{\Mop returns the next edge in the face cycle containing |e|.}*/
251 { return e->next(); }
252 
previous(Halfedge_const_handle e)253 Halfedge_const_handle previous(Halfedge_const_handle e) const
254 /*{\Mop returns the previous edge in the face cycle containing |e|.}*/
255 { return e->prev(); }
256 
face(Halfedge_const_handle e)257 Face_const_handle face(Halfedge_const_handle e) const
258 /*{\Mop returns the face incident to |e|.}*/
259 { return e->face(); }
260 
face(Vertex_const_handle v)261 Face_const_handle face(Vertex_const_handle v) const
262 /*{\Mop returns the face incident to |v|.
263    \precond |is_isolated(v)|.}*/
264 { return v->face(); }
265 
halfedge(Face_const_handle f)266 Halfedge_const_handle halfedge(Face_const_handle f) const
267 /*{\Mop returns a halfedge in the bounding face cycle of |f|
268 (|Halfedge_const_handle()| if there is no bounding face cycle).}*/
269 { return f->halfedge(); }
270 
271 
272 /*{\Mtext \headerline{Iteration} \setopdims{7.5cm}{0cm}}*/
273 
vertices_begin()274 Vertex_const_iterator   vertices_begin() const
275 { return phds->vertices_begin(); }
halfedges_begin()276 Halfedge_const_iterator halfedges_begin() const
277 { return phds->halfedges_begin(); }
faces_begin()278 Face_const_iterator     faces_begin() const
279 { return phds->faces_begin(); }
vertices_end()280 Vertex_const_iterator   vertices_end() const
281 { return phds->vertices_end(); }
halfedges_end()282 Halfedge_const_iterator halfedges_end() const
283 { return phds->halfedges_end(); }
faces_end()284 Face_const_iterator     faces_end() const
285 { return phds->faces_end(); }
points_begin()286 Point_const_iterator points_begin() const
287 { return Point_const_iterator(vertices_begin()); }
points_end()288 Point_const_iterator points_end() const
289 { return Point_const_iterator(vertices_end()); }
290 
291 Halfedge_around_vertex_const_circulator
out_edges(Vertex_const_handle v)292   out_edges(Vertex_const_handle v) const
293 /*{\Mop returns a circulator for the cyclic adjacency list of |v|.}*/
294 { return Halfedge_around_vertex_const_circulator(first_out_edge(v)); }
295 
296 Halfedge_around_face_const_circulator
face_cycle(Face_const_handle f)297   face_cycle(Face_const_handle f) const
298 /*{\Mop returns a circulator for the outer face cycle of |f|.}*/
299 { return Halfedge_around_face_const_circulator(f->halfedge()); }
300 
holes_begin(Face_const_handle f)301 Hole_const_iterator  holes_begin(Face_const_handle f) const
302 /*{\Mop returns an iterator for all holes in the interior of |f|.
303    A |Hole_iterator| can be assigned to a
304    |Halfedge_around_face_const_circulator|.}*/
305 { return f->fc_begin(); }
306 
holes_end(Face_const_handle f)307 Hole_const_iterator  holes_end(Face_const_handle f) const
308 /*{\Mop returns the past-the-end iterator of |f|.}*/
309 { return f->fc_end(); }
310 
311 Isolated_vertex_const_iterator
isolated_vertices_begin(Face_const_handle f)312   isolated_vertices_begin(Face_const_handle f) const
313 /*{\Mop returns an iterator for all isolated vertices in the interior
314    of |f|.}*/
315 { return f->iv_begin(); }
316 
317 Isolated_vertex_const_iterator
isolated_vertices_end(Face_const_handle f)318   isolated_vertices_end(Face_const_handle f) const
319 /*{\Mop returns the past the end iterator of |f|.}*/
320 { return f->iv_end(); }
321 
322 
323 /*{\Mtext \headerline{Associated Information}\setopdims{2.5cm}{4cm}
324 The type |Mark| is the general attribute of an object. The type
325 |GenPtr| is equal to type |void*|.}*/
326 
point(Vertex_const_handle v)327 const Point& point(Vertex_const_handle v) const
328 /*{\Mop returns the embedding of |v|.}*/
329 { return v->point(); }
330 
mark(Vertex_const_handle v)331 const Mark& mark(Vertex_const_handle v) const
332 /*{\Mop returns the mark of |v|.}*/
333 { return v->mark(); }
334 
mark(Halfedge_const_handle e)335 const Mark& mark(Halfedge_const_handle e) const
336 /*{\Mop returns the mark of |e|.}*/
337 { if (&*e < &*(e->opposite())) return e->mark();
338   else return e->opposite()->mark();
339 } // we store the mark in the container with smaller memory address !
340 
mark(Face_const_handle f)341 const Mark& mark(Face_const_handle f) const
342 /*{\Mop returns the mark of |f|.}*/
343 { return f->mark(); }
344 
info(Vertex_const_handle v)345 const GenPtr& info(Vertex_const_handle v) const
346 /*{\Mop returns a generic information slot.}*/
347 { return v->info(); }
348 
info(Halfedge_const_handle e)349 const GenPtr& info(Halfedge_const_handle e) const
350 /*{\Mop returns a generic information slot.}*/
351 { return e->info(); }
352 
info(Face_const_handle f)353 const GenPtr& info(Face_const_handle f) const
354 /*{\Mop returns a generic information slot.}*/
355 { return f->info(); }
356 
357 
358 /*{\Mtext \headerline{Statistics and Integrity}}*/
359 
number_of_vertices()360 Size_type number_of_vertices() const
361 /*{\Mop returns the number of vertices.}*/
362 { return phds->size_of_vertices(); }
363 
number_of_halfedges()364 Size_type number_of_halfedges() const
365 /*{\Mop returns the number of halfedges.}*/
366 { return phds->size_of_halfedges(); }
367 
number_of_edges()368 Size_type number_of_edges() const
369 /*{\Mop returns the number of halfedge pairs.}*/
370 { return phds->size_of_halfedges()/2; }
371 
number_of_faces()372 Size_type number_of_faces() const
373 /*{\Mop returns the number of faces.}*/
374 { return phds->size_of_faces(); }
375 
376 Size_type number_of_face_cycles() const;
377 /*{\Mop returns the number of face cycles.}*/
378 
379 Size_type number_of_connected_components() const;
380 /*{\Mop calculates the number of connected components of |P|.}*/
381 
382 void print_statistics(std::ostream& os = std::cout) const
383 /*{\Mop print the statistics of |P|: the number of vertices, edges, and
384    faces.}*/
385 {
386   os << "Plane Map - Statistics\n";
387   os << "|V| = " << number_of_vertices() << std::endl;
388   os << "|E| = " << number_of_edges()
389   << " (" << 2*number_of_edges() << ")" << std::endl;
390   os << "|F| = " << number_of_faces() << std::endl;
391   os << "|Fcs| = " << number_of_face_cycles() << std::endl << std::endl;
392 }
393 
394 void check_integrity_and_topological_planarity(bool faces=true) const;
395 /*{\Mop checks the link structure and the genus of |P|.}*/
396 
397 }; // PM_const_decorator
398 
399 template <class VH>
PV(VH v)400 std::string PV(VH v)
401 { std::ostringstream os; CGAL::IO::set_pretty_mode(os);
402   if (v != VH()) os << v->point();
403   else           os << "nil";
404   return os.str();
405 }
406 
407 template <class HH>
PE(HH e)408 std::string PE(HH e)
409 { std::ostringstream os;
410   if (e==HH()) return "nil";
411   os << "[" << PV(e->opposite()->vertex()) << ","
412             << PV(e->vertex()) << " "
413   #ifdef CGAL_I_DO_WANT_TO_USE_GENINFO
414   << e->info()
415   #endif
416   << "]";
417   return os.str();
418 }
419 
420 template <typename HDS>
421 void PM_const_decorator<HDS>::
check_integrity_and_topological_planarity(bool faces)422 check_integrity_and_topological_planarity(bool faces) const
423 {
424   CGAL_NEF_TRACEN("check_integrity_and_topological_planarity:");
425   using CGAL::Object_index;
426   Object_index<Vertex_const_iterator>
427     VI(vertices_begin(),vertices_end(),'v');
428   Object_index<Halfedge_const_iterator>
429     EI(halfedges_begin(),halfedges_end(),'e');
430   Object_index<Face_const_iterator>
431     FI(faces_begin(),faces_end(),'f');
432   Vertex_const_handle vit, vend = phds->vertices_end();
433   int iso_vert_num=0;
434   /* check the source links of out edges and count isolated vertices */
435   for (vit = vertices_begin() ; vit != vend; ++vit) {
436     if ( is_isolated(vit) ) {
437       if ( faces )
438         CGAL_assertion_msg( vit->face() != Face_const_handle(),
439                             VI(vit).c_str());
440       ++iso_vert_num;
441     } else {
442       CGAL_assertion_msg( vit->halfedge() != Halfedge_const_handle(),
443       VI(vit).c_str());
444       CGAL_assertion_msg( vit->halfedge()->vertex() == vit ,VI(vit).c_str());
445     }
446   }
447 
448   /* check the bidirected links and the face pointer init */
449   Halfedge_const_iterator eit, eend = phds->halfedges_end();
450   for (eit = phds->halfedges_begin() ; eit != eend; ++eit) {
451     CGAL_assertion( twin(twin(eit)) == eit );
452     CGAL_assertion( eit->vertex() != Vertex_const_handle() );
453     CGAL_assertion( next(eit) != Halfedge_const_handle() );
454     CGAL_assertion( previous(next(eit)) == eit );
455     CGAL_assertion( target(eit) == source(next(eit)) );
456     CGAL_assertion( previous(eit) != Halfedge_const_handle() );
457     CGAL_assertion( next(previous(eit)) == eit );
458     CGAL_assertion( target(previous(eit)) == source(eit) );
459     if ( !faces ) continue;
460     CGAL_assertion( face(eit) != Face_const_handle() );
461     CGAL_assertion( face(next(eit)) == face(eit) );
462     CGAL_assertion( face(previous(eit)) == face(eit) );
463   }
464 
465   bool first=true;
466   int fc_num(0),iv_num(0);
467   Face_const_iterator fit;
468   for (fit = faces_begin(); fit != faces_end(); ++fit) {
469     if (!first && halfedge(fit)!=Halfedge_const_handle()) {
470       CGAL_assertion( face(halfedge(fit))==fit ); ++fc_num;
471     }
472     Hole_const_iterator fcit;
473     for( fcit = holes_begin(fit); fcit != holes_end(fit); ++fcit) {
474       CGAL_assertion( face(fcit)==fit ); ++fc_num;
475     }
476     Isolated_vertex_const_iterator ivit;
477     for(ivit = isolated_vertices_begin(fit);
478         ivit != isolated_vertices_end(fit); ++ivit) {
479       CGAL_assertion( face(ivit)==fit ); ++iv_num;
480     }
481     first=false;
482   }
483 
484   std::size_t v_num = number_of_vertices() - iso_vert_num;
485   std::size_t e_num = number_of_edges();
486   std::size_t c_num = number_of_connected_components() - iso_vert_num;
487   std::size_t f_num = number_of_face_cycles() - c_num + 1;
488   CGAL_USE(v_num);
489   CGAL_USE(e_num);
490   CGAL_USE(f_num);
491   CGAL_NEF_TRACEV(fc_num);CGAL_NEF_TRACEV(iv_num);CGAL_NEF_TRACEV(iso_vert_num);
492   CGAL_NEF_TRACEV(v_num);CGAL_NEF_TRACEV(e_num);CGAL_NEF_TRACEV(c_num);CGAL_NEF_TRACEV(f_num);
493   // CGAL_assertion(fc_num == f_num && iv_num == iso_vert_num);
494   /* this means all face cycles and all isolated vertices are
495      indeed referenced from a face */
496   /* every isolated vertex increases the component count
497        one face cycle per component is redundent except one
498        finally check the Euler formula: */
499   CGAL_assertion( v_num - e_num + f_num == 1 + c_num );
500 }
501 
502 template <typename HDS>
503 typename PM_const_decorator<HDS>::Size_type
504 PM_const_decorator<HDS>::
number_of_face_cycles()505 number_of_face_cycles() const
506 {
507   Size_type fc_num=0;
508   CGAL::Unique_hash_map<Halfedge_const_handle,bool> visited;
509     // init with bool() == false
510   Halfedge_const_iterator eit =  phds->halfedges_begin();
511   Halfedge_const_iterator eend = phds->halfedges_end();
512   for ( ; eit != eend; ++eit) {
513     if (visited[eit]) continue;
514     Halfedge_around_face_const_circulator hfc(eit), hend(hfc);
515     CGAL_For_all(hfc,hend) visited[hfc]=true;
516     ++fc_num;
517   }
518   return fc_num;
519 }
520 
521 template <typename HDS>
522 size_t PM_const_decorator<HDS>::
number_of_connected_components()523 number_of_connected_components() const
524 {
525   typedef Vertex_const_iterator vc_handle;
526   typedef Halfedge_around_vertex_const_circulator hvc_circulator;
527   int comp_num=0;
528   CGAL::Unique_hash_map< vc_handle, bool> handled(false);
529   vc_handle vit = vertices_begin(), vend = vertices_end();
530   for ( ; vit != vend; ++vit) {
531     if (handled[vit]) continue;
532     std::list<vc_handle> L;
533     L.push_back(vit); handled[vit]=true;
534     /* we keep the invariant that all nodes which have been stacked
535        are marked handled */
536     while (!L.empty()) {
537       vc_handle v=L.front(); L.pop_front();
538       if ( is_isolated(v) ) continue;
539       hvc_circulator havc(first_out_edge(v)), hend(havc);
540       CGAL_For_all(havc,hend) {
541         if (!handled[target(havc)]) {
542           L.push_back(target(havc)); handled[target(havc)]=true;
543         }
544       }
545     }
546     ++comp_num;
547   }
548   return comp_num;
549 }
550 
551 struct KERNELPNT {
552   template <typename PNT>
operatorKERNELPNT553   std::string operator() (const PNT& p) const
554   { std::ostringstream os;
555     os << "(" << CGAL::to_double(p.x()) << ","
556               << CGAL::to_double(p.y()) << ")";
557     return os.str();
558   }
559 };
560 
561 template <typename PMCDEC, typename POINTDA>
print_as_leda_graph(std::ostream & os,const PMCDEC & D,const POINTDA & P)562 void print_as_leda_graph(std::ostream& os, const PMCDEC& D,
563   const POINTDA& P)
564 {
565   typedef typename PMCDEC::Vertex_const_iterator
566   Vertex_const_iterator;
567   typedef typename PMCDEC::Halfedge_const_iterator
568   Halfedge_const_iterator;
569   int vn(1), en(1);
570   CGAL::Unique_hash_map<Vertex_const_iterator,int>   v_num;
571   CGAL::Unique_hash_map<Halfedge_const_iterator,int> e_num;
572   os << "LEDA.GRAPH\n" << "point\n" << "int\n";
573   os << D.number_of_vertices() << std::endl;
574   Vertex_const_iterator vit;
575   for (vit = D.vertices_begin(); vit != D.vertices_end(); ++vit) {
576     v_num[vit] = vn++;
577     os << "|{(" << P(D.point(vit)) << ")}|\n";
578      typename PMCDEC::Halfedge_around_vertex_const_circulator
579        ecirc(D.first_out_edge(vit)),ecend(ecirc);
580     int l=0;
581     CGAL_For_all(ecirc,ecend) e_num[ecirc]=l++;
582   }
583   os << 2* D.number_of_edges() << std::endl;
584   Halfedge_const_iterator eit;
585   for (eit = D.halfedges_begin(); eit != D.halfedges_end(); ++eit) {
586     e_num[eit] = en++;
587   }
588   for (eit = D.halfedges_begin(); eit != D.halfedges_end(); ++eit) {
589     os << v_num[D.source(eit)] << " "
590        << v_num[D.target(eit)] << " "
591        << e_num[D.twin(eit)]   << " ";
592     os << "|{" << e_num[eit] << "}|\n";
593   }
594   os << std::flush;
595 }
596 
597 
598 
599 } //namespace CGAL
600 #endif // CGAL_PM_CONST_DECORATOR_H
601