• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pmp-library / pmp-library / 25871107477

14 May 2026 04:11PM UTC coverage: 89.671% (+0.02%) from 89.656%
25871107477

push

github

dsieger
Check for degenerate faces

17 of 18 new or added lines in 1 file covered. (94.44%)

1 existing line in 1 file now uncovered.

5226 of 5828 relevant lines covered (89.67%)

637854.26 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

79.1
/src/pmp/algorithms/analysis.cpp
1
// Copyright 2026 the Polygon Mesh Processing Library developers.
2
// SPDX-License-Identifier: MIT
3

4
#include "pmp/algorithms/analysis.h"
5
#include "pmp/algorithms/utilities.h"
6
#include "pmp/algorithms/differential_geometry.h"
7
#include "pmp/tolerances.h"
8

9
#include <queue>
10

11
namespace pmp {
12

13
namespace {
14

15
// const version of connected_components, count only
16
int count_connected_components(const SurfaceMesh& mesh)
11✔
17
{
18
    std::vector<bool> visited(mesh.n_vertices(), false);
11✔
19

20
    int count = 0;
11✔
21

22
    for (auto v : mesh.vertices())
117✔
23
    {
24
        if (visited[v.idx()])
106✔
25
            continue;
93✔
26

27
        std::queue<Vertex> queue;
13✔
28
        queue.push(v);
13✔
29
        visited[v.idx()] = true;
13✔
30

31
        while (!queue.empty())
119✔
32
        {
33
            auto vv = queue.front();
106✔
34
            queue.pop();
106✔
35

36
            for (auto vc : mesh.vertices(vv))
414✔
37
            {
38
                if (!visited[vc.idx()])
308✔
39
                {
40
                    visited[vc.idx()] = true;
93✔
41
                    queue.push(vc);
93✔
42
                }
43
            }
44
        }
45

46
        ++count;
13✔
47
    }
13✔
48

49
    return count;
11✔
50
}
11✔
51

52
bool is_degenerate(const SurfaceMesh& mesh, Face f, Scalar eps)
65✔
53
{
54
    bool degenerate = false;
65✔
55

56
    // check for zero area
57
    if (face_area(mesh, f) < eps * eps)
65✔
58
        degenerate = true;
3✔
59

60
    // check for short edges
61
    for (auto h : mesh.halfedges(f))
581✔
62
        if (edge_length(mesh, mesh.edge(h)) < eps)
258✔
63
            degenerate = true;
7✔
64

65
    return degenerate;
65✔
66
}
67

68
} // namespace
69

70
AnalysisReport analyze(const SurfaceMesh& mesh)
11✔
71
{
72
    AnalysisReport report;
11✔
73

74
    // basic stats
75
    report.n_vertices = mesh.n_vertices();
11✔
76
    report.n_edges = mesh.n_edges();
11✔
77
    report.n_faces = mesh.n_faces();
11✔
78

79
    // mesh type
80
    report.is_triangle_mesh = mesh.is_triangle_mesh();
11✔
81
    report.is_quad_mesh = mesh.is_quad_mesh();
11✔
82

83
    // manifoldness and boundary
84
    for (auto v : mesh.vertices())
223✔
85
    {
86
        if (!mesh.is_manifold(v))
106✔
87
            report.is_manifold = false;
1✔
88
        if (mesh.is_boundary(v))
106✔
89
            report.has_boundary = true;
52✔
90
        if (mesh.is_isolated(v))
106✔
91
            ++report.n_isolated_vertices;
3✔
92
    }
93

94
    // eps according to bounding box diagonal
95
    constexpr Scalar relative_eps = detail::relative_epsilon<Scalar>();
11✔
96
    constexpr Scalar absolute_eps = detail::absolute_epsilon<Scalar>();
11✔
97
    const Scalar diagonal = bounds(mesh).size();
11✔
98
    const Scalar eps = std::max(relative_eps * diagonal, absolute_eps);
11✔
99

100
    std::cerr << "Bounding box diagonal: " << diagonal << ", eps: " << eps
11✔
101
              << std::endl;
11✔
102

103
    for (auto f : mesh.faces())
141✔
104
        if (is_degenerate(mesh, f, eps))
65✔
105
            ++report.n_degenerate_faces;
3✔
106

107
    report.n_components = count_connected_components(mesh);
11✔
108

109
    return report;
22✔
110
}
111

112
std::ostream& operator<<(std::ostream& os, const AnalysisReport& report)
×
113
{
114
    os << "Analysis Report:\n";
×
115
    os << "  vertices: " << report.n_vertices << "\n";
×
116
    os << "  edges: " << report.n_edges << "\n";
×
117
    os << "  faces: " << report.n_faces << "\n";
×
118
    os << "  boundary: " << (report.has_boundary ? "yes" : "no") << "\n";
×
119
    os << "  manifold: " << (report.is_manifold ? "yes" : "no") << "\n";
×
120
    os << "  triangle mesh: " << (report.is_triangle_mesh ? "yes" : "no")
×
121
       << "\n";
×
122
    os << "  quad mesh: " << (report.is_quad_mesh ? "yes" : "no") << "\n";
×
123
    os << "  components: " << report.n_components << "\n";
×
124
    os << "  isolated vertices: " << report.n_isolated_vertices << "\n";
×
NEW
125
    os << "  degenerate faces: " << report.n_degenerate_faces << "\n";
×
UNCOV
126
    return os;
×
127
}
128

129
} // namespace pmp
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc