23#ifndef VCL_ALGORITHMS_MESH_SMOOTH_H
24#define VCL_ALGORITHMS_MESH_SMOOTH_H
26#include <vclib/mesh.h>
27#include <vclib/space/complex.h>
36template<
typename PositionType>
39 using ScalarType = PositionType::ScalarType;
44template<
typename MeshType,
typename PositionType>
45void accumulateLaplacianInfo(
47 std::vector<LaplacianInfo<PositionType>>& data,
48 bool cotangentFlag =
false)
50 using ScalarType = PositionType::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 PositionType& p0 = v0.position();
63 const PositionType& p1 = v1.position();
64 const PositionType& p2 = v2.position();
66 ScalarType angle = PositionType(p1 - p2).angle(p0 - p2);
67 weight = std::tan((M_PI * 0.5) - angle);
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;
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;
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;
127template<FaceMeshConcept MeshType>
128void laplacianSmoothing(
131 bool smoothSelected =
false,
132 bool cotangentWeight =
false )
134 using VertexType = MeshType::VertexType;
135 using PositionType = VertexType::PositionType;
137 const detail::LaplacianInfo<PositionType> lpz = {PositionType(0, 0, 0), 0};
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);
154template<FaceMeshConcept MeshType>
160 bool smoothSelected =
false )
162 using VertexType = MeshType::VertexType;
163 using PositionType = VertexType::PositionType;
165 const detail::LaplacianInfo<PositionType> lpz = {PositionType(0, 0, 0), 0};
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()) {
175 laplData[m.index(v)].sum / laplData[m.index(v)].cnt -
177 v.position() = v.position() + delta * lambda;
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()) {
187 laplData[m.index(v)].sum / laplData[m.index(v)].cnt -
189 v.position() = v.position() + delta * mu;
209template<MeshConcept MeshType, Po
intConcept Po
intType>
210void smoothPerVertexNormalsPointCloud(
212 const KDTree<PointType>& tree,
216 requirePerVertexNormal(m);
218 using Scalar = PointType::ScalarType;
219 using VertexType = MeshType::VertexType;
220 using NormalType = VertexType::NormalType;
222 std::vector<NormalType> TD(m.vertexContainerSize(), NormalType(0, 0, 0));
224 for (uint ii = 0; ii < iterNum; ++ii) {
225 for (
const VertexType& v : m.
vertices()) {
226 std::vector<Scalar> distances;
228 std::vector<uint> neighbors = tree.kNearestNeighborsIndices(
229 v.position(), neighborNum, distances);
231 for (uint nid : neighbors) {
232 if (m.vertex(nid).normal() * v.normal() > 0) {
233 TD[m.index(v)] += m.vertex(nid).normal();
236 TD[m.index(v)] -= m.vertex(nid).normal();
240 for (VertexType& v : m.
vertices()) {
241 v.normal() = TD[m.index(v)];
258template<MeshConcept MeshType>
259void smoothPerVertexNormalsPointCloud(
264 using PointType = MeshType::VertexType::PositionType;
265 KDTree<PointType> tree(m);
266 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:84
constexpr detail::VerticesView vertices
A view that allows to iterate over the Vertex elements of an object.
Definition vertex.h:92