mirror of https://github.com/CGAL/cgal
compatible remeshing function
This commit is contained in:
parent
a0e7cf4a7f
commit
9706baa796
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue