File: smooth_shape.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 (229 lines) | stat: -rw-r--r-- 10,269 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
// Copyright (c) 2018-2019 GeometryFactory (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org).
//
// $URL: https://github.com/CGAL/cgal/blob/v6.1/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smooth_shape.h $
// $Id: include/CGAL/Polygon_mesh_processing/smooth_shape.h b26b07a1242 $
// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial
//
//
// Author(s)     : Mael Rouxel-Labbé
//                 Konstantinos Katrioplas (konst.katrioplas@gmail.com)

#ifndef CGAL_POLYGON_MESH_PROCESSING_SMOOTH_SHAPE_H
#define CGAL_POLYGON_MESH_PROCESSING_SMOOTH_SHAPE_H

#include <CGAL/license/Polygon_mesh_processing/meshing_hole_filling.h>

#if defined(CGAL_EIGEN3_ENABLED)
#include <CGAL/Eigen_solver_traits.h>
#endif

#include <CGAL/Polygon_mesh_processing/internal/Smoothing/curvature_flow_impl.h>

#include <CGAL/utility.h>
#include <CGAL/property_map.h>

#ifdef CGAL_PMP_SMOOTHING_OUTPUT_INTERMEDIARY_STEPS
#include <fstream>
#include <sstream>
#endif

namespace CGAL {
namespace Polygon_mesh_processing {

/*!
* \ingroup PMP_meshing_grp
*
* @brief smooths the overall shape of the mesh by using the mean curvature flow.
*
* The effect depends on the curvature of each area and on a time step which
* represents the amount by which vertices are allowed to move.
* The result conformally maps the initial surface to a sphere.
*
* @tparam TriangleMesh model of `MutableFaceGraph`.
* @tparam FaceRange range of `boost::graph_traits<TriangleMesh>::%face_descriptor`,
*         model of `Range`. Its iterator type is `ForwardIterator`.
* @tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters"
*
* @param tmesh a polygon mesh with triangulated surface patches to be smoothed.
* @param faces the range of triangular faces defining one or several surface patches to be smoothed.
* @param time a time step that corresponds to the speed by which the surface is smoothed.
*        A larger time step results in faster convergence but details may be distorted to a larger extent
*        compared to more iterations with a smaller step. Typical values scale in the interval (1e-6, 1].
* @param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below
*
* \cgalNamedParamsBegin
*   \cgalParamNBegin{number_of_iterations}
*     \cgalParamDescription{the number of iterations for the sequence of the smoothing iterations performed}
*     \cgalParamType{unsigned int}
*     \cgalParamDefault{`1`}
*   \cgalParamNEnd
*
*   \cgalParamNBegin{vertex_is_constrained_map}
*     \cgalParamDescription{a property map containing the constrained-or-not status of each vertex of `tmesh`.}
*     \cgalParamType{a class model of `ReadWritePropertyMap` with `boost::graph_traits<TriangleMesh>::%vertex_descriptor`
*                    as key type and `bool` as value type. It must be default constructible.}
*     \cgalParamDefault{a default property map where no vertex is constrained}
*     \cgalParamExtra{A constrained vertex cannot be modified at all during smoothing.}
*   \cgalParamNEnd
*
*   \cgalParamNBegin{do_scale}
*     \cgalParamDescription{Whether to apply rescaling after smoothing. This is useful because
*                           the mean curvature flow tends to shrink the surface.}
*     \cgalParamType{Boolean}
*     \cgalParamDefault{`true`}
*     \cgalParamExtra{Scaling can only be applied if the mesh is closed and if there is no more than
*                     a single constrained vertex.}
*     \cgalParamExtra{If a vertex is constrained, it is the fixed point of the scaling, otherwise
*                     the centroid is used.}
*   \cgalParamNEnd
*
*   \cgalParamNBegin{vertex_point_map}
*     \cgalParamDescription{a property map associating points to the vertices of `tmesh`}
*     \cgalParamType{a class model of `ReadWritePropertyMap` with `boost::graph_traits<TriangleMesh>::%vertex_descriptor`
*                    as key type and `%Point_3` as value type}
*     \cgalParamDefault{`boost::get(CGAL::vertex_point, tmesh)`}
*     \cgalParamExtra{If this parameter is omitted, an internal property map for `CGAL::vertex_point_t`
*                     must be available in `TriangleMesh`.}
*   \cgalParamNEnd
*
*   \cgalParamNBegin{geom_traits}
*     \cgalParamDescription{an instance of a geometric traits class}
*     \cgalParamType{a class model of `Kernel`}
*     \cgalParamDefault{a \cgal Kernel deduced from the point type, using `CGAL::Kernel_traits`}
*     \cgalParamExtra{The geometric traits class must be compatible with the vertex point type.}
*   \cgalParamNEnd
*
*   \cgalParamNBegin{sparse_linear_solver}
*     \cgalParamDescription{an instance of the sparse linear solver used for smoothing}
*     \cgalParamType{a class model of `SparseLinearAlgebraWithFactorTraits_d`}
*     \cgalParamDefault{if \ref thirdpartyEigen "Eigen" 3.2 (or greater) is available and
*                       `CGAL_EIGEN3_ENABLED` is defined, then the following overload of `Eigen_solver_traits`
*                       is provided as default value:
*                       `CGAL::Eigen_solver_traits<Eigen::BiCGSTAB<CGAL::Eigen_sparse_matrix<double>::%EigenType, Eigen::IncompleteLUT<double> > >`}
*   \cgalParamNEnd
* \cgalNamedParamsEnd
*
* @warning This function involves linear algebra, that is computed using non-exact, floating-point arithmetic.
*
* @see `angle_and_area_smoothing()`
*/
template<typename TriangleMesh, typename FaceRange,
         typename NamedParameters = parameters::Default_named_parameters>
void smooth_shape(const FaceRange& faces,
                  TriangleMesh& tmesh,
                  const double time,
                  const NamedParameters& np = parameters::default_values())
{
  if(std::begin(faces) == std::end(faces))
    return;

  typedef typename boost::graph_traits<TriangleMesh>::vertex_descriptor      vertex_descriptor;
  typedef typename GetGeomTraits<TriangleMesh, NamedParameters>::type        GeomTraits;
  typedef typename GetVertexPointMap<TriangleMesh, NamedParameters>::type    VertexPointMap;
  typedef typename internal_np::Lookup_named_param_def<
                     internal_np::vertex_is_constrained_t,
                     NamedParameters,
                     Static_boolean_property_map<vertex_descriptor, false> >::type  VCMap;

  using parameters::choose_parameter;
  using parameters::get_parameter;

  GeomTraits gt = choose_parameter<GeomTraits>(get_parameter(np, internal_np::geom_traits));
  VertexPointMap vpmap = choose_parameter(get_parameter(np, internal_np::vertex_point),
                                          get_property_map(CGAL::vertex_point, tmesh));
  VCMap vcmap = choose_parameter(get_parameter(np, internal_np::vertex_is_constrained),
                                 Static_boolean_property_map<vertex_descriptor, false>());
  const unsigned int nb_iterations = choose_parameter(get_parameter(np, internal_np::number_of_iterations), 1);
  const bool scale_after_smoothing = choose_parameter(get_parameter(np, internal_np::do_scale), true);

#if defined(CGAL_EIGEN3_ENABLED)
#if EIGEN_VERSION_AT_LEAST(3,2,0)
  typedef typename Eigen::SparseMatrix<double>                                         Eigen_sparse_matrix;
  typedef typename Eigen::BiCGSTAB<Eigen_sparse_matrix, Eigen::IncompleteLUT<double> > Eigen_solver;
  typedef CGAL::Eigen_solver_traits<Eigen_solver>                                      Default_solver;
#else
  typedef bool Default_solver;//compilation should crash
  //if no solver is provided and Eigen version < 3.2
#endif
#else
  typedef bool Default_solver;//compilation should crash
  // if no solver is provided and Eigen version < 3.2
#endif

#if defined(CGAL_EIGEN3_ENABLED)
  static_assert(
      (!std::is_same<typename GetSolver<NamedParameters, Default_solver>::type, bool>::value) || EIGEN_VERSION_AT_LEAST(3, 2, 0),
      "Eigen3 version 3.2 or later is required.");
#else
  static_assert(
      (!std::is_same<typename GetSolver<NamedParameters, Default_solver>::type, bool>::value),
      "Eigen3 version 3.2 or later is required.");
#endif

  typedef typename GetSolver<NamedParameters, Default_solver>::type               Sparse_solver;
  typedef typename Sparse_solver::Matrix                                          Eigen_matrix;
  typedef typename Sparse_solver::Vector                                          Eigen_vector;

  Sparse_solver solver = choose_parameter<Default_solver>(get_parameter(np, internal_np::sparse_linear_solver));

  std::size_t n = vertices(tmesh).size();
  Eigen_matrix A(n, n);
  Eigen_vector bx(n), by(n), bz(n), Xx(n), Xy(n), Xz(n);
  std::vector<CGAL::Triple<std::size_t, std::size_t, double> > stiffness;

  internal::Shape_smoother<TriangleMesh, VertexPointMap, VCMap, Sparse_solver, GeomTraits> smoother(tmesh, vpmap, vcmap, scale_after_smoothing, gt);

  smoother.init_smoothing(faces);

  // For robustness reasons, the Laplacian coefficients are computed only once (only the mass
  // matrix is updated at every iteration). See Kazdhan et al. "Can Mean-Curvature Flow Be Made Non-Singular?".
  smoother.calculate_stiffness_matrix_elements(stiffness);

  for(unsigned int iter=0; iter<nb_iterations; ++iter)
  {
#ifdef CGAL_PMP_SMOOTHING_DEBUG
    std::cout << "iteration #" << iter << std::endl;
#endif

    smoother.setup_system(A, bx, by, bz, stiffness, time);

    if(smoother.solve_system(A, Xx, Xy, Xz, bx, by, bz, solver))
    {
      smoother.update_mesh(Xx, Xy, Xz);
    }
    else
    {
#ifdef CGAL_PMP_SMOOTHING_DEBUG
      std::cerr << "Failed to solve system!" << std::endl;
#endif
      break;
    }

#ifdef CGAL_PMP_SMOOTHING_OUTPUT_INTERMEDIARY_STEPS
    std::stringstream oss;
    oss << "smoothed_mesh_step_" << iter << ".off" << std::ends;
    std::ofstream out(oss.str().c_str());
    out.precision(17);
    out << tmesh;
    out.close();
#endif
  }
}

/// \cond SKIP_IN_MANUAL
template <typename TriangleMesh, typename CGAL_NP_TEMPLATE_PARAMETERS>
void smooth_shape(TriangleMesh& tmesh,
                  const double time,
                  const CGAL_NP_CLASS& np = parameters::default_values())
{
  smooth_shape(faces(tmesh), tmesh, time, np);
}
/// \endcond

} // Polygon_mesh_processing
} // CGAL

#endif // CGAL_POLYGON_MESH_PROCESSING_SMOOTH_SHAPE_H