compatible remeshing function

This commit is contained in:
konstantinos katrioplas 2017-08-20 23:18:07 +03:00
parent a0e7cf4a7f
commit 9706baa796
2 changed files with 237 additions and 45 deletions

View File

@ -48,6 +48,7 @@ CGAL_add_named_parameter(nb_points_per_distance_unit_t, nb_points_per_distance_u
CGAL_add_named_parameter(face_normal_t, face_normal, face_normal_map)
CGAL_add_named_parameter(gradient_descent_precision_t, gradient_descent_precision, gradient_descent_precision)
CGAL_add_named_parameter(use_weights_t, use_weights, use_weights)
CGAL_add_named_parameter(distance_precision_t, distance_precision, distance_precision)
//internal
CGAL_add_named_parameter(weight_calculator_t, weight_calculator, weight_calculator)

View File

@ -1,7 +1,6 @@
#ifndef CGAL_POLYGON_MESH_PROCESSING_SMOOTHING_H
#define CGAL_POLYGON_MESH_PROCESSING_SMOOTHING_H
#include <CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h>
#include <CGAL/Polygon_mesh_processing/internal/Smoothing/curvature_flow_impl.h>
#include <CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/remesh_impl.h>
@ -9,10 +8,18 @@
#include <CGAL/Polygon_mesh_processing/internal/named_function_params.h>
#include <CGAL/Polygon_mesh_processing/internal/named_params_helper.h>
#include <CGAL/Polygon_mesh_processing/distance.h>
#ifdef CGAL_PMP_REMESHING_VERBOSE
#include <CGAL/Timer.h>
#endif
#if defined(CGAL_LINKED_WITH_TBB)
#define TAG CGAL::Parallel_tag
#else
#define TAG CGAL::Sequential_tag
#endif
namespace CGAL {
namespace Polygon_mesh_processing {
@ -51,17 +58,15 @@ namespace Polygon_mesh_processing {
* \cgalParamBegin{face_index_map} a property map containing the index of each face of `pmesh`.
* \cgalParamEnd
* \cgalParamBegin{number_of_iterations} the number of iterations for the
* sequence of atomic operations performed (listed in the above description)
* sequence of the smoothing iterations performed.
* \cgalParamEnd
* \cgalParamBegin{edge_is_constrained_map} a property map containing the
* constrained-or-not status of each edge of `pmesh`. A constrained edge can be split
* or collapsed, but not flipped, nor its endpoints moved by smoothing.
* Note that patch boundary edges (i.e. incident to only one face in the range)
* are always considered as constrained edges.
* constrained-or-not status of each edge of `pmesh`. Vertices that belong to constrained
* edges are not modified at all during smoothing.
* \cgalParamEnd
* \cgalParamBegin{vertex_is_constrained_map} a property map containing the
* constrained-or-not status of each vertex of `pmesh`. A constrained vertex
* cannot be modified at all during remeshing.
* cannot be modified at all during smoothing.
* \cgalParamEnd
* \cgalParamBegin{use_weights} If `true`, small angles carry more weight than larger ones.
* \cgalParamEnd
@ -121,6 +126,9 @@ void angle_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const NamedPara
//use weighted angles
bool use_weights = choose_param(get_param(np, internal_np::use_weights), false);
// convergence precision
double precision = choose_param(get_param(np, internal_np::number_of_iterations), 1);
internal::Compatible_remesher<PolygonMesh, VertexPointMap, VCMap, ECMap, GeomTraits>
remesher(pmesh, vpmap, vcmap, ecmap);
@ -185,8 +193,8 @@ void angle_remeshing(PolygonMesh& pmesh)
* \ingroup PMP_meshing_grp
* @brief uses triangle area as a criterion for smoothing.
* This function imrpoves the overall distribution of points over a mesh area
* by trying to form triangles as uniform as possible. Should be used in combination with angle remeshing
* to avoid creation of long and skiny triangles. Vertices are moved towards equalizing adjacent triangle
* by trying to form triangles as uniform as possible. Use of many iterations of area equalization alone
* for remeshing may result in long and skinny triangles. Vertices are moved towards equalizing adjacent triangle
* areas using gradient descent.
*
* @tparam PolygonMesh model of `MutableFaceGraph`.
@ -214,17 +222,15 @@ void angle_remeshing(PolygonMesh& pmesh)
* \cgalParamBegin{face_index_map} a property map containing the index of each face of `pmesh`.
* \cgalParamEnd
* \cgalParamBegin{number_of_iterations} the number of iterations for the
* sequence of atomic operations performed (listed in the above description)
* sequence of the smoothing iterations performed.
* \cgalParamEnd
* \cgalParamBegin{edge_is_constrained_map} a property map containing the
* constrained-or-not status of each edge of `pmesh`. A constrained edge can be split
* or collapsed, but not flipped, nor its endpoints moved by smoothing.
* Note that patch boundary edges (i.e. incident to only one face in the range)
* are always considered as constrained edges.
* constrained-or-not status of each edge of `pmesh`. Vertices that belong to constrained
* edges are not modified at all during smoothing.
* \cgalParamEnd
* \cgalParamBegin{vertex_is_constrained_map} a property map containing the
* constrained-or-not status of each vertex of `pmesh`. A constrained vertex
* cannot be modified at all during remeshing.
* cannot be modified at all during smoothing.
* \cgalParamEnd
* \cgalParamBegin{gradient_descent_precision} The precision which is met during gradient descent refers to
* the relative energy between iterations of each triangle element which is minimized
@ -344,6 +350,208 @@ void area_remeshing(PolygonMesh& pmesh)
area_remeshing(pmesh, faces(pmesh), parameters::all_default());
}
/*!
* \ingroup PMP_meshing_grp
* @brief smoothes a triangulated region of a polygon mesh.
* This function imrpoves the overall mesh quality by using sequentially angle,
* area, and again angle criteria for each iteration until convergence. Convergence is realized based on
* the hausdorff distance of the mesh between previous and current iteration or until
* a specified maximum number of iterations.
*
* @tparam PolygonMesh model of `MutableFaceGraph`.
* The descriptor types `boost::graph_traits<PolygonMesh>::%face_descriptor`
* and `boost::graph_traits<PolygonMesh>::%halfedge_descriptor` must be
* models of `Hashable`.
* If `PolygonMesh` has an internal property map for `CGAL::face_index_t`,
* and no `face_index_map` is given
* as a named parameter, then the internal one should be initialized
* @tparam FaceRange range of `boost::graph_traits<PolygonMesh>::%face_descriptor`,
model of `Range`. Its iterator type is `ForwardIterator`.
* @tparam NamedParameters a sequence of \ref namedparameters
*
* @param pmesh a polygon mesh with triangulated surface patches to be remeshed
* @param faces the range of triangular faces defining one or several surface patches to be remeshed
* @param np optional sequence of \ref namedparameters among the ones listed below
*
* \cgalNamedParamsBegin
* \cgalParamBegin{geom_traits} a geometric traits class instance, model of `Kernel`.
* Exact constructions kernels are not supported by this function.
* \cgalParamEnd
* \cgalParamBegin{vertex_point_map} the property map with the points associated
* to the vertices of `pmesh`. Instance of a class model of `ReadWritePropertyMap`.
* \cgalParamEnd
* \cgalParamBegin{face_index_map} a property map containing the index of each face of `pmesh`.
* \cgalParamEnd
* \cgalParamBegin{number_of_iterations} the maximum number of iterations for the
* sequence of smoothing iterations performed.
* \cgalParamEnd
* \cgalParamBegin{edge_is_constrained_map} a property map containing the
* constrained-or-not status of each edge of `pmesh`. Vertices that belong to constrained
* edges are not modified at all during smoothing.
* \cgalParamEnd
* \cgalParamBegin{vertex_is_constrained_map} a property map containing the
* constrained-or-not status of each vertex of `pmesh`. A constrained vertex
* cannot be modified at all during smoothing.
* \cgalParamEnd
* \cgalParamBegin{use_weights} If `true`, small angles carry more weight than larger ones.
* \cgalParamEnd
* \cgalParamBegin{distance_precision} The Hausdorff distance between the mesh of the previous and the curent iteration.
* Defaults to 0.01.
* \cgalParamEnd
* \cgalNamedParamsEnd
*/
template<typename PolygonMesh, typename FaceRange, typename NamedParameters>
void compatible_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const NamedParameters& np)
{
using boost::choose_param;
using boost::get_param;
#ifdef CGAL_PMP_REMESHING_VERBOSE
CGAL::Timer t;
std::cout << "Remeshing parameters...";
std::cout.flush();
t.start();
#endif
// geom traits
typedef typename GetGeomTraits<PolygonMesh, NamedParameters>::type GeomTraits;
// vpmap
typedef typename GetVertexPointMap<PolygonMesh, NamedParameters>::type VertexPointMap;
VertexPointMap vpmap = choose_param(get_param(np, internal_np::vertex_point),
get_property_map(CGAL::vertex_point, pmesh));
// fimap
typedef typename GetFaceIndexMap<PolygonMesh, NamedParameters>::type FIMap;
FIMap fimap = choose_param(get_param(np, internal_np::face_index),
get_property_map(face_index, pmesh));
// vcmap
typedef typename boost::graph_traits<PolygonMesh>::vertex_descriptor vertex_descriptor;
typedef typename boost::lookup_named_param_def <
internal_np::vertex_is_constrained_t,
NamedParameters,
internal::No_constraint_pmap<vertex_descriptor>//default
> ::type VCMap;
VCMap vcmap = choose_param(get_param(np, internal_np::vertex_is_constrained),
internal::No_constraint_pmap<vertex_descriptor>());
// ecmap
typedef typename boost::lookup_named_param_def <
internal_np::edge_is_constrained_t,
NamedParameters,
internal::Border_constraint_pmap<PolygonMesh, FaceRange, FIMap>
> ::type ECMap;
ECMap ecmap = (boost::is_same<ECMap, internal::Border_constraint_pmap<PolygonMesh, FaceRange, FIMap> >::value)
? choose_param(get_param(np, internal_np::edge_is_constrained),
internal::Border_constraint_pmap<PolygonMesh, FaceRange, FIMap>(pmesh, faces, fimap))
: choose_param(get_param(np, internal_np::edge_is_constrained),
internal::Border_constraint_pmap<PolygonMesh, FaceRange, FIMap>());
//nb_iterations
unsigned int nb_iterations = choose_param(get_param(np, internal_np::number_of_iterations), 20);
//use weighted angles
bool use_weights = choose_param(get_param(np, internal_np::use_weights), false);
//gradient descent precision
double gd_precision = choose_param(get_param(np, internal_np::gradient_descent_precision), 0.001);
// convergence precision
double dist_precision = choose_param(get_param(np, internal_np::distance_precision), 1);
internal::Compatible_remesher<PolygonMesh, VertexPointMap, VCMap, ECMap, GeomTraits>
remesher(pmesh, vpmap, vcmap, ecmap);
#ifdef CGAL_PMP_REMESHING_VERBOSE
t.stop();
std::cout << " done ("<< t.time() <<" sec)." << std::endl;
std::cout << "Removing degenerate faces..." << std::endl;
t.reset(); t.start();
#endif
remesher.remove_degenerate_faces();
#ifdef CGAL_PMP_REMESHING_VERBOSE
t.stop();
std::cout << " done ("<< t.time() <<" sec)." << std::endl;
std::cout << "Initializing..." << std::endl;
t.reset(); t.start();
#endif
remesher.init_remeshing(faces);
#ifdef CGAL_PMP_REMESHING_VERBOSE
t.stop();
std::cout << " done ("<< t.time() <<" sec)." << std::endl;
std::cout << "#iter = " << nb_iterations << std::endl;
std::cout << "Remeshing ..." << std::endl;
t.reset(); t.start();
#endif
unsigned int count_iterations = 0;
PolygonMesh previous_mesh;
while(true)
{
previous_mesh = pmesh;
remesher.angle_relaxation(use_weights);
remesher.area_relaxation(gd_precision);
remesher.angle_relaxation(use_weights);
remesher.project_to_surface();
double dist = approximate_Hausdorff_distance
<TAG>(previous_mesh, pmesh, parameters::number_of_points_per_area_unit(1000));
count_iterations++;
if(dist < dist_precision)
{
#ifdef CGAL_PMP_REMESHING_VERBOSE
t.stop();
std::cout << "Remeshing done in ";
std::cout << t.time() << " sec." << std::endl;
std::cout << "Convergence to relative hausdorff distance has been achieved." << std::endl;
#endif
break;
}
if(count_iterations == nb_iterations)
{
#ifdef CGAL_PMP_REMESHING_VERBOSE
t.stop();
std::cout << "Remeshing done in ";
std::cout << t.time() << " sec." << std::endl;
std::cout << "Maximum number of iterations has been achieved." << std::endl;
#endif
break;
}
}
#ifdef CGAL_PMP_REMESHING_VERBOSE
t.stop();
std::cout << "Remeshing done in ";
std::cout << t.time() << " sec." << std::endl;
#endif
}
template<typename PolygonMesh, typename NamedParameters>
void compatible_remeshing(PolygonMesh& pmesh, const NamedParameters& np)
{
compatible_remeshing(pmesh, faces(pmesh), np);
}
template<typename PolygonMesh>
void compatible_remeshing(PolygonMesh& pmesh)
{
compatible_remeshing(pmesh, faces(pmesh), parameters::all_default());
}
/*!
* \ingroup PMP_meshing_grp
* @brief todo
@ -372,18 +580,13 @@ void area_remeshing(PolygonMesh& pmesh)
* \cgalParamEnd
* \cgalParamBegin{face_index_map} a property map containing the index of each face of `pmesh`.
* \cgalParamEnd
* \cgalParamBegin{number_of_iterations} the number of iterations for the
* sequence of atomic operations performed (listed in the above description)
* \cgalParamEnd
* \cgalParamBegin{edge_is_constrained_map} a property map containing the
* constrained-or-not status of each edge of `pmesh`. A constrained edge can be split
* or collapsed, but not flipped, nor its endpoints moved by smoothing.
* Note that patch boundary edges (i.e. incident to only one face in the range)
* are always considered as constrained edges.
* constrained-or-not status of each edge of `pmesh`. Vertices that belong to constrained
* edges are not modified at all during smoothing.
* \cgalParamEnd
* \cgalParamBegin{vertex_is_constrained_map} a property map containing the
* constrained-or-not status of each vertex of `pmesh`. A constrained vertex
* cannot be modified at all during remeshing.
* cannot be modified at all during smoothing.
* \cgalParamEnd
* \cgalNamedParamsEnd
*/
@ -403,17 +606,17 @@ void curvature_flow(PolygonMesh& pmesh, const FaceRange& faces, const NamedParam
// GeomTraits
typedef typename GetGeomTraits<PolygonMesh, NamedParameters>::type GeomTraits;
//vpmap
// vpmap
typedef typename GetVertexPointMap<PolygonMesh, NamedParameters>::type VertexPointMap;
VertexPointMap vpmap = choose_param(get_param(np, internal_np::vertex_point),
get_property_map(CGAL::vertex_point, pmesh));
//fimap
// fimap
typedef typename GetFaceIndexMap<PolygonMesh, NamedParameters>::type FIMap;
FIMap fimap = choose_param(get_param(np, internal_np::face_index),
get_property_map(face_index, pmesh));
//vcmap
// vcmap
typedef typename boost::graph_traits<PolygonMesh>::vertex_descriptor vertex_descriptor;
typedef typename boost::lookup_named_param_def <
internal_np::vertex_is_constrained_t,
@ -423,7 +626,7 @@ void curvature_flow(PolygonMesh& pmesh, const FaceRange& faces, const NamedParam
VCMap vcmap = choose_param(get_param(np, internal_np::vertex_is_constrained),
internal::No_constraint_pmap<vertex_descriptor>());
//ecmap
// ecmap
typedef typename boost::lookup_named_param_def <
internal_np::edge_is_constrained_t,
NamedParameters,
@ -435,7 +638,7 @@ void curvature_flow(PolygonMesh& pmesh, const FaceRange& faces, const NamedParam
: choose_param(get_param(np, internal_np::edge_is_constrained),
internal::Border_constraint_pmap<PolygonMesh, FaceRange, FIMap>());
//nb_iterations
// nb_iterations
unsigned int nb_iterations = choose_param(get_param(np, internal_np::number_of_iterations), 1);
#ifdef CGAL_PMP_REMESHING_VERBOSE
@ -454,6 +657,7 @@ void curvature_flow(PolygonMesh& pmesh, const FaceRange& faces, const NamedParam
std::cout << "Removing degenerate faces..." << std::endl;
t.reset(); t.start();
#endif
curvature_remesher.remove_degenerate_faces();
#ifdef CGAL_PMP_REMESHING_VERBOSE
@ -462,34 +666,21 @@ void curvature_flow(PolygonMesh& pmesh, const FaceRange& faces, const NamedParam
std::cout << "Initializing..." << std::endl;
t.reset(); t.start();
#endif
curvature_remesher.init_remeshing(faces);
#ifdef CGAL_PMP_REMESHING_VERBOSE
t.stop();
std::cout << " done ("<< t.time() <<" sec)." << std::endl;
std::cout << "#iter = " << nb_iterations << std::endl;
std::cout << "Remeshing ..." << std::endl;
std::cout << "Shape smoothing..." << std::endl;
t.reset(); t.start();
#endif
for(unsigned int i=0; i<nb_iterations; ++i)
{
#ifdef CGAL_PMP_REMESHING_VERBOSE
std::cout << " * Iteration " << (i + 1) << " *" << std::endl;
#endif
curvature_remesher.curvature_smoothing(); // normalized version sec 5.5
//curvature_remesher.good_curvature_smoothing(); // formula 14
//for now
//curvature_remesher.project_to_surface();
}
curvature_remesher.curvature_smoothing();
#ifdef CGAL_PMP_REMESHING_VERBOSE
t.stop();
std::cout << "Remeshing done in ";
std::cout << "Shape smoothing done in ";
std::cout << t.time() << " sec." << std::endl;
std::cout<<std::endl;
#endif