Visual Computing Library  devel
Loading...
Searching...
No Matches
clean.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_CLEAN_H
24#define VCL_ALGORITHMS_MESH_CLEAN_H
25
26#include <vclib/algorithms/mesh/sort.h>
27#include <vclib/algorithms/mesh/stat/topology.h>
28
29#include <vclib/algorithms/core.h>
30#include <vclib/mesh.h>
31#include <vclib/space/complex.h>
32
33#include <vector>
34
50namespace vcl {
51
52namespace detail {
53
54/* classe di confronto per l'algoritmo di eliminazione vertici duplicati*/
55template<typename VertexPointer>
56class VertPositionComparator
57{
58public:
59 inline bool operator()(const VertexPointer& a, const VertexPointer& b)
60 {
61 return (a->position() == b->position()) ?
62 (a < b) :
63 (a->position() < b->position());
64 }
65};
66
79template<typename IndexType, typename SentinelType, int N>
80class SortedIndexContainer
81{
82public:
83 SortedIndexContainer() {}
84
85 template<Range RangeType>
86 SortedIndexContainer(SentinelType s, RangeType rng) : s(s), v(rng)
87 {
88 std::sort(v.begin(), v.end());
89 }
90
91 bool operator<(const SortedIndexContainer& s) const
92 {
93 if constexpr (N >= 0) {
94 for (uint i = 0; i < N; ++i) {
95 if (v[i] != s.v[i])
96 return v[i] < s.v[i];
97 }
98 return false;
99 }
100 else {
101 for (uint i = 0; i < v.size() && i < s.v.size(); ++i) {
102 if (v[i] != s.v[i])
103 return v[i] < s.v[i];
104 }
105 return v.size() < s.v.size();
106 }
107 }
108
109 bool operator==(const SortedIndexContainer& s) const
110 {
111 if constexpr (N >= 0) {
112 for (uint i = 0; i < N; ++i) {
113 if (v[i] != s.v[i])
114 return false;
115 }
116 return true;
117 }
118 else {
119 if (v.size() != s.v.size())
120 return false;
121 for (uint i = 0; i < v.size(); ++i) {
122 if (v[i] != s.v[i])
123 return false;
124 }
125 return true;
126 }
127 }
128
129 SentinelType sentinel() const { return s; }
130
131private:
132 Vector<IndexType, N> v;
133 SentinelType s;
134};
135
136} // namespace detail
137
156template<MeshConcept MeshType>
158{
159 using VertexType = MeshType::VertexType;
160
161 // Generate a vector of boolean flags indicating whether each vertex is
162 // referenced by any of the mesh's elements.
163
164 uint n = 0;
166
167 // need to mark as deleted vertices only if the number of unreferenced is
168 // less than vn
169 if (n < m.vertexNumber()) {
170 // will store on this vector only the indices of the referenced vertices
171 std::vector<uint> refVertIndices(m.vertexContainerSize(), UINT_NULL);
172 // Iterate over all vertices in the mesh, and mark any unreferenced
173 // vertex as deleted.
174 for (const VertexType& v : m.vertices()) {
175 if (!refVertices[m.index(v)]) {
176 m.deleteVertex(m.index(v));
177 }
178 else {
179 refVertIndices[m.index(v)] = m.index(v);
180 }
181 }
182
183 // update the vertex indices of the mesh, setting to null the indices of
184 // the unreferenced vertices (it may happen on adjacent vertices of some
185 // container).
186 m.updateVertexIndices(refVertIndices);
187 }
188
189 return n;
190}
191
210template<MeshConcept MeshType>
212{
213 using VertexType = MeshType::VertexType;
214 using VertexPointer = MeshType::VertexType*;
215
216 if (m.vertexNumber() == 0)
217 return 0;
218
219 // a map that will be used to keep track of deleted vertices and their
220 // corresponding pointers.
221 std::vector<uint> newVertexIndices(m.vertexNumber());
222 // assigning each vertex index to itself.
223 std::iota(newVertexIndices.begin(), newVertexIndices.end(), 0);
224
225 uint deleted = 0;
226
227 std::vector<VertexPointer> perm(m.vertexNumber());
228
229 // put all the vertices into a vector for sorting.
230 uint k = 0;
231 for (VertexType& v : m.vertices())
232 perm[k++] = &v;
233
234 // sort the vector based on the vertices' spatial positions.
235 std::sort(
236 std::execution::par_unseq,
237 perm.begin(),
238 perm.end(),
239 detail::VertPositionComparator<VertexPointer>());
240
241 uint i = 0;
242
243 // compare the i-th position with the next ones while they are equal to the
244 // i-th.
245 while (i < perm.size() - 1) {
246 uint j = i + 1;
247 while (j < perm.size() && perm[i]->position() == perm[j]->position()) {
248 // j will be deleted, so we map its pointer to the i-th vertex's
249 // pointer.
250 newVertexIndices[m.index(perm[j])] = m.index(perm[i]); // map j -> i
251 m.deleteVertex(m.index(perm[j]));
252 j++;
253 deleted++;
254 }
255 // here perm[i] != perm[j], so we need to check perm[j] with the next
256 // vertex.
257 i = j;
258 }
259
260 // update the vertex pointers to point to the correct vertices, in every
261 // container of the mesh
262 m.updateVertexIndices(newVertexIndices);
263
264 // todo:
265 // - add a flag that removes degenerate elements after
266 return deleted;
267}
268
295template<FaceMeshConcept MeshType>
297{
298 using VertexType = MeshType::VertexType;
299 using FaceType = MeshType::FaceType;
300
301 // create a vector of sorted tuples of indices, where each tuple represents
302 // a face's vertices and a pointer to the face.
303 std::vector<detail::SortedIndexContainer<
304 VertexType*,
305 FaceType*,
306 FaceType::VERTEX_NUMBER>>
307 fvec;
308
309 for (FaceType& f : m.faces()) {
310 fvec.emplace_back(&f, f.vertices());
311 }
312
313 // sort the vector based on the face vertex indices.
314 std::sort(std::execution::par_unseq, fvec.begin(), fvec.end());
315 uint total = 0;
316
317 // iterate over the sorted vector, and mark any duplicate faces as deleted.
318 for (uint i = 0; i < fvec.size() - 1; ++i) {
319 if (fvec[i] == fvec[i + 1]) {
320 total++;
321 m.deleteFace(fvec[i].sentinel());
322 }
323 }
324 return total;
325}
326
350template<MeshConcept MeshType>
352{
353 using VertexType = MeshType::VertexType;
354
355 int count_vd = 0;
356
357 // iterate over all vertices in the mesh, and mark any with invalid floating
358 // point values as deleted.
359 for (VertexType& v : m.vertices()) {
360 if (v.position().isDegenerate()) {
361 count_vd++;
362 m.deleteVertex(&v);
363 }
364 }
365
366 // If the mesh has faces and the `deleteAlsoFaces` flag is true, delete all
367 // faces incident on deleted vertices.
368 if constexpr (HasFaces<MeshType>) {
369 using FaceType = MeshType::FaceType;
370 if (deleteAlsoFaces) {
371 for (FaceType& f : m.faces()) {
372 bool deg = false;
373 for (VertexType* v : f.vertices()) {
374 if (v->deleted()) {
375 deg = true;
376 }
377 }
378 if (deg) {
379 m.deleteFace(&f);
380 }
381 }
382 }
383 }
384
385 return count_vd;
386}
387
410template<FaceMeshConcept MeshType>
412{
413 uint count = 0;
414 using FaceType = MeshType::FaceType;
415
416 // iterate over all faces in the mesh, and mark any that are degenerate as
417 // deleted.
418 for (FaceType& f : m.faces()) {
419 bool deg = false; // flag to check if a face is degenerate
420 for (uint i = 0; i < f.vertexNumber() && !deg; ++i) {
421 if (f.vertex(i) == f.vertexMod(i + 1)) {
422 deg = true;
423 m.deleteFace(m.index(f));
424 count++;
425 }
426 }
427 }
428 return count;
429}
430
431} // namespace vcl
432
433#endif // VCL_ALGORITHMS_MESH_CLEAN_H
A class representing a box in N-dimensional space.
Definition box.h:46
PointT size() const
Computes the size of the box.
Definition box.h:267
HasFaces concepts is satisfied when at least one of its template types is (or inherits from) a vcl::m...
Definition face_container.h:1389
constexpr uint UINT_NULL
The UINT_NULL value represent a null value of uint that is the maximum value that can be represented ...
Definition base.h:48
uint removeUnreferencedVertices(MeshType &m)
Marks as deleted all the non-deleted unreferenced vertices of the mesh.
Definition clean.h:157
uint removeDegeneratedVertices(MeshType &m, bool deleteAlsoFaces)
Removes all vertices that have position with invalid floating point values (NaN or inf).
Definition clean.h:351
uint removeDegenerateFaces(MeshType &m)
Removes all degenerate faces from the input mesh.
Definition clean.h:411
uint removeDuplicatedFaces(MeshType &m)
Removes all duplicate faces of the mesh by looking only at their vertex references.
Definition clean.h:296
uint removeDuplicatedVertices(MeshType &m)
Marks as deleted the duplicate vertices of the mesh, by looking only at their spatial positions.
Definition clean.h:211