Visual Computing Library
Loading...
Searching...
No Matches
face_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_FACE_TOPOLOGY_H
24#define VCL_ALGORITHMS_MESH_FACE_TOPOLOGY_H
25
26#include <vclib/algorithms/core/polygon/ear_cut.h>
27#include <vclib/concepts/mesh.h>
28#include <vclib/exceptions/mesh.h>
29#include <vclib/mesh/iterators/face/edge_adj_face_iterator.h>
30#include <vclib/misc/comparators.h>
31#include <vclib/space/complex/mesh_pos.h>
32#include <vclib/space/core/polygon.h>
33#include <vclib/views/mesh.h>
34
35#include <set>
36
37namespace vcl {
38
65template<FaceMeshConcept MeshType, FaceConcept FaceType>
66void addTriangleFacesFromPolygon(
67 MeshType& m,
68 FaceType& f,
69 const std::vector<uint>& polygon)
70{
71 using VertexType = MeshType::VertexType;
72 using CoordType = VertexType::CoordType;
73
74 // from the ids, create a polygon of coordinates
75 std::vector<CoordType> polCoords(polygon.size());
76 for (uint i = 0; i < polygon.size(); ++i) {
77 if (polygon[i] >= m.vertexContainerSize()) {
78 throw BadVertexIndexException(
79 "Index " + std::to_string(polygon[i]) +
80 " is out of range in Vertex Container.");
81 }
82 if (m.vertex(polygon[i]).deleted()) {
83 throw BadVertexIndexException(
84 "Vertex " + std::to_string(polygon[i]) + " is deleted.");
85 }
86 polCoords[i] = m.vertex(polygon[i]).coord();
87 }
88
89 // compute earcut of the polygons
90 std::vector<uint> tris = earCut(polCoords);
91
92 // faux edges management: create a set of unordered edges of the polygon
93 // note: we use indices from 0 to polygon.size() because that are the output
94 // indices given by the earcut algorithm
95 std::set<std::pair<uint, uint>, UnorderedPairComparator<uint>>
96 unorderedEdges;
97 for (uint i = 0; i < polygon.size(); ++i)
98 unorderedEdges.emplace(i, (i + 1) % (uint) polygon.size());
99
100 if constexpr (FaceType::VERTEX_NUMBER < 0) {
101 f.resizeVertices(3);
102 }
103
104 // set the first triangle of the loaded polygon
105 for (uint i = 0; i < f.vertexNumber(); ++i) {
106 f.setVertex(i, polygon[tris[i]]);
107 }
108
109 if constexpr (face::HasFaceBitFlags<FaceType>) {
110 if (unorderedEdges.find(std::make_pair(tris[0], tris[1])) ==
111 unorderedEdges.end())
112 f.edgeFaux(0) = true;
113 if (unorderedEdges.find(std::make_pair(tris[1], tris[2])) ==
114 unorderedEdges.end())
115 f.edgeFaux(1) = true;
116 if (unorderedEdges.find(std::make_pair(tris[2], tris[0])) ==
117 unorderedEdges.end())
118 f.edgeFaux(2) = true;
119 }
120
121 // remaining triangles, need to create more faces in the mesh
122 for (uint i = 3; i < tris.size(); i += 3) {
123 uint ff = m.addFace();
124
125 if constexpr (FaceType::VERTEX_NUMBER < 0) {
126 m.face(ff).resizeVertices(3);
127 }
128
129 for (uint j = 0; j < m.face(ff).vertexNumber(); ++j) {
130 m.face(ff).setVertex(j, polygon[tris[i + j]]);
131 }
132
133 if constexpr (face::HasFaceBitFlags<FaceType>) {
134 if (unorderedEdges.find(std::make_pair(tris[i], tris[i + 1])) ==
135 unorderedEdges.end())
136 m.face(ff).edgeFaux(0) = true;
137 if (unorderedEdges.find(std::make_pair(tris[i + 1], tris[i + 2])) ==
138 unorderedEdges.end())
139 m.face(ff).edgeFaux(1) = true;
140 if (unorderedEdges.find(std::make_pair(tris[i + 2], tris[i + 0])) ==
141 unorderedEdges.end())
142 m.face(ff).edgeFaux(2) = true;
143 }
144 }
145}
146
162template<FaceMeshConcept MeshType>
163uint addTriangleFacesFromPolygon(MeshType& m, const std::vector<uint>& polygon)
164{
165 uint fid = m.addFace();
166 addTriangleFacesFromPolygon(m, m.face(fid), polygon);
167 return fid;
168}
169
186template<FaceConcept FaceType>
187bool isFaceManifoldOnEdge(const FaceType& f, uint edge)
188 requires comp::HasAdjacentFaces<FaceType>
189{
190 // Check if the AdjacentFaces component is available for the given face.
191 if (!comp::isAdjacentFacesAvailableOn(f)) {
192 throw MissingComponentException(
193 "Face has no Adjacent Faces component.");
194 }
195
196 // Check if the edge is a boundary edge.
197 if (f.adjFace(edge) == nullptr) {
198 return true;
199 }
200 else { // Check if the edge is shared by exactly two faces.
201 return f.adjFace(edge)->indexOfAdjFace(&f) != UINT_NULL;
202 }
203}
204
221template<FaceConcept FaceType>
222bool isFaceEdgeOnBorder(const FaceType& f, uint edge)
223 requires comp::HasAdjacentFaces<FaceType>
224{
225 if (!comp::isAdjacentFacesAvailableOn(f)) {
226 throw MissingComponentException(
227 "Face has no Adjacent Faces component.");
228 }
229
230 return f->adjFace(edge) == nullptr;
231}
232
267template<FaceConcept FaceType>
268bool checkFlipEdge(const FaceType& f, uint edge)
269 requires comp::HasAdjacentFaces<FaceType>
270{
271 if (!comp::isAdjacentFacesAvailableOn(f)) {
272 throw MissingComponentException(
273 "Face has no Adjacent Faces component.");
274 }
275
276 using VertexType = FaceType::VertexType;
277
278 if (f.vertexNumber() > 3)
279 return false;
280
281 if (isFaceEdgeOnBorder(f, edge))
282 return false;
283
284 const VertexType* v0 = f.vertex(edge);
285 const VertexType* v1 = f.vertexMod(edge + 1);
286
287 const FaceType* of = f.adjFace(edge);
288 uint oe = of->indexOfAdjFace(&f);
289 assert(oe != UINT_NULL);
290
291 // check if the vertices of the edge are the same
292 // e.g. the mesh has to be well oriented
293 if (of->vertex(oe) != v1 || of->vertexMod(oe + 1) != v0)
294 return false;
295
296 // check if the flipped edge is already present in the mesh
297 // f_v2 and of_v2 are the vertices of the new edge
298 const VertexType* f_v2 = f.vertexMod(edge + 2);
299 const VertexType* of_v2 = of->vertexMod(oe + 2);
300
301 MeshPos<FaceType> pos(&f, f_v2);
302 MeshPos<FaceType> startPos = pos;
303 // loop in the one ring of f_v2
304 do {
305 pos.nextEdgeAdjacentToV();
306 if (pos.adjVertex() == of_v2)
307 return false;
308 } while (pos != startPos);
309
310 return true;
311}
312
333template<FaceConcept FaceType>
334uint edgeAdjacentFacesNumber(const FaceType& f, uint edge)
335 requires comp::HasAdjacentFaces<FaceType>
336{
337 if (!comp::isAdjacentFacesAvailableOn(f)) {
338 throw MissingComponentException(
339 "Face has no Adjacent Faces component.");
340 }
341
342 ConstEdgeAdjFaceIterator<FaceType> begin(f, edge), end;
343 uint cnt = 0;
344 for (auto it = begin; it != end; ++it) {
345 ++cnt;
346 }
347
348 return cnt;
349}
350
366template<FaceConcept FaceType>
367uint faceEdgesOnBorderNumber(const FaceType& f)
368 requires comp::HasAdjacentFaces<FaceType>
369{
370 if (!comp::isAdjacentFacesAvailableOn(f)) {
371 throw MissingComponentException(
372 "Face has no Adjacent Faces component.");
373 }
374
375 uint cnt = 0;
376 for (uint i = 0; i < f.vertexNumber(); ++i)
377 if (isFaceEdgeOnBorder(f, i))
378 cnt++;
379
380 return cnt;
381}
382
402template<FaceConcept FaceType>
403auto faceDihedralAngleOnEdge(const FaceType& f, uint e)
404 requires comp::HasAdjacentFaces<FaceType>
405{
406 if (!comp::isAdjacentFacesAvailableOn(f)) {
407 throw MissingComponentException(
408 "Face has no Adjacent Faces component.");
409 }
410
411 /*
412 * v0 ___________ vf1
413 * |\ |
414 * | e\ f1 |
415 * | \e1 |
416 * |f \ |
417 * | \ |
418 * |__________\|
419 * vf0 v1
420 */
421
422 assert(f.adjFace(e) != nullptr);
423 const FaceType& f1 = *(f.adjFace(e));
424
425 uint e1 = f1.indexOfAdjFace(&f);
426 assert(e1 != UINT_NULL);
427
428 const auto& vf0 = *(f.vertexMod((int) e - 1));
429 const auto& vf1 = *(f1.vertexMod(e1 - 1));
430
431 auto n0 = faceNormal(f);
432 auto n1 = faceNormal(f1);
433
434 auto off0 = n0 * vf0.coord();
435 auto off1 = n1 * vf1.coord();
436
437 auto dist01 = off0 - n0 * vf1.coord();
438 auto dist10 = off1 - n1 * vf0.coord();
439
440 auto sign = std::abs(dist01) > std::abs(dist10) ? dist01 : dist10;
441
442 auto angleRad = n0.angle(n1);
443 return sign > 0 ? angleRad : -angleRad;
444}
445
471template<FaceConcept FaceType>
472void detachAdjacentFacesOnEdge(FaceType& f, uint edge)
473 requires comp::HasAdjacentFaces<FaceType>
474{
475 if (!comp::isAdjacentFacesAvailableOn(f)) {
476 throw MissingComponentException(
477 "Face has no Adjacent Faces component.");
478 }
479
480 FaceType* nextFace = f.adjFace(edge);
481
482 // if nextFace == nullptr there is nothing to do
483 // the face is already detached on the edge
484 if (nextFace != nullptr) {
485 FaceType* prevFace;
486 ConstEdgeAdjFaceIterator<FaceType> begin(f, edge), end;
487 for (auto it = begin; it != end; ++it) {
488 prevFace = *it;
489 }
490
491 if (nextFace == prevFace) { // manifold case
492 uint en = nextFace->indexOfAdjFace(&f);
493 assert(en != UINT_NULL);
494 nextFace->setAdjFace(en, nullptr);
495 }
496 else { // non manifold case
497 // the prev face does not have to point to f anymore, but to
498 // nextFace
499 uint pn = prevFace->indexOfAdjFace(&f);
500 assert(pn != UINT_NULL);
501 prevFace->setAdjFace(pn, nextFace);
502 }
503 f.setAdjFace(edge, nullptr);
504 }
505}
506
528template<FaceConcept FaceType>
529void detachFace(FaceType& f) requires comp::HasAdjacentFaces<FaceType>
530{
531 if (!comp::isAdjacentFacesAvailableOn(f)) {
532 throw MissingComponentException(
533 "Face has no Adjacent Faces component.");
534 }
535
536 using VertexType = FaceType::VertexType;
537
538 for (uint e = 0; e < f.vertexNumber(); ++e) {
539 detachAdjacentFacesOnEdge(f, e);
540
541 // if the vertices have adjacent faces
542 if constexpr (comp::HasAdjacentFaces<VertexType>) {
543 if (comp::isAdjacentFacesAvailableOn(f.vertex(e))) {
544 VertexType* v = f.vertex(e);
545 uint vpos = v->indexOfAdjFace(&f);
546 if (vpos != UINT_NULL) { // may happen if vertex adj faces are
547 // not initialized / updated
548 v->eraseAdjFace(vpos); // the vertex v has not anymore the
549 // adjacent face f
550 }
551 }
552 }
553 }
554}
555
569template<FaceConcept FaceType>
570std::set<const FaceType*> floodFacePatch(
571 const FaceType& seed,
572 auto&& faceSelector)
573{
574 if (!comp::isAdjacentFacesAvailableOn(seed)) {
575 throw MissingComponentException(
576 "Face has no Adjacent Faces component.");
577 }
578
579 std::set<const FaceType*> faces;
580 // only faces that satisfy the faceSelector will stay on the stack
581 std::vector<const FaceType*> stackFaces;
582
583 if (!faceSelector(seed))
584 return faces;
585
586 faces.insert(&seed);
587
588 for (const FaceType* adjacent : seed.adjFaces()) {
589 // adding neighbor faces (if faceSelector returns true) to the stack
590 if (adjacent && faceSelector(*adjacent))
591 stackFaces.push_back(adjacent);
592 }
593
594 // while there aren't other faces on the stack
595 while (stackFaces.size() > 0) {
596 const FaceType* fi = stackFaces[stackFaces.size() - 1];
597 stackFaces.pop_back(); // pop
598 faces.insert(fi);
599 for (const FaceType* adjacent : fi->adjFaces()) {
600 if (adjacent && faceSelector(*adjacent)) {
601 if (faces.find(adjacent) == faces.end())
602 stackFaces.push_back(adjacent);
603 }
604 }
605 }
606 return faces;
607}
608
609} // namespace vcl
610
611#endif // VCL_ALGORITHMS_MESH_FACE_TOPOLOGY_H
FaceType::VertexType::CoordType faceNormal(const FaceType &f)
Computes the normal of a face, without modifying the face. Works both for triangle and polygonal face...
Definition geometry.h:45
std::vector< uint > earCut(Iterator begin, Iterator end)
Triangulates a simple polygon with no holes using the ear-cutting algorithm.
Definition ear_cut.h:92
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
constexpr detail::AdjFacesView adjFaces
The adjFaces view allows to obtain a view that access to the adjacent faces of the object that has be...
Definition adj_faces.h:65