23#ifndef VCL_ALGORITHMS_MESH_SMOOTH_H
24#define VCL_ALGORITHMS_MESH_SMOOTH_H
26#include <vclib/mesh/requirements.h>
27#include <vclib/space/complex/kd_tree.h>
36template<
typename CoordType>
39 using ScalarType = CoordType::ScalarType;
44template<
typename MeshType,
typename CoordType>
45void accumulateLaplacianInfo(
47 std::vector<LaplacianInfo<CoordType>>& data,
48 bool cotangentFlag =
false)
50 using ScalarType = CoordType::ScalarType;
51 using VertexType = MeshType::VertexType;
52 using FaceType = MeshType::FaceType;
54 ScalarType weight = 1.0f;
56 for (
const FaceType& f : m.
faces()) {
57 for (uint j = 0; j < f.vertexNumber(); ++j) {
58 if (!f.edgeOnBorder(j)) {
59 const VertexType& v0 = *f.vertex(j);
60 const VertexType& v1 = *f.vertexMod(j + 1);
61 const VertexType& v2 = *f.vertexMod(j + 2);
62 const CoordType& p0 = v0.coord();
63 const CoordType& p1 = v1.coord();
64 const CoordType& p2 = v2.coord();
66 ScalarType angle = CoordType(p1 - p2).angle(p0 - p2);
67 weight = std::tan((M_PI * 0.5) - angle);
70 data[m.index(v0)].sum += f.vertexMod(j + 1)->coord() * weight;
71 data[m.index(v1)].sum += f.vertex(j)->coord() * weight;
72 data[m.index(v0)].cnt += weight;
73 data[m.index(v1)].cnt += weight;
78 for (
const FaceType& f : m.
faces()) {
79 for (uint j = 0; j < f.vertexNumber(); ++j) {
80 if (f.edgeOnBorder(j)) {
81 const VertexType& v0 = *f.vertex(j);
82 const VertexType& v1 = *f.vertexMod(j + 1);
83 const CoordType& p0 = v0.coord();
84 const CoordType& p1 = v1.coord();
85 data[m.index(v0)].sum = p0;
86 data[m.index(v1)].sum = p1;
87 data[m.index(v0)].cnt = 1;
88 data[m.index(v1)].cnt = 1;
94 for (
const FaceType& f : m.
faces()) {
95 for (uint j = 0; j < f.vertexNumber(); ++j) {
96 if (f.edgeOnBorder(j)) {
97 const VertexType& v0 = *f.vertex(j);
98 const VertexType& v1 = *f.vertexMod(j + 1);
99 const CoordType& p0 = v0.coord();
100 const CoordType& p1 = v1.coord();
101 data[m.index(v0)].sum += p1;
102 data[m.index(v1)].sum += p0;
103 ++data[m.index(v0)].cnt;
104 ++data[m.index(v1)].cnt;
126template<FaceMeshConcept MeshType>
127void laplacianSmoothing(
130 bool smoothSelected =
false,
131 bool cotangentWeight =
false )
133 using VertexType = MeshType::VertexType;
134 using CoordType = VertexType::CoordType;
136 const detail::LaplacianInfo<CoordType> lpz = {CoordType(0, 0, 0), 0};
138 for (uint i = 0; i < step; ++i) {
139 std::vector<detail::LaplacianInfo<CoordType>> laplData(
140 m.vertexContainerSize(), lpz);
141 detail::accumulateLaplacianInfo(m, laplData, cotangentWeight);
142 for (VertexType& v : m.
vertices()) {
143 if (laplData[m.index(v)].cnt > 0) {
144 if (!smoothSelected || v.selected()) {
145 v.coord() = (v.coord() + laplData[m.index(v)].sum) /
146 (laplData[m.index(v)].cnt + 1);
153template<FaceMeshConcept MeshType>
159 bool smoothSelected =
false )
161 using VertexType = MeshType::VertexType;
162 using CoordType = VertexType::CoordType;
164 const detail::LaplacianInfo<CoordType> lpz = {CoordType(0, 0, 0), 0};
166 for (uint i = 0; i < step; ++i) {
167 std::vector<detail::LaplacianInfo<CoordType>> laplData(
168 m.vertexContainerSize(), lpz);
169 detail::accumulateLaplacianInfo(m, laplData);
170 for (VertexType& v : m.
vertices()) {
171 if (laplData[m.index(v)].cnt > 0) {
172 if (!smoothSelected || v.selected()) {
174 laplData[m.index(v)].sum / laplData[m.index(v)].cnt -
176 v.coord() = v.coord() + delta * lambda;
180 std::fill(laplData.begin(), laplData.end(), lpz);
181 detail::accumulateLaplacianInfo(m, laplData);
182 for (VertexType& v : m.
vertices()) {
183 if (laplData[m.index(v)].cnt > 0) {
184 if (!smoothSelected || v.selected()) {
186 laplData[m.index(v)].sum / laplData[m.index(v)].cnt -
188 v.coord() = v.coord() + delta * mu;
208template<MeshConcept MeshType, Po
intConcept Po
intType>
209void smoothPerVertexNormalsPointCloud(
211 const KDTree<PointType>& tree,
215 requirePerVertexNormal(m);
217 using Scalar = PointType::ScalarType;
218 using VertexType = MeshType::VertexType;
219 using NormalType = VertexType::NormalType;
221 std::vector<NormalType> TD(m.vertexContainerSize(), NormalType(0, 0, 0));
223 for (uint ii = 0; ii < iterNum; ++ii) {
224 for (
const VertexType& v : m.
vertices()) {
225 std::vector<Scalar> distances;
227 std::vector<uint> neighbors = tree.kNearestNeighborsIndices(
228 v.coord(), neighborNum, distances);
230 for (uint nid : neighbors) {
231 if (m.vertex(nid).normal() * v.normal() > 0) {
232 TD[m.index(v)] += m.vertex(nid).normal();
235 TD[m.index(v)] -= m.vertex(nid).normal();
239 for (VertexType& v : m.
vertices()) {
240 v.normal() = TD[m.index(v)];
257template<MeshConcept MeshType>
258void smoothPerVertexNormalsPointCloud(
263 using Scalar = MeshType::VertexType::CoordType::ScalarType;
264 KDTree<Scalar> tree(m);
265 smoothPerVertexNormalsPointCloud(m, tree, neighborNum, iterNum);
constexpr detail::FacesView faces
A view that allows to iterate overt the Face elements of an object.
Definition face.h:52
constexpr detail::VerticesView vertices
A view that allows to iterate over the Vertex elements of an object.
Definition vertex.h:60