Visual Computing Library  devel
Loading...
Searching...
No Matches
smooth.h
1/*****************************************************************************
2 * VCLib *
3 * Visual Computing Library *
4 * *
5 * Copyright(C) 2021-2025 *
6 * Visual Computing Lab *
7 * ISTI - Italian National Research Council *
8 * *
9 * All rights reserved. *
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the Mozilla Public License Version 2.0 as published *
13 * by the Mozilla Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 * This program is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19 * Mozilla Public License Version 2.0 *
20 * (https://www.mozilla.org/en-US/MPL/2.0/) for more details. *
21 ****************************************************************************/
22
23#ifndef VCL_ALGORITHMS_MESH_SMOOTH_H
24#define VCL_ALGORITHMS_MESH_SMOOTH_H
25
26#include <vclib/mesh.h>
27#include <vclib/space/complex.h>
28
29#include <cmath>
30#include <vector>
31
32namespace vcl {
33
34namespace detail {
35
36template<typename PositionType>
37struct LaplacianInfo
38{
39 using ScalarType = PositionType::ScalarType;
40 PositionType sum;
41 ScalarType cnt;
42};
43
44template<typename MeshType, typename PositionType>
45void accumulateLaplacianInfo(
46 const MeshType& m,
47 std::vector<LaplacianInfo<PositionType>>& data,
48 bool cotangentFlag = false)
49{
50 using ScalarType = PositionType::ScalarType;
51 using VertexType = MeshType::VertexType;
52 using FaceType = MeshType::FaceType;
53
54 ScalarType weight = 1.0f;
55
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 PositionType& p0 = v0.position();
63 const PositionType& p1 = v1.position();
64 const PositionType& p2 = v2.position();
65 if (cotangentFlag) {
66 ScalarType angle = PositionType(p1 - p2).angle(p0 - p2);
67 weight = std::tan((M_PI * 0.5) - angle);
68 }
69
70 data[m.index(v0)].sum +=
71 f.vertexMod(j + 1)->position() * weight;
72 data[m.index(v1)].sum += f.vertex(j)->position() * weight;
73 data[m.index(v0)].cnt += weight;
74 data[m.index(v1)].cnt += weight;
75 }
76 }
77 }
78 // si azzaera i dati per i vertici di bordo
79 for (const FaceType& f : m.faces()) {
80 for (uint j = 0; j < f.vertexNumber(); ++j) {
81 if (f.edgeOnBorder(j)) {
82 const VertexType& v0 = *f.vertex(j);
83 const VertexType& v1 = *f.vertexMod(j + 1);
84 const PositionType& p0 = v0.position();
85 const PositionType& p1 = v1.position();
86 data[m.index(v0)].sum = p0;
87 data[m.index(v1)].sum = p1;
88 data[m.index(v0)].cnt = 1;
89 data[m.index(v1)].cnt = 1;
90 }
91 }
92 }
93
94 // se l'edge j e' di bordo si deve mediare solo con gli adiacenti
95 for (const FaceType& f : m.faces()) {
96 for (uint j = 0; j < f.vertexNumber(); ++j) {
97 if (f.edgeOnBorder(j)) {
98 const VertexType& v0 = *f.vertex(j);
99 const VertexType& v1 = *f.vertexMod(j + 1);
100 const PositionType& p0 = v0.position();
101 const PositionType& p1 = v1.position();
102 data[m.index(v0)].sum += p1;
103 data[m.index(v1)].sum += p0;
104 ++data[m.index(v0)].cnt;
105 ++data[m.index(v1)].cnt;
106 }
107 }
108 }
109}
110
111} // namespace detail
112
127template<FaceMeshConcept MeshType>
128void laplacianSmoothing(
129 MeshType& m,
130 uint step,
131 bool smoothSelected = false,
132 bool cotangentWeight = false /*, CallBackPos *cb*/)
133{
134 using VertexType = MeshType::VertexType;
135 using PositionType = VertexType::PositionType;
136
137 const detail::LaplacianInfo<PositionType> lpz = {PositionType(0, 0, 0), 0};
138
139 for (uint i = 0; i < step; ++i) {
140 std::vector<detail::LaplacianInfo<PositionType>> laplData(
141 m.vertexContainerSize(), lpz);
142 detail::accumulateLaplacianInfo(m, laplData, cotangentWeight);
143 for (VertexType& v : m.vertices()) {
144 if (laplData[m.index(v)].cnt > 0) {
145 if (!smoothSelected || v.selected()) {
146 v.position() = (v.position() + laplData[m.index(v)].sum) /
147 (laplData[m.index(v)].cnt + 1);
148 }
149 }
150 }
151 }
152}
153
154template<FaceMeshConcept MeshType>
155void taubinSmoothing(
156 MeshType& m,
157 uint step,
158 float lambda,
159 float mu,
160 bool smoothSelected = false /*, CallBackPos *cb*/)
161{
162 using VertexType = MeshType::VertexType;
163 using PositionType = VertexType::PositionType;
164
165 const detail::LaplacianInfo<PositionType> lpz = {PositionType(0, 0, 0), 0};
166
167 for (uint i = 0; i < step; ++i) {
168 std::vector<detail::LaplacianInfo<PositionType>> laplData(
169 m.vertexContainerSize(), lpz);
170 detail::accumulateLaplacianInfo(m, laplData);
171 for (VertexType& v : m.vertices()) {
172 if (laplData[m.index(v)].cnt > 0) {
173 if (!smoothSelected || v.selected()) {
174 PositionType delta =
175 laplData[m.index(v)].sum / laplData[m.index(v)].cnt -
176 v.position();
177 v.position() = v.position() + delta * lambda;
178 }
179 }
180 }
181 std::fill(laplData.begin(), laplData.end(), lpz);
182 detail::accumulateLaplacianInfo(m, laplData);
183 for (VertexType& v : m.vertices()) {
184 if (laplData[m.index(v)].cnt > 0) {
185 if (!smoothSelected || v.selected()) {
186 PositionType delta =
187 laplData[m.index(v)].sum / laplData[m.index(v)].cnt -
188 v.position();
189 v.position() = v.position() + delta * mu;
190 }
191 }
192 }
193 }
194}
195
209template<MeshConcept MeshType, PointConcept PointType>
210void smoothPerVertexNormalsPointCloud(
211 MeshType& m,
212 const KDTree<PointType>& tree,
213 uint neighborNum,
214 uint iterNum)
215{
216 requirePerVertexNormal(m);
217
218 using Scalar = PointType::ScalarType;
219 using VertexType = MeshType::VertexType;
220 using NormalType = VertexType::NormalType;
221
222 std::vector<NormalType> TD(m.vertexContainerSize(), NormalType(0, 0, 0));
223
224 for (uint ii = 0; ii < iterNum; ++ii) {
225 for (const VertexType& v : m.vertices()) {
226 std::vector<Scalar> distances;
227
228 std::vector<uint> neighbors = tree.kNearestNeighborsIndices(
229 v.position(), neighborNum, distances);
230
231 for (uint nid : neighbors) {
232 if (m.vertex(nid).normal() * v.normal() > 0) {
233 TD[m.index(v)] += m.vertex(nid).normal();
234 }
235 else {
236 TD[m.index(v)] -= m.vertex(nid).normal();
237 }
238 }
239 }
240 for (VertexType& v : m.vertices()) {
241 v.normal() = TD[m.index(v)];
242 }
243 }
244}
245
258template<MeshConcept MeshType>
259void smoothPerVertexNormalsPointCloud(
260 MeshType& m,
261 uint neighborNum,
262 uint iterNum)
263{
264 using PointType = MeshType::VertexType::PositionType;
265 KDTree<PointType> tree(m);
266 smoothPerVertexNormalsPointCloud(m, tree, neighborNum, iterNum);
267}
268
269} // namespace vcl
270
271#endif // VCL_ALGORITHMS_MESH_SMOOTH_H
constexpr detail::FacesView faces
A view that allows to iterate overt the Face elements of an object.
Definition face.h:84
constexpr detail::VerticesView vertices
A view that allows to iterate over the Vertex elements of an object.
Definition vertex.h:92