# 【CGAL_网格处理】平滑处理

CGAL网格处理中封装了针对网格平滑或形状平滑的算法来实现三角网格区域的平滑。

• 形状平滑：`CGAL::Polygon_mesh_processing::smooth_shape()`通过使用平均曲率流来平滑网格的整体形状。沿着平均曲率流将顶点逐渐移向其邻居的加权重心。基于Desbrun等人的用于形状平滑的曲率流算法。
• 网格平滑：`CGAL::Polygon_mesh_processing::angle_and_area_smoothing()`通过移动（非约束顶点）使三角形角度和面积分布尽可能均匀。

## 形状平滑

``````template<typename TriangleMesh , typename FaceRange , typename NamedParameters = parameters::Default_named_parameters>
void CGAL::Polygon_mesh_processing::smooth_shape(const FaceRange & 			faces,
TriangleMesh & 			tmesh,
const double 				time,
const NamedParameters & 	np = parameters::default_values()
)
``````

#include <CGAL/Polygon_mesh_processing/smooth_shape.h>

tmesh a polygon mesh with triangulated surface patches to be smoothed.
faces the range of triangular faces defining one or several surface patches to be smoothed.
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].
np an optional sequence of Named Parameters among the ones listed below

tmesh：三角化表面后的多边形网格。

faces：面片序列。

time：时间步长。越大收敛越快，平滑速度越快。但是细节上可能会导致丢失。取值(1e-6, 1]。

• `number_of_iterations`：平滑操作迭代次数。默认1次平滑操作。
• `vertex_is_constrained_map`：一个包含了`tmesh`每个顶点在平滑过程中是否受约束的property map。如果某一顶点受约束，其在平滑操作中将不会被修改。

### 测试代码

``````#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Polygon_mesh_processing/smooth_shape.h>
#include <CGAL/Polygon_mesh_processing/IO/polygon_mesh_io.h>
#include <CGAL/draw_surface_mesh.h>
#include <iostream>
#include <set>
#include <string>
typedef CGAL::Exact_predicates_inexact_constructions_kernel   K;
typedef CGAL::Surface_mesh<K::Point_3>                        Mesh;
namespace PMP = CGAL::Polygon_mesh_processing;
int main()
{
const std::string filename = "data/remeshing_surface_layer_1.off";
Mesh mesh;
{
std::cerr << "Invalid input." << std::endl;
return 1;
}
CGAL::draw(mesh);
const unsigned int nb_iterations = 5;
const double time = 0.3;
std::set<Mesh::Vertex_index> constrained_vertices;
for (Mesh::Vertex_index v : vertices(mesh))
{
if (is_border(v, mesh))
constrained_vertices.insert(v);
}
std::cout << "Constraining: " << constrained_vertices.size() << " border vertices" << std::endl;
CGAL::Boolean_property_map<std::set<Mesh::Vertex_index> > vcmap(constrained_vertices);
std::cout << "Smoothing shape... (" << nb_iterations << " iterations)" << std::endl;
PMP::smooth_shape(mesh, time, CGAL::parameters::number_of_iterations(nb_iterations)
.vertex_is_constrained_map(vcmap));
CGAL::IO::write_polygon_mesh("mesh_shape_smoothed.off", mesh, CGAL::parameters::stream_precision(17));
std::cout << "Done!" << std::endl;
CGAL::draw(mesh);
return EXIT_SUCCESS;
}
``````

``````1>D:\\CGAL\\CGAL-5.4.1\\include\\CGAL/Polygon_mesh_processing/smooth_shape.h(149,1): error C2338: static_assert failed: 'Eigen3 version 3.2 or later is required.'
``````

VS2015中配置Eigen_Aria_J的博客-CSDN博客_vs2015配置eigen

## 网格平滑

``````template<typename TriangleMesh , typename FaceRange , typename NamedParameters = parameters::Default_named_parameters>
void CGAL::Polygon_mesh_processing::angle_and_area_smoothing(const FaceRange & 			faces,
TriangleMesh & 			tmesh,
const NamedParameters & 	np = parameters::default_values()
)
``````

#include <CGAL/Polygon_mesh_processing/angle_and_area_smoothing.h>

tmesh a polygon mesh with triangulated surface patches to be smoothed.
faces the range of triangular faces defining one or several surface patches to be smoothed.
np an optional sequence of Named Parameters among the ones listed below

tmesh：同上`smooth_shape()`

faces：同上`smooth_shape()`

• `number_of_iterations`：平滑操作迭代次数。默认1次平滑操作。
• `using_angle_smoothing``using_area_smoothing`：基于角度平滑和基于面积平滑的开关，默认为true。
• `vertex_is_constrained_map``edge_is_constrained_map`：顶点和边的是否受约束映射关系。默认没有顶点和边受约束，即在平滑过程中都会被调整。
• `use_safety_constraints`：布尔值。如果为true，会忽略那些使网格恶化的顶点移动行为。默认为false。
• `use_Delaunay_flips`：布尔值。如果为true，则基于面积的平滑将通过基于 Delaunay 的边缘翻转来完成，以防止产生被拉长的三角面片。

### 测试代码

``````#define CGAL_PMP_USE_CERES_SOLVER
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Polygon_mesh_processing/smooth_mesh.h>
#include <CGAL/Polygon_mesh_processing/detect_features.h>
#include <CGAL/Polygon_mesh_processing/IO/polygon_mesh_io.h>
#include <CGAL/draw_surface_mesh.h>
#include <iostream>
#include <string>
typedef CGAL::Exact_predicates_inexact_constructions_kernel     K;
typedef CGAL::Surface_mesh<K::Point_3>                          Mesh;
typedef boost::graph_traits<Mesh>::edge_descriptor              edge_descriptor;
namespace PMP = CGAL::Polygon_mesh_processing;

int main()
{
const std::string filename = "meshes/anchor_dense.off";
Mesh mesh;
{
std::cerr << "Invalid input." << std::endl;
return 1;
}
CGAL::draw(mesh);
// Constrain edges with a dihedral angle over 60°
typedef boost::property_map<Mesh, CGAL::edge_is_feature_t>::type EIFMap;
EIFMap eif = get(CGAL::edge_is_feature, mesh);
PMP::detect_sharp_edges(mesh, 60, eif);
int sharp_counter = 0;
for (edge_descriptor e : edges(mesh))
if (get(eif, e))
++sharp_counter;
std::cout << sharp_counter << " sharp edges" << std::endl;
const unsigned int nb_iterations = 10;
std::cout << "Smoothing mesh... (" << nb_iterations << " iterations)" << std::endl;
// Smooth with both angle and area criteria + Delaunay flips
PMP::smooth_mesh(mesh, CGAL::parameters::number_of_iterations(nb_iterations)
.use_safety_constraints(false) // authorize all moves
.edge_is_constrained_map(eif));
CGAL::IO::write_polygon_mesh("mesh_smoothed.off", mesh, CGAL::parameters::stream_precision(17));
std::cout << "Done!" << std::endl;
CGAL::draw(mesh);
return EXIT_SUCCESS;
}
``````

``````Area-based smoothing requires the Ceres Library, which is not available.
No such smoothing will be performed!
``````

``````#define CGAL_PMP_USE_CERES_SOLVER
``````

### 测试结果

Smooth with angle，number_of_iterations=10.

Smooth with area，number_of_iterations=10.

Smooth with both angle and area criteria + Delaunay flips，number_of_iterations=10.

## 问题与总结

• Type: 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.
• Default: a default property map where no vertex is constrained
• Extra: A constrained vertex cannot be modified at all during smoothing.

``````std::set<Mesh::Vertex_index> constrained_vertices;
for (Mesh::Vertex_index v : vertices(mesh))
{
if (is_border(v, mesh))
constrained_vertices.insert(v);
}
``````

``````CGAL::Boolean_property_map<std::set<Mesh::Vertex_index> > vcmap(constrained_vertices);
``````

``````/// \\ingroup PkgPropertyMapRef
/// Read-write property map turning a set (such a `std::set`,
/// `boost::unordered_set`, `std::unordered_set`) into a property map
/// associating a Boolean to the value type of the set. The function `get` will
/// return `true` if the key is inside the set and `false` otherwise. The `put`
/// function will insert an element in the set if `true` is passed and erase it
/// otherwise.
template<class Set>
struct Boolean_property_map
{
typedef typename Set::value_type key_type;
typedef bool value_type;
typedef bool reference;

Set* set_ptr;
/// Constructor taking a copy of the set. Note that `set_` must be valid
/// while the property map is in use.
Boolean_property_map(Set& set_) : set_ptr(&set_) {}
Boolean_property_map() : set_ptr(nullptr) {}

friend bool get(const Boolean_property_map<Set>& pm, const key_type& k)
{
CGAL_assertion(pm.set_ptr!=nullptr);
return pm.set_ptr->count(k) != 0;
}

friend void put(Boolean_property_map<Set>& pm, const key_type& k, bool v)
{
CGAL_assertion(pm.set_ptr!=nullptr);
if (v)
pm.set_ptr->insert(k);
else
pm.set_ptr->erase(k);
}
};
``````

Type: 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.

`edge_is_constrained_map`构造同理。