File: Parameterization_mesh_patch_3.h

package info (click to toggle)
cgal 3.2.1-2
  • links: PTS
  • area: non-free
  • in suites: etch, etch-m68k
  • size: 47,752 kB
  • ctags: 72,510
  • sloc: cpp: 397,707; ansic: 10,393; sh: 4,232; makefile: 3,713; perl: 394; sed: 9
file content (968 lines) | stat: -rw-r--r-- 43,255 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
// Copyright (c) 2005  INRIA (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org); you may redistribute it under
// the terms of the Q Public License version 1.0.
// See the file LICENSE.QPL distributed with CGAL.
//
// Licensees holding a valid commercial license may use this file in
// accordance with the commercial license agreement provided with the software.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// $URL: svn+ssh://scm.gforge.inria.fr/svn/cgal/branches/CGAL-3.2-branch/Surface_mesh_parameterization/include/CGAL/Parameterization_mesh_patch_3.h $
// $Id: Parameterization_mesh_patch_3.h 29301 2006-03-09 17:15:04Z lsaboret $
//
//
// Author(s)     : Laurent Saboret, Pierre Alliez, Bruno Levy


#ifndef CGAL_PARAMETERIZATION_MESH_PATCH_3_H
#define CGAL_PARAMETERIZATION_MESH_PATCH_3_H

#include <CGAL/iterator.h>
#include <CGAL/circulator.h>
#include <CGAL/Convertible_iterator_project.h>
#include <CGAL/Convertible_circulator_project.h>
#include <CGAL/Convertible_filter_iterator.h>
#include <CGAL/Param_mesh_patch_vertex.h>
#include <CGAL/Param_mesh_patch_iterators.h>
#include <CGAL/Param_mesh_patch_circulators.h>

#include <CGAL/surface_mesh_parameterization_assertions.h>

CGAL_BEGIN_NAMESPACE


/// Parameterization_mesh_patch_3 is a Decorator class to "virtually" cut a patch
/// in a ParameterizationPatchableMesh_3 3D surface. Only the patch is exported,
/// making the 3D surface look like a topological disk.
///
/// The input mesh can be of any genus, but it has to come with a "seam" that
/// describes the border of a topological disc. This border may be an actual
/// border of the mesh or a virtual border.
///
/// Concept:
/// Model of ParameterizationMesh_3 concept, whose purpose is to allow
/// the Surface_mesh_parameterization package to access meshes in a uniform manner.
///
/// Design Pattern:
/// Parameterization_mesh_patch_3 is a Decorator [GHJV95]: it changes the behavior
/// of a ParameterizationPatchableMesh_3 3D surface while keeping its
/// ParameterizationMesh_3 interface.

template<class ParameterizationPatchableMesh_3>
class Parameterization_mesh_patch_3
{
// Private types
private:

    // Forward references
    struct                                  Inner_facets_filter;

    /// Seaming flag.
    enum Seaming_status  { OUTER, INNER, BORDER };

public:

    //*******************************************************************
    /// @name INTERFACE SPECIFIC TO Parameterization_mesh_patch_3
    //*******************************************************************
    //@{

    /// Export template parameter.
    typedef ParameterizationPatchableMesh_3 Adaptor;

    //@} // end of INTERFACE SPECIFIC TO Parameterization_mesh_patch_3

    //*******************************************************************
    /// @name ParameterizationMesh_3 INTERFACE
    //*******************************************************************
    //@{

    /// Number type to represent coordinates.
    typedef typename Adaptor::NT            NT;

    /// 2D point that represents (u,v) coordinates computed
    /// by parameterization methods. Must provide X() and Y() methods.
    typedef typename Adaptor::Point_2       Point_2;
    /// 3D point that represents vertices coordinates. Must provide X() and Y() methods.
    typedef typename Adaptor::Point_3       Point_3;
    /// 2D vector. Must provide X() and Y() methods.
    typedef typename Adaptor::Vector_2      Vector_2;
    /// 3D vector. Must provide X() and Y() methods.
    typedef typename Adaptor::Vector_3      Vector_3;

    /// Opaque type representing a facet of the 3D mesh. No methods are expected.
    typedef typename Adaptor::Facet         Facet;
    /// Handle to a facet. Model of the Handle concept.
    typedef typename Adaptor::Facet_handle  Facet_handle;
    typedef typename Adaptor::Facet_const_handle
                                            Facet_const_handle;
    /// Iterator over all mesh facets. Model of the ForwardIterator concept.
    typedef Convertible_filter_iterator<typename Adaptor::Facet_iterator,
                                        Inner_facets_filter,
                                        Facet_const_handle,
                                        Facet_handle>
                                            Facet_iterator;
    typedef Convertible_filter_iterator<typename Adaptor::Facet_const_iterator,
                                        Inner_facets_filter,
                                        Facet_const_handle>
                                            Facet_const_iterator;

    /// Opaque type representing a vertex of the 3D mesh. No methods are expected.
    typedef Param_mesh_patch_vertex<Adaptor> Vertex;
    /// Handle to a vertex. Model of the Handle concept.
    typedef Param_mesh_patch_vertex_handle<Adaptor>
                                            Vertex_handle;
    typedef Param_mesh_patch_vertex_const_handle<Adaptor>
                                            Vertex_const_handle;
    /// Iterator over all vertices of a mesh. Model of the ForwardIterator concept.
    typedef Param_mesh_patch_vertex_list_iterator<Adaptor>
                                            Vertex_iterator;
    typedef Param_mesh_patch_vertex_list_const_iterator<Adaptor>
                                            Vertex_const_iterator;
    /// Iterator over vertices of the mesh "main border".
    /// Model of the ForwardIterator concept.
    typedef Vertex_iterator                 Border_vertex_iterator;
    typedef Vertex_const_iterator           Border_vertex_const_iterator;
    /// Counter-clockwise circulator over a facet's vertices.
    /// Model of the BidirectionalCirculator concept.
    typedef Mesh_patch_vertex_around_facet_cir<Parameterization_mesh_patch_3,
                                               Vertex_handle,
                                               typename Adaptor::Vertex_around_facet_circulator>
                                            Vertex_around_facet_circulator;
    typedef Mesh_patch_vertex_around_facet_cir<const Parameterization_mesh_patch_3,
                                               Vertex_const_handle,
                                               typename Adaptor::Vertex_around_facet_const_circulator>
                                            Vertex_around_facet_const_circulator;
    /// Clockwise circulator over the vertices incident to a vertex.
    /// Model of the BidirectionalCirculator concept.
    typedef Mesh_patch_vertex_around_vertex_cir<Parameterization_mesh_patch_3,
                                                Vertex_handle,
                                                typename Adaptor::Vertex_around_vertex_circulator,
                                                typename Adaptor::Vertex_handle>
                                            Vertex_around_vertex_circulator;
    typedef Mesh_patch_vertex_around_vertex_cir<const Parameterization_mesh_patch_3,
                                                Vertex_const_handle,
                                                typename Adaptor::Vertex_around_vertex_const_circulator,
                                                typename Adaptor::Vertex_const_handle>
                                            Vertex_around_vertex_const_circulator;

    //@} // end of ParameterizationMesh_3 INTERFACE

// Public operations
public:

    ///******************************************************************
    /// @name INTERFACE SPECIFIC TO Parameterization_mesh_patch_3
    ///******************************************************************
    //@{

    /// Create a Decorator for an existing ParameterizationPatchableMesh_3 mesh.
    /// The input mesh can be of any genus, but it has to come with a "seam" that
    /// describes the border of a topological disc. This border may be an actual
    /// border of the mesh or a virtual border.
    ///
    /// Preconditions:
    /// - first_seam_vertex -> end_seam_vertex defines the outer seam,
    ///   ie Parameterization_mesh_patch_3 will export the "right" of the seam.
    /// - the "seam" is given as a container of Adaptor::Vertex_handle elements.
    template<class InputIterator>
    Parameterization_mesh_patch_3(Adaptor& mesh,
                                  InputIterator first_seam_vertex,
                                  InputIterator end_seam_vertex)
        // Store reference to adapted mesh
      : m_mesh_adaptor(mesh)
    {
        // Set seaming flag of all vertices and edges to INNER, BORDER or OUTER
        // wrt the first_seam_vertex -> end_seam_vertex border
        set_mesh_seaming(first_seam_vertex, end_seam_vertex);

        // Construct the list of all exported vertices, ie INNER and BORDER vertices
        //
        // 1) add inner vertices
        for (typename Adaptor::Vertex_iterator it = mesh.mesh_vertices_begin();
             it != mesh.mesh_vertices_end();
             it++)
        {
            if (m_mesh_adaptor.get_vertex_seaming(it) == INNER)
                m_inner_and_border_vertices.push_back( Vertex(it) );
        }
        // 2) add seam vertices, wrt outer seam/border order
        InputIterator border_it      = first_seam_vertex;
        InputIterator prev_border_it = end_seam_vertex; prev_border_it--;;
        InputIterator next_border_it = first_seam_vertex; next_border_it++;
        while (border_it != end_seam_vertex)
        {
            // Get outer border vertex
            Vertex v;
            // if border vertex
            if (m_mesh_adaptor.get_halfedge_seaming(*border_it, *prev_border_it) != BORDER)
                v = Vertex(*border_it, *prev_border_it, *next_border_it);
            else // if seam vertex
                v = Vertex(*border_it, *next_border_it, *prev_border_it);   // order inverted!

            // Add vertex
            m_inner_and_border_vertices.push_back(v);

            // Increment iterators
            border_it++;
            //
            prev_border_it++;
            if (prev_border_it == end_seam_vertex)
                prev_border_it = first_seam_vertex;
            //
            next_border_it++;
            if (next_border_it == end_seam_vertex)
                next_border_it = first_seam_vertex;
        }

        // Initialize m_seam_begin = iterator to beginning of seam/main border
        // inside m_inner_and_border_vertices
        m_seam_begin = mesh_vertices_end();
        for (Vertex_iterator it=mesh_vertices_begin(); it!=mesh_vertices_end(); it++) {
            if (get_vertex_seaming(it) == BORDER) {
                m_seam_begin = it;
                break;
            }
        }

#ifndef NDEBUG
        // Index vertices right away to ease debugging
        index_mesh_vertices();
#endif
    }

    /// Get the decorated mesh.
    Adaptor&       get_decorated_mesh()       { return *m_mesh_adaptor; }
    const Adaptor& get_decorated_mesh() const { return *m_mesh_adaptor; }

    //@} // end of INTERFACE SPECIFIC TO Parameterization_mesh_patch_3

    //*******************************************************************
    /// @name ParameterizationMesh_3 INTERFACE
    //*******************************************************************
    //@{

    // MESH INTERFACE

    /// Get iterator over first vertex of mesh.
    Vertex_iterator  mesh_vertices_begin() {
        return m_inner_and_border_vertices.begin();
    }
    Vertex_const_iterator  mesh_vertices_begin() const {
        return m_inner_and_border_vertices.begin();
    }

    /// Get iterator over past-the-end vertex of mesh.
    Vertex_iterator  mesh_vertices_end() {
        return m_inner_and_border_vertices.end();
    }
    Vertex_const_iterator  mesh_vertices_end() const {
        return m_inner_and_border_vertices.end();
    }

    /// Count the number of vertices of the mesh.
    int  count_mesh_vertices() const {
        int index = 0;
        for (Vertex_const_iterator it=mesh_vertices_begin(); it!=mesh_vertices_end(); it++)
            index++;
        return index;
    }

    /// Index vertices of the mesh from 0 to count_mesh_vertices()-1.
    void  index_mesh_vertices ()
    {
        //fprintf(stderr,"  index Parameterization_mesh_patch_3 vertices:\n");
        int index = 0;
        for (Vertex_iterator it=mesh_vertices_begin(); it!=mesh_vertices_end(); it++)
        {
            //fprintf(stderr, "    #%d = {%s,%s,%s}\n",
            //                index,
            //                get_vertex_index_as_string(it->vertex()).c_str(),
            //                get_vertex_index_as_string(it->last_cw_neighbor()).c_str(),
            //                get_vertex_index_as_string(it->first_cw_neighbor()).c_str());
            set_vertex_index(it, index++);
        }
        //fprintf(stderr,"    ok\n");
    }

    /// Get iterator over first vertex of mesh's main border (aka "seam").
    Border_vertex_iterator  mesh_main_border_vertices_begin() {
        return m_seam_begin;
    }
    Border_vertex_const_iterator  mesh_main_border_vertices_begin() const {
        return (Border_vertex_const_iterator) m_seam_begin;
    }

    /// Get iterator over past-the-end vertex of mesh's main border (aka "seam").
    Border_vertex_iterator  mesh_main_border_vertices_end() {
        return mesh_vertices_end();
    }
    Border_vertex_const_iterator  mesh_main_border_vertices_end() const {
        return mesh_vertices_end();
    }

    /// Return the border containing seed_vertex.
    /// Return an empty list if not found.
    std::list<Vertex_handle> get_border(Vertex_handle seed_vertex)
    {
        std::list<Vertex_handle> border;    // returned list

        // If seam vertex, return the seam
        if (is_vertex_on_main_border(seed_vertex))
        {
            for (Border_vertex_iterator it = mesh_main_border_vertices_begin();
                 it != mesh_main_border_vertices_end();
                 it++)
            {
                border.push_back(it);
            }
        }
        else // if vertex on the border of a hole
        {
            // Get list of vertices on this border
            std::list<typename Adaptor::Vertex_handle> adaptor_border =
                m_mesh_adaptor.get_border(seed_vertex->vertex());

            // Copy them into 'border'
            for (typename std::list<typename Adaptor::Vertex_handle>::iterator it = adaptor_border.begin();
                 it != adaptor_border.end();
                 it++)
            {
                // Check that vertex is inner
                assert(m_mesh_adaptor.get_vertex_seaming(*it) == INNER);
                border.push_back( Vertex_handle(*it) );
            }
        }

        return border;
    }

    /// Get iterator over first facet of mesh.
    Facet_iterator  mesh_facets_begin() {
        return Facet_iterator(m_mesh_adaptor.mesh_facets_end(),
                              Inner_facets_filter(*this),
                              m_mesh_adaptor.mesh_facets_begin());
    }
    Facet_const_iterator  mesh_facets_begin() const {
        return Facet_const_iterator(m_mesh_adaptor.mesh_facets_end(),
                                    Inner_facets_filter(*this),
                                    m_mesh_adaptor.mesh_facets_begin());
    }

    /// Get iterator over past-the-end facet of mesh.
    Facet_iterator  mesh_facets_end() {
        return Facet_iterator(m_mesh_adaptor.mesh_facets_end(),
                              Inner_facets_filter(*this));
    }
    Facet_const_iterator  mesh_facets_end() const {
        return Facet_const_iterator(m_mesh_adaptor.mesh_facets_end(),
                                    Inner_facets_filter(*this));
    }

    /// Count the number of facets of the mesh.
    int  count_mesh_facets() const {
        int index = 0;
        for (Facet_const_iterator it=mesh_facets_begin(); it!=mesh_facets_end(); it++)
            index++;
        return index;
    }

    /// Return true of all mesh's facets are triangles.
    bool  is_mesh_triangular() const {
        for (Facet_const_iterator it = mesh_facets_begin(); it != mesh_facets_end(); it++)
            if (count_facet_vertices(it) != 3)
                return false;
        return true;            // mesh is triangular if we reach this point
    }

    /// Count the number of halfedges of the mesh.
    int  count_mesh_halfedges() const {
        int index = 0;
        for (Vertex_const_iterator it=mesh_vertices_begin(); it!=mesh_vertices_end(); it++)
        {
            // Count each neighbor vertex
            Vertex_around_vertex_const_circulator cir = vertices_around_vertex_begin(it);
            Vertex_around_vertex_const_circulator cir_end = cir;
            CGAL_For_all(cir, cir_end)
                index++;
        }
        return index;
    }

    // FACET INTERFACE

    /// Get circulator over facet's vertices.
    Vertex_around_facet_circulator  facet_vertices_begin(Facet_handle facet) {
        CGAL_surface_mesh_parameterization_assertion(is_valid(facet));
        return Vertex_around_facet_circulator(*this, m_mesh_adaptor.facet_vertices_begin(facet));
    }
    Vertex_around_facet_const_circulator  facet_vertices_begin(Facet_const_handle facet) const {
        CGAL_surface_mesh_parameterization_assertion(is_valid(facet));
        return Vertex_around_facet_const_circulator(*this, m_mesh_adaptor.facet_vertices_begin(facet));
    }

    /// Count the number of vertices of a facet.
    int  count_facet_vertices(Facet_const_handle facet) const {
        CGAL_surface_mesh_parameterization_assertion(is_valid(facet));
        int index = 0;
        Vertex_around_facet_const_circulator cir     = facet_vertices_begin(facet),
                                             cir_end = cir;
        CGAL_For_all(cir, cir_end)
            index++;
        return index;
    }

    // VERTEX INTERFACE

    /// Get the 3D position of a vertex.
    Point_3 get_vertex_position(Vertex_const_handle vertex) const {
        CGAL_surface_mesh_parameterization_assertion(is_valid(vertex));
        return m_mesh_adaptor.get_vertex_position(vertex->vertex());
    }

    /// Get/set the 2D position (u/v pair) of a vertex. Default value is undefined.
    Point_2  get_vertex_uv(Vertex_const_handle vertex) const {
        CGAL_surface_mesh_parameterization_assertion(is_valid(vertex));
        return m_mesh_adaptor.get_corners_uv(vertex->vertex(),
                                             vertex->last_cw_neighbor(),
                                             vertex->first_cw_neighbor());
    }
    void  set_vertex_uv(Vertex_handle vertex, const Point_2& uv)
    {
        CGAL_surface_mesh_parameterization_assertion(is_valid(vertex));
        return m_mesh_adaptor.set_corners_uv(vertex->vertex(),
                                             vertex->last_cw_neighbor(),
                                             vertex->first_cw_neighbor(),
                                             uv);
    }

    /// Get/set "is parameterized" field of vertex. Default value is undefined.
    bool  is_vertex_parameterized(Vertex_const_handle vertex) const {
        CGAL_surface_mesh_parameterization_assertion(is_valid(vertex));
        return m_mesh_adaptor.are_corners_parameterized(vertex->vertex(),
                                                        vertex->last_cw_neighbor(),
                                                        vertex->first_cw_neighbor());
    }
    void  set_vertex_parameterized(Vertex_handle vertex, bool parameterized)
    {
        CGAL_surface_mesh_parameterization_assertion(is_valid(vertex));
        return m_mesh_adaptor.set_corners_parameterized(vertex->vertex(),
                                                        vertex->last_cw_neighbor(),
                                                        vertex->first_cw_neighbor(),
                                                        parameterized);
    }

    /// Get/set vertex index. Default value is undefined.
    int  get_vertex_index(Vertex_const_handle vertex) const {
        CGAL_surface_mesh_parameterization_assertion(is_valid(vertex));
        return m_mesh_adaptor.get_corners_index(vertex->vertex(),
                                                vertex->last_cw_neighbor(),
                                                vertex->first_cw_neighbor());
    }
    void  set_vertex_index(Vertex_handle vertex, int index)  {
        CGAL_surface_mesh_parameterization_assertion(is_valid(vertex));
        return m_mesh_adaptor.set_corners_index(vertex->vertex(),
                                                vertex->last_cw_neighbor(),
                                                vertex->first_cw_neighbor(),
                                                index);
    }

    /// Get/set vertex' all purpose tag. Default value is undefined.
    int  get_vertex_tag(Vertex_const_handle vertex) const {
        CGAL_surface_mesh_parameterization_assertion(is_valid(vertex));
        return m_mesh_adaptor.get_corners_tag(vertex->vertex(),
                                              vertex->last_cw_neighbor(),
                                              vertex->first_cw_neighbor());
    }
    void set_vertex_tag(Vertex_handle vertex, int tag) {
        return m_mesh_adaptor.set_corners_tag(vertex->vertex(),
                                              vertex->last_cw_neighbor(),
                                              vertex->first_cw_neighbor(),
                                              tag);
    }

    /// Return true if a vertex belongs to ANY mesh's border.
    bool  is_vertex_on_border(Vertex_const_handle vertex) const {
        CGAL_surface_mesh_parameterization_assertion(is_valid(vertex));
        return is_vertex_on_main_border(vertex) ||
               m_mesh_adaptor.is_vertex_on_border(vertex->vertex());
    }

    /// Return true if a vertex belongs to the UNIQUE mesh's main border
    /// set by the constructor.
    bool  is_vertex_on_main_border(Vertex_const_handle vertex) const {
        CGAL_surface_mesh_parameterization_assertion(is_valid(vertex));
        return get_vertex_seaming(vertex) == BORDER;
    }

    /// Get circulator over the vertices incident to 'vertex'.
    /// 'start_position' defines the optional initial position of the circulator.
    Vertex_around_vertex_circulator vertices_around_vertex_begin(
                            Vertex_handle vertex,
                            Vertex_handle start_position = Vertex_handle())
    {
        CGAL_surface_mesh_parameterization_assertion(is_valid(vertex));
        CGAL_surface_mesh_parameterization_assertion(start_position == NULL ||
                                        is_valid(start_position));

        // If no start position provided, pick one
        if (start_position == NULL)
        {
            // If 'vertex' is an inner vertex, pick any neighbor
            if (vertex->last_cw_neighbor() == NULL)
            {
                typename Adaptor::Vertex_around_vertex_circulator adaptor_circulator
                    = m_mesh_adaptor.vertices_around_vertex_begin(vertex->vertex());
                start_position = get_decorated_inner_vertex(adaptor_circulator,
                                                            vertex->vertex());
            }
            else // If 'vertex' is a seam vertex, pick its last clockwise neighbor
            {
                start_position = get_decorated_border_vertex(vertex->last_cw_neighbor(),
                                                             NULL,
                                                             vertex->vertex());
            }
        }

        return Vertex_around_vertex_circulator(*this, vertex, start_position);
    }
    Vertex_around_vertex_const_circulator vertices_around_vertex_begin(
                                Vertex_const_handle vertex,
                                Vertex_const_handle start_position = Vertex_const_handle()) const
    {
        CGAL_surface_mesh_parameterization_assertion(is_valid(vertex));
        CGAL_surface_mesh_parameterization_assertion(start_position == NULL ||
                                        is_valid(start_position));

        // If no start position provided, pick one
        if (start_position == NULL)
        {
            // If 'vertex' is an inner vertex, pick any neighbor
            if (vertex->last_cw_neighbor() == NULL)
            {
                typename Adaptor::Vertex_around_vertex_const_circulator adaptor_circulator
                    = m_mesh_adaptor.vertices_around_vertex_begin(vertex->vertex());
                start_position = get_decorated_inner_vertex(adaptor_circulator,
                                                            vertex->vertex());
            }
            else // If 'vertex' is a seam vertex, pick its last clockwise neighbor
            {
                start_position = get_decorated_border_vertex(vertex->last_cw_neighbor(),
                                                             NULL,
                                                             vertex->vertex());
            }
        }

        return Vertex_around_vertex_const_circulator(*this, vertex, start_position);
    }

    //@} // end of ParameterizationMesh_3 INTERFACE


// Private operations
private:

    /// Default copy constructor and operator =() are not (yet) implemented.
    Parameterization_mesh_patch_3(const Parameterization_mesh_patch_3& toCopy);
    Parameterization_mesh_patch_3& operator =(const Parameterization_mesh_patch_3& toCopy);

    /// Set seaming flag of all vertices and edges to INNER, BORDER or OUTER
    /// wrt the first_seam_vertex -> end_seam_vertex border
    /// (outer seam edges are marked BORDER).
    ///
    /// Preconditions:
    /// - first_seam_vertex -> end_seam_vertex defines the outer seam,
    ///   ie Parameterization_mesh_patch_3 will export the "right" of the seam.
    /// - the "seam" is given as a container of Adaptor::Vertex_handle elements.
    template<class InputIterator>
    void set_mesh_seaming(InputIterator first_seam_vertex,
                          InputIterator end_seam_vertex)
    {
        // Initialize the seaming flag of all vertices to OUTER
        for (typename Adaptor::Vertex_iterator it = m_mesh_adaptor.mesh_vertices_begin();
             it != m_mesh_adaptor.mesh_vertices_end();
             it++)
        {
             m_mesh_adaptor.set_vertex_seaming(it, OUTER);
        }

        // Initialize the seaming flag of all halfedges to OUTER
        for (typename Adaptor::Vertex_iterator it = m_mesh_adaptor.mesh_vertices_begin();
             it != m_mesh_adaptor.mesh_vertices_end();
             it++)
        {
            // For each neighbor vertex
            typename Adaptor::Vertex_around_vertex_circulator cir, cir_end;
            cir     = m_mesh_adaptor.vertices_around_vertex_begin(it);
            cir_end = cir;
            CGAL_For_all(cir, cir_end)
                m_mesh_adaptor.set_halfedge_seaming(it, cir, OUTER);
        }

        // Set seaming flag of seam vertices to BORDER.
        // Set seaming flag of outer seam edges to BORDER
        // and inner seam vertices to INNER.
        for (InputIterator border_it = first_seam_vertex;
             border_it != end_seam_vertex;
             border_it++)
        {
            // Set vertex seaming flag
            m_mesh_adaptor.set_vertex_seaming(*border_it, BORDER);

            // Get next iterator (looping)
            InputIterator next_border_it = border_it;
            next_border_it++;
            if (next_border_it == end_seam_vertex)
                next_border_it = first_seam_vertex;

            // Set outer seam edge to BORDER
            m_mesh_adaptor.set_halfedge_seaming(*border_it, *next_border_it,
                                                BORDER);

            // Set inner seam edge to INNER (except if also BORDER)
            if (m_mesh_adaptor.get_halfedge_seaming(*next_border_it,
                                                    *border_it) != BORDER) {
                m_mesh_adaptor.set_halfedge_seaming(*next_border_it, *border_it,
                                                    INNER);
            }
        }

        // Set the seaming flag of inner vertices and edges to INNER
        for (InputIterator border_it = first_seam_vertex;
             border_it != end_seam_vertex;
             border_it++)
        {
            // Get next iterator (looping)
            InputIterator next_border_it = border_it;
            next_border_it++;
            if (next_border_it == end_seam_vertex)
                next_border_it = first_seam_vertex;

            // Get inner point at the "right" of *border_it
            // by a counter-clockwise rotation around the next seam vertex
            typename Adaptor::Vertex_around_vertex_circulator cir =
                m_mesh_adaptor.vertices_around_vertex_begin(*next_border_it,
                                                            *border_it);
            cir--;

            // Fill topological disk
            if (m_mesh_adaptor.get_vertex_seaming(cir) != BORDER)
                set_inner_region_seaming(cir);
        }
    }

    /// Set the seaming flag of inner vertices and edges to INNER
    /// by filling the topological disk.
    ///
    /// Preconditions:
    /// - Inner vertices are marked as OUTER, seam vertices as BORDER.
    /// - Inner edges are marked as OUTER,
    ///   outer seam edges as BORDER, inner seam edges as INNER.
    /// - pSeedVertex is in the inner region.
    /// - pSeedVertex != NULL.
    ///
    /// Implementation note:
    /// The seaming status of inner edges is unused, thus this part is not tested.
    ///
    void set_inner_region_seaming(typename Adaptor::Vertex_handle pSeedVertex)
    {
        if (pSeedVertex == NULL)
            return;                 // Gloups... topological disc is empty!

        // List of vertices to flag = pSeedVertex initially
        std::list<typename Adaptor::Vertex_handle> vertices;
        vertices.push_front(pSeedVertex);

        // For each vertex in the list: pop it out, flag it as INNER and
        // add its surrounding vertices to the list
        while (!vertices.empty())
        {
            typename Adaptor::Vertex_handle pVertex = vertices.front();
            vertices.pop_front();
            CGAL_surface_mesh_parameterization_assertion(pVertex != NULL);

            // Flag this vertex as INNER
            if (m_mesh_adaptor.get_vertex_seaming(pVertex) == OUTER)
                m_mesh_adaptor.set_vertex_seaming(pVertex, INNER);
            else
                continue;           // Skip this vertex if it is already done

            // For each neighbor vertex
            typename Adaptor::Vertex_around_vertex_circulator cir, cir_end;
            cir     = m_mesh_adaptor.vertices_around_vertex_begin(pVertex);
            cir_end = cir;
            CGAL_For_all(cir, cir_end)
            {
                // Flag both oriented edges pVertex <-> cir
                m_mesh_adaptor.set_halfedge_seaming(pVertex, cir, INNER);
                m_mesh_adaptor.set_halfedge_seaming(cir, pVertex, INNER);

                // Add surrounding vertices to list without crossing the border
                if (m_mesh_adaptor.get_vertex_seaming(cir) == OUTER)
                    vertices.push_front(cir);
            }
        }
    }

    /// Get facet' seaming status (INNER or OUTER).
    Seaming_status get_facet_seaming(typename Adaptor::Facet_const_handle facet) const
    {
        // do not call is_valid() to avoid an infinite loop
        CGAL_surface_mesh_parameterization_assertion(facet != NULL);

        typename Adaptor::Vertex_around_facet_const_circulator
                            cir = m_mesh_adaptor.facet_vertices_begin(facet);
        CGAL_surface_mesh_parameterization_assertion(cir != NULL);
        return (m_mesh_adaptor.get_vertex_seaming(cir) == OUTER) ?
               OUTER :
               INNER;
    }

    /// Get/set vertex seaming flag,
    /// ie position of the vertex wrt to the UNIQUE main border.
    Seaming_status  get_vertex_seaming(Vertex_const_handle vertex) const {
        CGAL_surface_mesh_parameterization_assertion(is_valid(vertex));
        return (Seaming_status) m_mesh_adaptor.get_vertex_seaming(
                                                    vertex->vertex());
    }
    void set_vertex_seaming(Vertex_handle vertex, Seaming_status seaming) {
        m_mesh_adaptor.set_vertex_seaming(vertex->vertex(), seaming);
    }

    /// Create a patch vertex from an adaptor vertex + one of its neighbors.
    ///
    /// Preconditions:
    /// - adaptor_neighbor is a neighbor of adaptor_vertex.
    /// - (adaptor_vertex, adaptor_neighbor) must NOT be a seam (non-oriented) edge.
    Vertex_const_handle get_decorated_inner_vertex(
                typename Adaptor::Vertex_const_handle adaptor_vertex,
                typename Adaptor::Vertex_const_handle adaptor_neighbor) const
    {
        // We need at least an inner neighbor as input
        assert(m_mesh_adaptor.get_halfedge_seaming(adaptor_vertex,
                                                   adaptor_neighbor) != BORDER
            || m_mesh_adaptor.get_halfedge_seaming(adaptor_neighbor,
                                                   adaptor_vertex) != BORDER);

        // if inner vertex
        if (m_mesh_adaptor.get_vertex_seaming(adaptor_vertex) != BORDER)
        {
            // No extra information needed if inner vertex
            return Vertex_const_handle(adaptor_vertex);
        }
        else // if seam vertex
        {
            // find last neighbor (on seam) for a clockwise rotation
            typename Adaptor::Vertex_around_vertex_const_circulator last_cw_neighbor_cir
                = m_mesh_adaptor.vertices_around_vertex_begin(adaptor_vertex,
                                                              adaptor_neighbor);
            while (m_mesh_adaptor.get_halfedge_seaming(last_cw_neighbor_cir,
                                                       adaptor_vertex) != BORDER)
            {
                last_cw_neighbor_cir++;
            }

            // find first clockwise neighbor (on seam) by a counter-clockwise rotation
            typename Adaptor::Vertex_around_vertex_const_circulator first_cw_neighbor_cir
                = m_mesh_adaptor.vertices_around_vertex_begin(adaptor_vertex,
                                                              adaptor_neighbor);
            while (m_mesh_adaptor.get_halfedge_seaming(adaptor_vertex,
                                                       first_cw_neighbor_cir) != BORDER)
            {
                first_cw_neighbor_cir--;
            }

            // The decorated vertex is then:
            return Vertex_const_handle(adaptor_vertex,
                                       last_cw_neighbor_cir,
                                       first_cw_neighbor_cir);
        }
    }
    Vertex_handle get_decorated_inner_vertex(
                typename Adaptor::Vertex_handle adaptor_vertex,
                typename Adaptor::Vertex_handle adaptor_neighbor)
    {
        // Call the const version of get_decorated_inner_vertex()
        Vertex_const_handle vertex_hdl = get_decorated_inner_vertex(
                        (typename Adaptor::Vertex_const_handle)adaptor_vertex,
                        (typename Adaptor::Vertex_const_handle)adaptor_neighbor);
        return const_cast<Vertex*>(&*vertex_hdl);
    }

    /// Create a patch vertex from a border/seam adaptor vertex
    /// + one of its neighbors on the seam.
    ///
    /// Preconditions:
    /// - adaptor_vertex is a border/seam vertex.
    /// - [first_cw_neighbor, last_cw_neighbor] defines the range
    ///   of the valid neighbors of adaptor_vertex (included) or are NULL.
    /// - either first_cw_neighbor or last_cw_neighbor are not NULL.
    Vertex_const_handle get_decorated_border_vertex(
                typename Adaptor::Vertex_const_handle adaptor_vertex,
                typename Adaptor::Vertex_const_handle last_cw_neighbor,
                typename Adaptor::Vertex_const_handle first_cw_neighbor) const
    {
        assert(adaptor_vertex != NULL);
        assert(last_cw_neighbor != NULL || first_cw_neighbor != NULL);

        assert(last_cw_neighbor == NULL
            || m_mesh_adaptor.get_halfedge_seaming(adaptor_vertex,
                                                   last_cw_neighbor) == BORDER
            || m_mesh_adaptor.get_halfedge_seaming(last_cw_neighbor,
                                                   adaptor_vertex) == BORDER);
        assert(first_cw_neighbor == NULL
            || m_mesh_adaptor.get_halfedge_seaming(adaptor_vertex,
                                                   first_cw_neighbor) == BORDER
            || m_mesh_adaptor.get_halfedge_seaming(first_cw_neighbor,
                                                   adaptor_vertex) == BORDER);

        // If both first_cw_neighbor and last_cw_neighbor are provided
        if (last_cw_neighbor != NULL && first_cw_neighbor != NULL)
        {
            // we're done (quick)
            return Vertex_const_handle(adaptor_vertex,
                                       last_cw_neighbor,
                                       first_cw_neighbor);
        }
        else // if either first_cw_neighbor or last_cw_neighbor is missing
        {
            // search in border vertices list (slow)
            for (Border_vertex_const_iterator it = mesh_main_border_vertices_begin();
                 it != mesh_main_border_vertices_end();
                 it++)
            {
                if (it->vertex() == adaptor_vertex
                 && (last_cw_neighbor == NULL  || it->last_cw_neighbor() == last_cw_neighbor)
                 && (first_cw_neighbor == NULL || it->first_cw_neighbor() == first_cw_neighbor))
                {
                    return it;
                }
            }

            // we should not get here
            assert(false);
            return NULL;
        }
    }
    Vertex_handle get_decorated_border_vertex(
                        typename Adaptor::Vertex_handle adaptor_vertex,
                        typename Adaptor::Vertex_handle last_cw_neighbor,
                        typename Adaptor::Vertex_handle first_cw_neighbor)
    {
        // Call the const version of get_decorated_border_vertex()
        Vertex_const_handle vertex_hdl = get_decorated_border_vertex(
                        (typename Adaptor::Vertex_const_handle)adaptor_vertex,
                        (typename Adaptor::Vertex_const_handle)last_cw_neighbor,
                        (typename Adaptor::Vertex_const_handle)first_cw_neighbor);
        return const_cast<Vertex*>(&*vertex_hdl);
    }

    /// Debug utility: Check if a Parameterization_mesh_patch_3 facet is valid.
    bool is_valid(Facet_const_handle facet) const
    {
        if (facet == NULL)
            return false;
        // outer facets are not exported
        if (get_facet_seaming(facet) != INNER)
            return false;
        // eventually: ok
        return true;
    }

    /// Debug utility: Check if a Parameterization_mesh_patch_3 vertex is valid.
    bool is_valid(Vertex_const_handle vertex) const
    {
        if (vertex == NULL)
            return false;
        // outer vertices are not exported
        if (m_mesh_adaptor.get_vertex_seaming(vertex->vertex()) == OUTER)
            return false;
        // prev/next vertices must be on the main border
        if (vertex->last_cw_neighbor() != NULL &&
            m_mesh_adaptor.get_vertex_seaming(vertex->last_cw_neighbor()) != BORDER)
            return false;
        if (vertex->first_cw_neighbor() != NULL &&
            m_mesh_adaptor.get_vertex_seaming(vertex->first_cw_neighbor()) != BORDER)
            return false;
        // eventually: ok
        return true;
    }

    /// Debug utility: get vertex index as string ("-" if NULL vertex).
    std::string get_vertex_index_as_string(typename Adaptor::Vertex_const_handle vertex) const
    {
        if (vertex == NULL) {
            return std::string("-");
        } else {
            char index_as_string[64];
            CGAL_CLIB_STD::sprintf(index_as_string, "%d", (int)m_mesh_adaptor.get_vertex_index(vertex));
            return std::string(index_as_string);
        }
    }

// Fields
private:

    /// The decorated mesh.
    Adaptor& m_mesh_adaptor;

    /// List of all exported vertices.
    /// Order is: inner vertices, then seam/main border ones.
    Param_mesh_patch_vertex_list<Adaptor> m_inner_and_border_vertices;

    /// Iterator to first seam vertex inside m_inner_and_border_vertices.
    Border_vertex_iterator m_seam_begin;

// Private types
private:

    /// Utility class to generate the Facet_iterator type.
    struct Inner_facets_filter
    {
        Inner_facets_filter(const Parameterization_mesh_patch_3& mesh) : m_mesh_patch(mesh) {}

        /// Return TRUE <=> the facet IS NOT EXPORTED by Parameterization_mesh_patch_3,
        /// ie is out of the topological disc.
        bool operator()(const typename Adaptor::Facet_iterator& f) const       {
            return m_mesh_patch.get_facet_seaming(f) == OUTER;
        }
        bool operator()(const typename Adaptor::Facet_const_iterator& f) const {
            return m_mesh_patch.get_facet_seaming(f) == OUTER;
        }

    private:
        const Parameterization_mesh_patch_3& m_mesh_patch;
    };

// Friends
    friend class Param_mesh_patch_vertex<Adaptor>;
    friend class Param_mesh_patch_vertex_handle<Adaptor>;
    friend class Param_mesh_patch_vertex_const_handle<Adaptor>;
    friend class Param_mesh_patch_vertex_list_iterator<Adaptor>;
    friend class Param_mesh_patch_vertex_list_const_iterator<Adaptor>;
    friend class Mesh_patch_vertex_around_facet_cir<Parameterization_mesh_patch_3,
                                                    Vertex_handle,
                                                    typename Adaptor::Vertex_around_facet_circulator>;
    friend class Mesh_patch_vertex_around_facet_cir<const Parameterization_mesh_patch_3,
                                                    Vertex_const_handle,
                                                    typename Adaptor::Vertex_around_facet_const_circulator>;
    friend class Mesh_patch_vertex_around_vertex_cir<Parameterization_mesh_patch_3,
                                                     Vertex_handle,
                                                     typename Adaptor::Vertex_around_vertex_circulator,
                                                     typename Adaptor::Vertex_handle>;
    friend class Mesh_patch_vertex_around_vertex_cir<const Parameterization_mesh_patch_3,
                                                     Vertex_const_handle,
                                                     typename Adaptor::Vertex_around_vertex_const_circulator,
                                                     typename Adaptor::Vertex_const_handle>;

}; // Parameterization_mesh_patch_3


CGAL_END_NAMESPACE

#endif //CGAL_SURFACE_MESH_PARAMETERIZATION_MESH_PATCH_3_H