Visual Computing Library
Loading...
Searching...
No Matches
topology.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_STAT_TOPOLOGY_H
24#define VCL_ALGORITHMS_MESH_STAT_TOPOLOGY_H
25
26#include <vclib/concepts/mesh.h>
27#include <vclib/mesh/requirements.h>
28
29#include <map>
30
31namespace vcl {
32
33namespace detail {
34
35// function called for the Container Cont of the Mesh
36template<typename Cont>
37void setReferencedVertices(const auto& mesh, auto& refs, uint& nRefs)
38{
39 // check if the Cont container of the Mesh has vertex references
40 if constexpr (comp::HasVertexReferences<typename Cont::ElementType>) {
41 // if there are still some vertices non-referenced
42 if (nRefs < mesh.vertexNumber()) {
43 constexpr uint ELEM_ID = Cont::ElementType::ELEMENT_ID;
44 // for eache element of the Cont container
45 for (const auto& el : mesh.template elements<ELEM_ID>()) {
46 // for each vertex of the element
47 for (uint vi : el.vertexIndices()) {
48 // vertex references shoule never be null
49 assert(vi != UINT_NULL);
50 if (!refs[vi]) {
51 // set the vertex as referenced
52 refs[vi] = true;
53 nRefs++;
54 }
55 }
56 }
57 }
58 }
59}
60
61// function called for each container of the Mesh, using variadic templates
62template<typename... Cont>
63void setReferencedVertices(
64 const auto& mesh,
65 auto& refs,
66 uint& nRefs,
67 TypeWrapper<Cont...>)
68{
69 // call the setReferencedVerticesOnVector function for each container of the
70 // mesh
71 (setReferencedVertices<Cont>(mesh, refs, nRefs), ...);
72}
73
74// struct to store the information of the wedge texcoords
75template<typename WedgeTexCoordType>
76struct WedgeTexCoordsInfo
77{
78 WedgeTexCoordType texCoord;
79 ushort texCoordIndex;
80
81 bool operator<(const WedgeTexCoordsInfo& other) const
82 {
83 if (texCoordIndex == other.texCoordIndex) {
84 return texCoord < other.texCoord;
85 }
86 return texCoordIndex < other.texCoordIndex;
87 }
88};
89
90inline std::list<uint> dummyUintList;
91inline std::list<std::list<std::pair<uint, uint>>> dummyListOfLists;
92inline std::vector<std::pair<uint, uint>> dummyVectorOfPairs;
93
94} // namespace detail
95
106uint countPerFaceVertexReferences(const MeshConcept auto& mesh)
107{
108 using MeshType = decltype(mesh);
109
110 uint nRefs = 0;
111
112 if constexpr (FaceMeshConcept<MeshType>) {
113 if constexpr (TriangleMeshConcept<MeshType>) {
114 return mesh.faceNumber() * 3;
115 }
116 else {
117 for (const auto& f : mesh.faces()) {
118 nRefs += f.vertexNumber();
119 }
120 }
121 }
122
123 return nRefs;
124}
125
135uint largestFaceSize(const MeshConcept auto& mesh)
136{
137 using MeshType = decltype(mesh);
138
139 uint maxFaceSize = 0;
140
141 if constexpr (TriangleMeshConcept<MeshType>) {
142 return 3;
143 }
144 else if constexpr (FaceMeshConcept<MeshType>) {
145 for (const auto& f : mesh.faces()) {
146 maxFaceSize = std::max(maxFaceSize, f.vertexNumber());
147 }
148 }
149
150 return maxFaceSize;
151}
152
161uint countTriangulatedTriangles(const MeshConcept auto& mesh)
162{
163 using MeshType = decltype(mesh);
164
165 uint nTris = 0;
166
167 if constexpr (FaceMeshConcept<MeshType>) {
168 for (const auto& f : mesh.faces()) {
169 nTris += f.vertexNumber() - 2;
170 }
171 }
172
173 return nTris;
174}
175
200template<typename Container, MeshConcept MeshType>
201Container referencedVertices(
202 const MeshType& mesh,
203 uint& nUnref,
204 bool onlyFaces = false)
205{
206 using VertexType = MeshType::VertexType;
207
208 uint nRefs = 0;
209
210 Container refVertices(mesh.vertexContainerSize(), false);
211
212 if (onlyFaces) {
213 if constexpr (FaceMeshConcept<MeshType>) {
214 using FaceContainer = MeshType::FaceContainer;
215
216 detail::setReferencedVertices(
217 mesh, refVertices, nRefs, TypeWrapper<FaceContainer>());
218 }
219 }
220 else {
221 detail::setReferencedVertices(
222 mesh, refVertices, nRefs, typename MeshType::Containers());
223 }
224
225 nUnref = mesh.vertexNumber() - nRefs;
226
227 return refVertices;
228}
229
254template<FaceMeshConcept MeshType>
255uint countVerticesToDuplicateByWedgeTexCoords(
256 const MeshType& mesh,
257 std::vector<std::pair<uint, uint>>& vertWedgeMap =
258 detail::dummyVectorOfPairs,
259 std::list<uint>& vertsToDuplicate = detail::dummyUintList,
260 std::list<std::list<std::pair<uint, uint>>>& facesToReassign =
261 detail::dummyListOfLists)
262{
264
265 using WedgeTexCoordType = MeshType::FaceType::WedgeTexCoordType;
266 using WedgeTexCoordsInfo = detail::WedgeTexCoordsInfo<WedgeTexCoordType>;
267
268 // list of faces that reference a wedge texcoord, with the index of the
269 // vertex in the face
270 using FaceList = std::list<std::pair<uint, uint>>;
271
272 vertWedgeMap.resize(mesh.vertexContainerSize());
273 vertsToDuplicate.clear();
274 facesToReassign.clear();
275
276 uint count = 0;
277
278 // for each vertex, I'll store a map of WedgeTexCoordsInfo
279 // each element of the map represent a unique wedge texcoord(the texcoord
280 // itself and the index of the texcoord), and for each element it maps a
281 // list of faces that reference the texcoord
282 std::vector<std::map<WedgeTexCoordsInfo, FaceList>> wedges(
283 mesh.vertexContainerSize());
284
285 // TODO: use compacted indices instead of f.index() in this loop
286 for (const auto& f : mesh.faces()) {
287 for (uint i = 0; i < f.vertexNumber(); ++i) {
288 uint vi = f.vertexIndex(i);
289
290 // check if the i-th wedge texcoord of the face already exists
291 WedgeTexCoordsInfo wi = {f.wedgeTexCoord(i), f.textureIndex()};
292 auto it = wedges[vi].find(wi);
293 if (it == wedges[vi].end()) { // if it doesn't exist, add it
294 // if there was already a texcoord for the vertex, it means that
295 // the vertex will be duplicated
296 if (!wedges[vi].empty()) {
297 count++;
298 }
299 wedges[vi][wi].emplace_back(f.index(), i);
300 }
301 else {
302 // if it exists, add the face to the list of faces that
303 // reference the texcoord
304 it->second.emplace_back(f.index(), i);
305 }
306 }
307 }
308
309 // for each vertex, check if there are multiple texcoords
310 // note: here we will modify the maps for convenience: at the end of this
311 // loop, the info will be contained in the two lists vertsToDuplicate and
312 // facesToReassign (the wedges vector of map will be inconsistent)
313 for (uint vi = 0; auto& map : wedges) {
314 if (map.size() > 1) {
315 // there are multiple texcoords for the vertex vi, so it will be
316 // duplicated
317
318 // remove from the map the element having the higher number of
319 // faces referencing the texcoord (we do this to reassign the less
320 // number of faces)
321 auto it = std::max_element(
322 map.begin(), map.end(), [](const auto& a, const auto& b) {
323 return a.second.size() < b.second.size();
324 });
325 // store the reference of the texcoord to keep (pair face/vertex
326 // index in the face)
327 vertWedgeMap[vi] = it->second.front();
328 map.erase(it);
329
330 // store the vertex to duplicate, and the faces to reassign
331 for (auto& [wi, fl] : map) {
332 vertsToDuplicate.push_back(vi);
333 facesToReassign.push_back(std::move(fl));
334 }
335 }
336 else {
337 if (map.size() == 1) {
338 // there is only one texcoord for the vertex vi, so store its
339 // reference (pair face/vertex index in the face)
340 vertWedgeMap[vi] = map.begin()->second.front();
341 }
342 else { // the vertex was unreferenced
343 vertWedgeMap[vi] = {UINT_NULL, UINT_NULL};
344 }
345 }
346 ++vi;
347 }
348
349 assert(vertWedgeMap.size() == mesh.vertexContainerSize());
350 assert(vertsToDuplicate.size() == count);
351 assert(facesToReassign.size() == count);
352
353 return count;
354}
355
356} // namespace vcl
357
358#endif // VCL_ALGORITHMS_MESH_STAT_TOPOLOGY_H
void requirePerFaceWedgeTexCoords(const MeshType &m)
This function asserts that a Mesh has a FaceContainer, the Face has a WedgeTexCoords Component,...
Definition face_requirements.h:947
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
constexpr detail::FacesView faces
A view that allows to iterate overt the Face elements of an object.
Definition face.h:52