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

pmp-library / pmp-library / 25867071622

14 May 2026 02:52PM UTC coverage: 89.671% (-0.1%) from 89.809%
25867071622

push

github

dsieger
Missing include

5209 of 5809 relevant lines covered (89.67%)

624791.71 hits per line

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

69.41
/src/pmp/io/read_obj.cpp
1
// Copyright 2011-2022 the Polygon Mesh Processing Library developers.
2
// SPDX-License-Identifier: MIT
3

4
#include "pmp/io/read_obj.h"
5
#include "pmp/exceptions.h"
6

7
namespace pmp {
8

9
void read_obj(SurfaceMesh& mesh, const std::filesystem::path& file)
1✔
10
{
11
    std::array<char, 200> s;
12
    float x, y, z, r, g, b;
13
    std::vector<Vertex> vertices;
1✔
14
    std::vector<TexCoord> all_tex_coords; //individual texture coordinates
1✔
15
    std::vector<int>
16
        halfedge_tex_idx; //texture coordinates sorted for halfedges
1✔
17
    HalfedgeProperty<TexCoord> tex_coords =
18
        mesh.halfedge_property<TexCoord>("h:tex");
3✔
19
    bool with_tex_coord = false;
1✔
20
    VertexProperty<Color> colors;
1✔
21

22
    // open file (in ASCII mode)
23
    FILE* in = fopen(file.string().c_str(), "r");
1✔
24
    if (!in)
1✔
25
        throw IOException("Failed to open file: " + file.string());
×
26

27
    // clear line once
28
    memset(s.data(), 0, 200);
1✔
29

30
    // parse line by line (currently only supports vertex positions & faces
31
    while (in && !feof(in) && fgets(s.data(), 200, in))
12✔
32
    {
33
        // comment
34
        if (s[0] == '#' || isspace(s[0]))
5✔
35
            continue;
1✔
36

37
        // vertex
38
        else if (strncmp(s.data(), "v ", 2) == 0)
4✔
39
        {
40
            const int n =
41
                sscanf(s.data(), "v %f %f %f %f %f %f", &x, &y, &z, &r, &g, &b);
3✔
42
            if (n >= 3)
3✔
43
            {
44
                const Vertex v = mesh.add_vertex(Point(x, y, z));
3✔
45
                if (n >= 6)
3✔
46
                {
47
                    if (!colors)
×
48
                        colors = mesh.vertex_property<Color>("v:color");
×
49
                    colors[v] = Color(r, g, b);
×
50
                }
51
            }
52
        }
53

54
        // normal
55
        else if (strncmp(s.data(), "vn ", 3) == 0)
1✔
56
        {
57
            if (sscanf(s.data(), "vn %f %f %f", &x, &y, &z))
×
58
            {
59
                // problematic as it can be either a vertex property when interpolated
60
                // or a halfedge property for hard edges
61
            }
62
        }
63

64
        // texture coordinate
65
        else if (strncmp(s.data(), "vt ", 3) == 0)
1✔
66
        {
67
            if (sscanf(s.data(), "vt %f %f", &x, &y))
×
68
            {
69
                all_tex_coords.emplace_back(x, y);
×
70
            }
71
        }
72

73
        // face
74
        else if (strncmp(s.data(), "f ", 2) == 0)
1✔
75
        {
76
            int component(0);
1✔
77
            bool end_of_vertex(false);
1✔
78
            char *p0, *p1(s.data() + 1);
1✔
79

80
            vertices.clear();
1✔
81
            halfedge_tex_idx.clear();
1✔
82

83
            // skip white-spaces
84
            while (*p1 == ' ')
2✔
85
                ++p1;
1✔
86

87
            while (p1)
4✔
88
            {
89
                p0 = p1;
3✔
90

91
                // overwrite next separator
92

93
                // skip '/', '\n', ' ', '\0', '\r' <-- don't forget Windows
94
                while (*p1 != '/' && *p1 != '\r' && *p1 != '\n' && *p1 != ' ' &&
6✔
95
                       *p1 != '\0')
3✔
96
                    ++p1;
3✔
97

98
                // detect end of vertex
99
                if (*p1 != '/')
3✔
100
                {
101
                    end_of_vertex = true;
3✔
102
                }
103

104
                // replace separator by '\0'
105
                if (*p1 != '\0')
3✔
106
                {
107
                    *p1 = '\0';
3✔
108
                    p1++; // point to next token
3✔
109
                }
110

111
                // detect end of line and break
112
                if (*p1 == '\0' || *p1 == '\n')
3✔
113
                {
114
                    p1 = nullptr;
1✔
115
                }
116

117
                // read next vertex component
118
                if (*p0 != '\0')
3✔
119
                {
120
                    switch (component)
3✔
121
                    {
122
                        case 0: // vertex
3✔
123
                        {
124
                            int idx = atoi(p0);
3✔
125
                            if (idx < 0)
3✔
126
                                idx = mesh.n_vertices() + idx + 1;
×
127
                            vertices.emplace_back(idx - 1);
3✔
128
                            break;
3✔
129
                        }
130
                        case 1: // texture coord
×
131
                        {
132
                            const int idx = atoi(p0) - 1;
×
133
                            halfedge_tex_idx.push_back(idx);
×
134
                            with_tex_coord = true;
×
135
                            break;
×
136
                        }
137
                        case 2: // normal
×
138
                            break;
×
139
                    }
140
                }
141

142
                ++component;
3✔
143

144
                if (end_of_vertex)
3✔
145
                {
146
                    component = 0;
3✔
147
                    end_of_vertex = false;
3✔
148
                }
149
            }
150

151
            Face f;
1✔
152
            try
153
            {
154
                f = mesh.add_face(vertices);
1✔
155
            }
156
            catch (const TopologyException& e)
×
157
            {
158
                std::cerr << e.what();
×
159
            }
×
160

161
            // add texture coordinates
162
            if (with_tex_coord && f.is_valid())
1✔
163
            {
164
                auto h_fit = mesh.halfedges(f);
×
165
                auto h_end = h_fit;
×
166
                unsigned v_idx = 0;
×
167
                do
168
                {
169
                    tex_coords[*h_fit] =
×
170
                        all_tex_coords.at(halfedge_tex_idx.at(v_idx));
×
171
                    ++v_idx;
×
172
                    ++h_fit;
×
173
                } while (h_fit != h_end);
×
174
            }
175
        }
176
        // clear line
177
        memset(s.data(), 0, 200);
4✔
178
    }
179

180
    // if there are no textures, delete texture property!
181
    if (!with_tex_coord)
1✔
182
    {
183
        mesh.remove_halfedge_property(tex_coords);
1✔
184
    }
185

186
    fclose(in);
1✔
187
}
1✔
188

189
} // 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