File: MVC_post_processor_3.h

package info (click to toggle)
cgal 6.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 144,912 kB
  • sloc: cpp: 810,858; ansic: 208,477; sh: 493; python: 411; makefile: 286; javascript: 174
file content (761 lines) | stat: -rw-r--r-- 29,495 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
// Copyright (c) 2016  GeometryFactory (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
//
// $URL: https://github.com/CGAL/cgal/blob/v6.1/Surface_mesh_parameterization/include/CGAL/Surface_mesh_parameterization/MVC_post_processor_3.h $
// $Id: include/CGAL/Surface_mesh_parameterization/MVC_post_processor_3.h b26b07a1242 $
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
// Author(s)     : Mael Rouxel-Labbé

#ifndef CGAL_SURFACE_MESH_PARAMETERIZATION_MVC_POST_PROCESSOR_3_H
#define CGAL_SURFACE_MESH_PARAMETERIZATION_MVC_POST_PROCESSOR_3_H

#include <CGAL/license/Surface_mesh_parameterization.h>

#include <CGAL/Surface_mesh_parameterization/internal/Bool_property_map.h>
#include <CGAL/Surface_mesh_parameterization/internal/Containers_filler.h>
#include <CGAL/Surface_mesh_parameterization/internal/kernel_traits.h>

#include <CGAL/Surface_mesh_parameterization/Two_vertices_parameterizer_3.h>
#include <CGAL/Surface_mesh_parameterization/parameterize.h>

#include <CGAL/Weights/tangent_weights.h>
#include <CGAL/Constrained_triangulation_2.h>
#include <CGAL/Constrained_Delaunay_triangulation_2.h>
#include <CGAL/Polygon_mesh_processing/border.h>
#include <CGAL/Triangulation_vertex_base_with_info_2.h>
#include <CGAL/Triangulation_face_base_with_info_2.h>

#ifdef CGAL_EIGEN3_ENABLED
#include <CGAL/Eigen_solver_traits.h>
#endif

#include <CGAL/Default.h>

#include <unordered_set>
#include <vector>
#include <fstream>
#include <iostream>

/// \file MVC_post_processor_3.h

// @todo Determine the proper name of this file
// @todo Handle non-simple boundary

namespace CGAL {

namespace Surface_mesh_parameterization {

// ------------------------------------------------------------------------------------
// Declaration
// ------------------------------------------------------------------------------------

///
/// The class `MVC_post_processor_3` implements
/// the *Free boundary linear Parameterization* algorithm \cgalCite{kami2005free}.
///
/// This parameterizer provides a post processing step to other parameterizers
/// that do not necessarily return a valid embedding. It is based on
/// the convexification of the initial (2D) parameterization and the resolution
/// of a linear system with coefficients based on Mean Value Coordinates.
///
/// \cgalModels{Parameterizer_3}
///
/// \tparam TriangleMesh_ must be a model of `FaceGraph`.
///
/// \tparam SolverTraits_ must be a model of `SparseLinearAlgebraTraits_d`.<br>
///         <b>%Default:</b> If \ref thirdpartyEigen "Eigen" 3.1 (or greater) is available
///         and `CGAL_EIGEN3_ENABLED` is defined, then an overload of `Eigen_solver_traits`
///         is provided as default parameter:
/// \code
///   CGAL::Eigen_solver_traits<
///           Eigen::BiCGSTAB<Eigen_sparse_matrix<double>::EigenType,
///                           Eigen::IncompleteLUT< double > > >
/// \endcode
///
/// \sa `CGAL::Surface_mesh_parameterization::ARAP_parameterizer_3<TriangleMesh, BorderParameterizer_, Solver_traits>`
///
template < class TriangleMesh_,
           class SolverTraits_ = Default>
class MVC_post_processor_3
{
public:
#ifndef DOXYGEN_RUNNING
  typedef typename Default::Get<
    SolverTraits_,
  #if defined(CGAL_EIGEN3_ENABLED)
    CGAL::Eigen_solver_traits<
      Eigen::BiCGSTAB<Eigen_sparse_matrix<double>::EigenType,
                      Eigen::IncompleteLUT<double> > >
  #else
    SolverTraits_ // no parameter provided, and Eigen is not enabled: so don't compile!
  #endif
  >::type                                                     Solver_traits;
#else
  /// Solver traits type
  typedef SolverTraits_                                       Solver_traits;
#endif

  /// Triangle mesh type
  typedef TriangleMesh_                                       Triangle_mesh;

  typedef TriangleMesh_                                       TriangleMesh;

// Private types
private:
  // This class
  typedef MVC_post_processor_3<Triangle_mesh, Solver_traits>  Self;

// Private types
private:
  typedef typename boost::graph_traits<Triangle_mesh>::vertex_descriptor    vertex_descriptor;
  typedef typename boost::graph_traits<Triangle_mesh>::halfedge_descriptor  halfedge_descriptor;
  typedef typename boost::graph_traits<Triangle_mesh>::face_descriptor      face_descriptor;
  typedef typename boost::graph_traits<Triangle_mesh>::face_iterator        face_iterator;
  typedef typename boost::graph_traits<Triangle_mesh>::vertex_iterator      vertex_iterator;

  typedef std::unordered_set<vertex_descriptor>         Vertex_set;
  typedef std::vector<face_descriptor>                  Faces_vector;

  // Traits subtypes:
  typedef typename internal::Kernel_traits<Triangle_mesh>::Kernel   Kernel;
  typedef typename Kernel::FT                                       NT;
  typedef typename Kernel::Point_2                                  Point_2;
  typedef typename Kernel::Vector_2                                 Vector_2;
  typedef typename Kernel::Segment_2                                Segment_2;

  // Solver traits subtypes:
  typedef typename Solver_traits::Vector                            Vector;
  typedef typename Solver_traits::Matrix                            Matrix;

  // Types used for the convexification of the mesh
    // Each triangulation vertex is associated its corresponding vertex_descriptor
  typedef CGAL::Triangulation_vertex_base_with_info_2<vertex_descriptor, Kernel>  Vb;
    // Each triangulation face is associated a color (inside/outside information)
  typedef CGAL::Triangulation_face_base_with_info_2<int, Kernel>                  Fb;
  typedef CGAL::Constrained_triangulation_face_base_2<Kernel, Fb>                 Cfb;
  typedef CGAL::Triangulation_data_structure_2<Vb, Cfb>                           TDS;
  typedef CGAL::No_constraint_intersection_requiring_constructions_tag            Itag;

    // Can choose either a triangulation or a Delaunay triangulation
  typedef CGAL::Constrained_triangulation_2<Kernel, TDS, Itag>                    CT;
//  typedef CGAL::Constrained_Delaunay_triangulation_2<Kernel, TDS, Itag>           CT;

// Private fields
private:
  // Traits object to solve a sparse linear system
  Solver_traits m_linearAlgebra;

// Private accessors
private:
  // Get the sparse linear algebra (traits object to access the linear system).
  Solver_traits& get_linear_algebra_traits() { return m_linearAlgebra; }

// Private utility
  // Print the exterior faces of the constrained triangulation.
  template <typename CT>
  void output_ct_exterior_faces(const CT& ct) const
  {
    std::ofstream out("constrained_triangulation_exterior.txt");
    typename CT::Finite_faces_iterator fit = ct.finite_faces_begin(),
                                       fend = ct.finite_faces_end();
    for(; fit!=fend; ++fit) {
      if(fit->info() != -1) // only output exterior (finite) faces
        continue;

      out << "4 ";
      for(std::size_t i=0; i<4; ++i) {
        out << fit->vertex(i%3)->point() << " 0 ";
      }
      out << '\n';
    }
    out << std::endl;
  }

  // Copy the data from two vectors to the UVmap.
  template <typename VertexUVMap,
            typename VertexIndexMap>
  void assign_solution(const Vector& Xu,
                       const Vector& Xv,
                       const Vertex_set& vertices,
                       VertexUVMap uvmap,
                       const VertexIndexMap vimap) const
  {
    for(vertex_descriptor vd : vertices) {
      int index = get(vimap, vd);
      NT u = Xu(index);
      NT v = Xv(index);
      put(uvmap, vd, Point_2(u, v));
    }
  }

// Private operations
private:
  // Store the vertices and faces of the mesh in memory.
  void initialize_containers(const Triangle_mesh& mesh,
                             halfedge_descriptor bhd,
                             Vertex_set& vertices,
                             Faces_vector& faces) const
  {
    internal::Containers_filler<Triangle_mesh> fc(mesh, vertices, &faces);
    CGAL::Polygon_mesh_processing::connected_component(
                                      face(opposite(bhd, mesh), mesh),
                                      mesh,
                                      boost::make_function_output_iterator(fc));
  }

  // Checks whether the polygon's border is simple.
  template <typename VertexUVMap>
  bool is_polygon_simple(const Triangle_mesh& mesh,
                         halfedge_descriptor bhd,
                         const VertexUVMap uvmap) const
  {
    // @fixme inefficient: use sweep line algorithms instead of brute force

    for(halfedge_descriptor hd_1 : halfedges_around_face(bhd, mesh)) {
      for(halfedge_descriptor hd_2 : halfedges_around_face(bhd, mesh)) {
        if(hd_1 == hd_2 || // equality
           next(hd_1, mesh) == hd_2 || next(hd_2, mesh) == hd_1) // adjacency
          continue;

        if(CGAL::do_intersect(Segment_2(get(uvmap, source(hd_1, mesh)),
                                        get(uvmap, target(hd_1, mesh))),
                              Segment_2(get(uvmap, source(hd_2, mesh)),
                                        get(uvmap, target(hd_2, mesh))))) {
#ifdef CGAL_SMP_ARAP_DEBUG
          std::ofstream out("non-simple.txt"); // polygon lines
          out << "2 " << get(uvmap, source(hd_1, mesh)) << " 0 "
                      << get(uvmap, target(hd_1, mesh)) << " 0" << std::endl;
          out << "2 " << get(uvmap, source(hd_2, mesh)) << " 0 "
                      << get(uvmap, target(hd_2, mesh)) << " 0" << std::endl;
#endif
          return false;
        }
      }
    }
    return true;
  }

  // Spread the inside / outside coloring from a Face to its neighbors
  // depending on whether the common edge is constrained.
  template <typename CT>
  void spread(CT& ct,
              const typename CT::Face_handle fh) const
  {
    typedef typename CT::Edge           Edge;
    typedef typename CT::Face_handle    Face_handle;

    int fh_color = fh->info();
    CGAL_precondition(fh_color != 0); // fh must be colored

    // look at the three neighbors for potential further spreading
    for(int i=0; i<3; ++i)
    {
      // ignore infinite faces and faces that already have a color
      Face_handle neigh_fh = fh->neighbor(i);

      if(ct.is_infinite(neigh_fh)) // infinite
        continue;

      if(neigh_fh->info() != 0) // already colored
        continue;

      bool is_common_edge_constrained = ct.is_constrained(Edge(fh, i));

      // Only constrain the exterior faces of the ct; since we have started
      // from an exterior face, we must not go over any constrained edge
      if(is_common_edge_constrained)
        continue;
      else
        neigh_fh->info() = fh_color;

      spread(ct, neigh_fh);
    }
  }

  // Triangulate the convex hull of the border of the parameterization.
  template <typename CT,
            typename VertexUVMap>
  Error_code triangulate_convex_hull(const Triangle_mesh& mesh,
                                     halfedge_descriptor bhd,
                                     const VertexUVMap uvmap,
                                     CT& ct) const
  {
    // Build the constrained triangulation

    // Since the border is closed and we are interested in triangles that are outside
    // of the border, we actually only need to insert points on the border
    for(halfedge_descriptor hd : halfedges_around_face(bhd, mesh)) {
      vertex_descriptor s = source(hd, mesh);
      const Point_2& sp = get(uvmap, s);

      typename CT::Vertex_handle vh = ct.insert(sp);
      vh->info() = s;
    }

    // Insert constraints (the border)
    for(halfedge_descriptor hd : halfedges_around_face(bhd, mesh)) {
      vertex_descriptor s = source(hd, mesh), t = target(hd, mesh);
      const Point_2& sp = get(uvmap, s), tp = get(uvmap, t);

      ct.insert_constraint(sp, tp);
    }

#ifdef CGAL_SMP_ARAP_DEBUG
    std::ofstream out("constrained_triangulation.cgal");
    out << ct;
#endif

    return OK;
  }

  // Color the (finite) faces of the constrained triangulation with an outside (-1) tag
  template <typename CT>
  Error_code color_faces(CT& ct) const
  {
    typedef typename CT::Edge                               Edge;
    typedef typename CT::Face_handle                        Face_handle;

    // Initialize all colors to 0
    typename CT::Finite_faces_iterator fit = ct.finite_faces_begin(),
                                       fend = ct.finite_faces_end();
    for(; fit!=fend; ++fit)
      fit->info() = 0;

    // start from infinite faces and check if the neighboring finite face is
    // inside or outside 'mesh'. If it is outside, mark it and spread to other
    // neighboring exterior faces
    typename CT::Vertex_handle infinite_vertex = ct.infinite_vertex();
    typename CT::Face_circulator fc = ct.incident_faces(infinite_vertex), done(fc);
    do {
      CGAL_precondition(ct.is_infinite(fc));
      int index_of_inf_vertex = fc->index(infinite_vertex);

      Face_handle mirror_face = fc->neighbor(index_of_inf_vertex);
      if(mirror_face->info() != 0)
        continue;

      bool is_edge_constrained = ct.is_constrained(Edge(fc, index_of_inf_vertex));
      if(!is_edge_constrained) {
        // edge is not constrained so the face is part of the convex hull but
        // geometrically outside of 'mesh'
        mirror_face->info() = -1; // outside
        spread<CT>(ct, mirror_face);
      }
    } while(++fc != done);

#ifdef CGAL_SMP_ARAP_DEBUG
    // Output the exterior faces of the constrained triangulation
    output_ct_exterior_faces(ct);
#endif

    return OK;
  }

  // Fix vertices that are on the convex hull.
  template <typename CT,
            typename VertexParameterizedMap>
  void fix_convex_hull_border(const CT& ct,
                              VertexParameterizedMap vpmap) const
  {
    // All the vertices incident to the infinite vertex are on the convex hull
    typename CT::Vertex_circulator vc = ct.incident_vertices(ct.infinite_vertex()),
                                   vend = vc;
    do{
      vertex_descriptor vd = vc->info();
      put(vpmap, vd, true);
    } while (++vc != vend);
  }

  void fill_linear_system_matrix_mvc_from_points(const Point_2& pi, int i,
                                                 const Point_2& pj, int j,
                                                 const Point_2& pk, int k,
                                                 Matrix& A) const
  {
    // For MVC, the entry of A(i,j) is - [ tan(gamma_ij/2) + tan(delta_ij)/2 ] / |ij|
    // where gamma_ij and delta_ij are the angles at i around the edge ij

    // This function computes the angle alpha at i, and add
    // -- A(i,j) += tan(alpha / 2) / |ij|
    // -- A(i,k) += tan(alpha / 2) / |ik|
    // -- A(i,i) -= A(i,j) + A(i,k)

    // The other parts of A(i,j) and A(i,k) will be added when this function
    // is called from the neighboring faces of F_ijk that share the vertex i

    // @fixme inefficient: lengths are computed (and inversed!) twice per edge

    // Set w_i_base: - tan(alpha / 2)
    // Match order of the input points to the new weight implementation.
    const Point_2& p = pk;
    const Point_2& q = pi;
    const Point_2& r = pj;
    const CGAL::Weights::Tangent_weight<NT> tangent_weight(p, q, r);

    // Set w_ij in matrix
    const NT w_ij = tangent_weight.get_w_r();
    A.add_coef(i, j, w_ij);

    // Set w_ik in matrix
    const NT w_ik = tangent_weight.get_w_p();
    A.add_coef(i, k, w_ik);

    // Add to w_ii (w_ii = - sum w_ij)
    const NT w_ii = - w_ij - w_ik;
    A.add_coef(i, i, w_ii);
  }

  // Partially fill the matrix coefficients A(i,i), A(i,j) and A(i,k)
  // Precondition: i, j, and k are ordered counterclockwise
  template <typename CT,
            typename VertexUVMap,
            typename VertexIndexMap,
            typename VertexParameterizedMap>
  void fill_linear_system_matrix_mvc_from_ct_vertices(typename CT::Vertex_handle vh_i,
                                                      typename CT::Vertex_handle vh_j,
                                                      typename CT::Vertex_handle vh_k,
                                                      const VertexUVMap uvmap,
                                                      const VertexIndexMap vimap,
                                                      const VertexParameterizedMap vpmap,
                                                      Matrix& A) const
  {
    vertex_descriptor vd_i = vh_i->info();
    vertex_descriptor vd_j = vh_j->info();
    vertex_descriptor vd_k = vh_k->info();

    // Coordinates are grabbed from the uvmap
    const Point_2& pi = get(uvmap, vd_i);
    const Point_2& pj = get(uvmap, vd_j);
    const Point_2& pk = get(uvmap, vd_k);
    int i = get(vimap, vd_i);
    int j = get(vimap, vd_j);
    int k = get(vimap, vd_k);

    // if vh_i is fixed, there is nothing to do: A(i,i)=1 and A(i,j)=0 for j!=i
    if(get(vpmap, vd_i))
    {
      // @fixme inefficient: A(i,i) is written as many times as i has neighbors
      A.set_coef(i, i, 1);
      return;
    }

    // vh_i is NOT fixed
    fill_linear_system_matrix_mvc_from_points(pi, i, pj, j, pk, k, A);
  }

  // Add the corresponding coefficients in A for all the edges of the face fh
  template <typename CT,
            typename VertexUVMap,
            typename VertexIndexMap,
            typename VertexParameterizedMap>
  void fill_linear_system_matrix_mvc_from_ct_face(const CT& CGAL_precondition_code(ct),
                                                  typename CT::Finite_faces_iterator fh,
                                                  const VertexUVMap uvmap,
                                                  const VertexIndexMap vimap,
                                                  const VertexParameterizedMap vpmap,
                                                  Matrix& A) const
  {
    CGAL_precondition(!ct.is_infinite(fh));
    typedef typename CT::Vertex_handle                    Vertex_handle;

    // Doing it explicitly rather than a loop for clarity
    Vertex_handle vh0 = fh->vertex(0);
    Vertex_handle vh1 = fh->vertex(1);
    Vertex_handle vh2 = fh->vertex(2);

    fill_linear_system_matrix_mvc_from_ct_vertices<CT>(vh0, vh1, vh2,
                                                       uvmap, vimap, vpmap, A);
    fill_linear_system_matrix_mvc_from_ct_vertices<CT>(vh1, vh2, vh0,
                                                       uvmap, vimap, vpmap, A);
    fill_linear_system_matrix_mvc_from_ct_vertices<CT>(vh2, vh0, vh1,
                                                       uvmap, vimap, vpmap, A);
  }

  template <typename VertexUVMap,
            typename VertexIndexMap,
            typename VertexParameterizedMap>
  void fill_linear_system_matrix_mvc_from_mesh_halfedge(const Triangle_mesh& mesh,
                                                        halfedge_descriptor hd,
                                                        const VertexUVMap uvmap,
                                                        const VertexIndexMap vimap,
                                                        const VertexParameterizedMap vpmap,
                                                        Matrix& A) const
  {
    vertex_descriptor vd_i = target(hd, mesh);
    vertex_descriptor vd_j = target(next(hd, mesh), mesh);
    vertex_descriptor vd_k = source(hd, mesh);
    const Point_2& pi = get(uvmap, vd_i);
    const Point_2& pj = get(uvmap, vd_j);
    const Point_2& pk = get(uvmap, vd_k);
    int i = get(vimap, vd_i);
    int j = get(vimap, vd_j);
    int k = get(vimap, vd_k);

    // if vh_i is fixed, there is nothing to do: A(i,i)=1 and A(i,j)=0 for j!=i
    if(get(vpmap, vd_i))
    {
      // @fixme inefficient A(i,i) is written as many times as i has neighbors
      A.set_coef(i, i, 1);
      return;
    }

    // Below, vh_i is NOT fixed
    fill_linear_system_matrix_mvc_from_points(pi, i, pj, j, pk, k, A);
  }

  // Fill the matrix A in an MVC linear system with the face 'fd' of 'mesh'.
  template <typename VertexUVMap,
            typename VertexIndexMap,
            typename VertexParameterizedMap>
  void fill_linear_system_matrix_mvc_from_mesh_face(const Triangle_mesh& mesh,
                                                    face_descriptor fd,
                                                    const VertexUVMap uvmap,
                                                    const VertexIndexMap vimap,
                                                    const VertexParameterizedMap vpmap,
                                                    Matrix& A) const
  {
    halfedge_descriptor hd = halfedge(fd, mesh);

    fill_linear_system_matrix_mvc_from_mesh_halfedge(mesh, hd, uvmap, vimap, vpmap, A);
    fill_linear_system_matrix_mvc_from_mesh_halfedge(mesh, next(hd, mesh),
                                                     uvmap, vimap, vpmap, A);
    fill_linear_system_matrix_mvc_from_mesh_halfedge(mesh, prev(hd, mesh),
                                                     uvmap, vimap, vpmap, A);
  }

  // Compute the matrix A in the MVC linear system using the exterior faces
  // of the constrained triangulation 'ct' and the graph 'mesh'.
  template <typename CT,
            typename VertexUVMap,
            typename VertexIndexMap,
            typename VertexParameterizedMap>
  Error_code compute_mvc_matrix(const CT& ct,
                                const Triangle_mesh& mesh,
                                const Faces_vector& faces,
                                const VertexUVMap uvmap,
                                const VertexIndexMap vimap,
                                const VertexParameterizedMap vpmap,
                                Matrix& A) const
  {
    Error_code status = OK;

    // The constrained triangulation has only "real" faces outside of the border
    // of mesh.

    // Thus, coefficients will come from 'ct' for faces that are in the convex hull
    // but not in 'mesh' nor in the holes of 'mesh'.
    // The coefficients will come from 'mesh' for faces that are in the convex hull
    // but not in 'ct'.

    // Loop over the "outside" faces of ct
    typename CT::Finite_faces_iterator fit = ct.finite_faces_begin(),
                                       fend = ct.finite_faces_end();
    for(; fit!=fend; ++fit)
    {
      if(fit->info() != -1) // not an outside face
        continue;

      fill_linear_system_matrix_mvc_from_ct_face(ct, fit, uvmap, vimap, vpmap, A);
    }

    // Loop over the faces of 'mesh'
    for(face_descriptor fd : faces) {
      fill_linear_system_matrix_mvc_from_mesh_face(mesh, fd, uvmap, vimap, vpmap, A);
    }

    return status;
  }

  // Compute the right hand side of a MVC linear system.
  template <typename VertexUVMap,
            typename VertexIndexMap,
            typename VertexParameterizedMap>
  void compute_mvc_rhs(const Vertex_set& vertices,
                       const VertexUVMap uvmap,
                       const VertexIndexMap vimap,
                       const VertexParameterizedMap vpmap,
                       Vector& Bu, Vector& Bv) const
  {
    for(vertex_descriptor vd : vertices) {
      int index = get(vimap, vd);
      const Point_2& uv = get(uvmap, vd);
      if(!get(vpmap, vd)) { // not yet parameterized
        Bu[index] = 0.; // might not be needed
        Bv[index] = 0.;
      } else { // fixed vertices
        Bu[index] = uv.x();
        Bv[index] = uv.y();
      }
    }
  }

  // Solve the two linear systems A*Xu=Bu and A*Xv=Bv.
  Error_code solve_mvc(const Matrix& A,
                       const Vector& Bu, const Vector& Bv,
                       Vector& Xu, Vector& Xv)
  {
    Error_code status = OK;

    double Du, Dv;
    if(!get_linear_algebra_traits().linear_solver(A, Bu, Xu, Du) ||
       !get_linear_algebra_traits().linear_solver(A, Bv, Xv, Dv)) {
      status = ERROR_CANNOT_SOLVE_LINEAR_SYSTEM;
    }

    return status;
  }

  // Color the faces with inside/outside information and fix the border.
  template <typename CT, typename VertexParameterizedMap>
  Error_code prepare_CT_for_parameterization(CT& ct,
                                             VertexParameterizedMap vpmap) const
  {
    Error_code status = OK;

    // Gather the finite faces of the CT that are outside the (main) border of 'mesh'
    status = color_faces(ct);
    if(status != OK)
      return status;

    // Gather the vertices that are on the border of the convex hull and will be fixed
    fix_convex_hull_border(ct, vpmap);

    return status;
  }

  // Run an MVC parameterization on the (2D) ARAP UV map and the convexified mesh.
  template <typename CT,
            typename VertexUVMap,
            typename VertexIndexMap,
            typename VertexParameterizedMap>
  Error_code parameterize_convex_hull_with_MVC(const Triangle_mesh& mesh,
                                               const Vertex_set& vertices,
                                               const Faces_vector& faces,
                                               const CT& ct,
                                               VertexUVMap uvmap,
                                               const VertexIndexMap vimap,
                                               const VertexParameterizedMap vpmap)
  {
    Error_code status = OK;

    // Matrices and vectors needed in the resolution
    int nbVertices = static_cast<int>(vertices.size());
    Matrix A(nbVertices, nbVertices);
    Vector Xu(nbVertices), Xv(nbVertices), Bu(nbVertices), Bv(nbVertices);

    // Compute the (constant) matrix A
    compute_mvc_matrix(ct, mesh, faces, uvmap, vimap, vpmap, A);

    // Compute the right hand side of the linear system
    compute_mvc_rhs(vertices, uvmap, vimap, vpmap, Bu, Bv);

    // Solve the linear system
    status = solve_mvc(A, Bu, Bv, Xu, Xv);
    if(status != OK)
      return status;

    CGAL_postcondition_code
    (
      // make sure that the constrained vertices have not been moved
      for(vertex_descriptor vd : vertices) {
        if(get(vpmap, vd)) {
          int index = get(vimap, vd);
          CGAL_postcondition(std::abs(Xu[index] - Bu[index] ) < 1e-10);
          CGAL_postcondition(std::abs(Xv[index] - Bv[index] ) < 1e-10);
        }
      }
    )

    // Assign the UV values
    assign_solution(Xu, Xv, vertices, uvmap, vimap);

    return OK;
  }

public:
  template <typename VertexUVMap,
            typename VertexIndexMap>
  Error_code parameterize(const Triangle_mesh& mesh,
                          const Vertex_set& vertices,
                          const Faces_vector& faces,
                          halfedge_descriptor bhd,
                          VertexUVMap uvmap,
                          const VertexIndexMap vimap)
  {
    // Check if the border forms a simple polygon.
    // Note that there can be self-intersections in other borders,
    // but it is irrelevant and potential holes do not matter.
    const bool is_param_border_simple = is_polygon_simple(mesh, bhd, uvmap);

    // Not sure how to handle non-simple yet @fixme
    if(!is_param_border_simple) {
#ifdef CGAL_SMP_ARAP_DEBUG
      std::cerr << "Border is not simple!" << std::endl;
#endif
      return ERROR_NON_CONVEX_BORDER;
    }

    // Compute the convex hull of the border of 'mesh'
    CT ct;
    triangulate_convex_hull<CT>(mesh, bhd, uvmap, ct);

    // Prepare the constrained triangulation: collect exterior faces (faces in
    // the convex hull but not -- geometrically -- in 'mesh').
    std::unordered_set<vertex_descriptor> vs;
    internal::Bool_property_map<std::unordered_set<vertex_descriptor> > vpmap(vs);
    prepare_CT_for_parameterization(ct, vpmap);

    // Run the MVC
    parameterize_convex_hull_with_MVC(mesh, vertices, faces, ct, uvmap, vimap, vpmap);

    return OK;
  }

  /// computes a one-to-one mapping from a triangular 2D surface mesh
  /// that is not necessarily embedded to a piece of the 2D space.
  ///
  /// \tparam VertexUVmap must be a model of `ReadWritePropertyMap` with
  ///         `boost::graph_traits<Triangle_mesh>::%vertex_descriptor` as key type and
  ///         %Point_2 (type deduced from `Triangle_mesh` using `Kernel_traits`)
  ///         as value type.
  /// \tparam VertexIndexMap must be a model of `ReadablePropertyMap` with
  ///         `boost::graph_traits<Triangle_mesh>::%vertex_descriptor` as key type and
  ///         a unique integer as value type.
  ///
  /// \param mesh a triangulated surface.
  /// \param bhd a halfedge descriptor on the boundary of `mesh`.
  /// \param uvmap an instantiation of the class `VertexUVmap`.
  /// \param vimap an instantiation of the class `VertexIndexMap`.
  ///
  template <typename VertexUVMap,
            typename VertexIndexMap>
  Error_code parameterize(const Triangle_mesh& mesh,
                          halfedge_descriptor bhd,
                          VertexUVMap uvmap,
                          const VertexIndexMap vimap)
  {
    Vertex_set vertices;
    Faces_vector faces;
    initialize_containers(mesh, bhd, vertices, faces);

    return parameterize(mesh, vertices, faces, bhd, uvmap, vimap);
  }

public:
  /// Constructor
  ///
  /// \param sparse_la %Traits object to access a sparse linear system.
  ///
  MVC_post_processor_3(Solver_traits sparse_la = Solver_traits())
    :
      m_linearAlgebra(sparse_la)
  { }
};

} // namespace Surface_mesh_parameterization

} // namespace CGAL

#endif // CGAL_SURFACE_MESH_PARAMETERIZATION_MVC_POST_PROCESSOR_3_H