-
Notifications
You must be signed in to change notification settings - Fork 5
/
mesh.h
370 lines (303 loc) · 8.77 KB
/
mesh.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
/*!
* @file mesh.h
* @brief Data structures for representing a mesh
*/
#ifndef __MESH_H__
#define __MESH_H__
#include <iostream>
#include <vector>
#include <string>
#include <utility>
#include <set>
#include <map>
#include <limits>
#include "vertex.h"
#include "directed_edge.h"
#include "edge.h"
#include "face.h"
namespace psalm
{
/*!
* @class mesh
* @brief Represents a mesh
*/
class mesh
{
public:
// Enumerating the different file types that may occur
enum file_type
{
TYPE_PLY,
TYPE_OBJ,
TYPE_OFF,
TYPE_EXT
};
// Status flags for mesh::load() and mesh::save(). By using a
// three-valued status the function is able to check whether
// all other means of loading and saving have failed. If this
// is the case, a fallback to loading/saving .PLY files may be
// performed.
enum status
{
STATUS_OK,
STATUS_ERROR,
STATUS_UNDEFINED
};
mesh();
~mesh();
bool load(const std::string& filename, file_type type = TYPE_EXT);
bool save(const std::string& filename, file_type type = TYPE_EXT);
bool load_raw_data(int num_vertices, long* vertex_IDs, double* coordinates, double* scale_attributes = NULL, double* normals = NULL);
bool save_raw_data(int* num_new_vertices, double** new_coordinates, int* num_faces, long** vertex_IDs);
void prune( const std::set<size_t>& remove_faces,
const std::set<size_t>& remove_vertices);
void destroy();
void replace_with(mesh& M);
double get_density();
// Functions for modifying the topology of the mesh
vertex* add_vertex(double x, double y, double z, size_t id = std::numeric_limits<size_t>::max());
vertex* add_vertex(double x, double y, double z, double nx, double ny, double nz, size_t id = std::numeric_limits<size_t>::max());
vertex* add_vertex(const v3ctor& pos, size_t id = std::numeric_limits<size_t>::max());
void remove_vertex(vertex* v);
size_t num_vertices() const;
vertex* get_vertex(size_t i);
size_t num_edges() const;
edge* get_edge(size_t i);
bool relax_edge(edge* e);
face* add_face(std::vector<vertex*> vertices, bool ignore_orientation_warning = false);
face* add_face(vertex* v1, vertex* v2, vertex* v3, bool ignore_orientation_warning = false);
face* add_face(vertex* v1, vertex* v2, vertex* v3, vertex* v4, bool ignore_orientation_warning = false);
void remove_face(face* f);
size_t num_faces() const;
face* get_face(size_t i);
protected:
// Data variables
std::vector<vertex*> V;
std::vector<edge*> E;
std::vector<face*> F;
std::map<std::pair<size_t,size_t>, edge*> E_M;
size_t id_offset;
// Internal functions
directed_edge add_edge(vertex* u, vertex* v);
void remove_edge(edge* e);
std::pair<size_t, size_t> calc_edge_id(const vertex* u, const vertex* v);
std::pair<vertex*, vertex*> find_remaining_vertices(const vertex* v, const face* f);
void mark_boundaries();
bool load_ply(std::istream& in);
bool load_obj(std::istream& in);
bool load_off(std::istream& in);
bool save_ply(std::ostream& out);
bool save_obj(std::ostream& out);
bool save_off(std::ostream& out);
bool save_hole(std::ostream& out);
};
/*!
* Adds a vertex to the mesh. If not specified by the user, the vertex ID
* is assigned automatically.
*
* @param x x position of vertex
* @param y y position of vertex
* @param z z position of vertex
* @param id Vertex ID (by default, this is set to the largest
* number fitting into a size_t and thus will be ignored)
*
* @warning The vertices are not checked for duplicates because this
* function is assumed to be called from internal methods only.
*
* @return Pointer to new vertex. The pointer remains valid during the
* lifecycle of the mesh.
*/
inline vertex* mesh::add_vertex(double x, double y, double z, size_t id)
{
return(add_vertex( x,
y,
z,
0.0, // default normal vector
0.0,
0.0,
id));
}
/*!
* Adds a vertex to the mesh. If not specified by the user, the vertex ID
* is assigned automatically.
*
* @param x x position of vertex
* @param y y position of vertex
* @param z z position of vertex
* @param nx x position of normal vector
* @param ny y position of normal vector
* @param nz z position of normal vector
* @param id Vertex ID (by default, this is set to the largest
* number fitting into a size_t and thus will be ignored)
*
* @warning The vertices are not checked for duplicates because this
* function is assumed to be called from internal methods only.
*
* @return Pointer to new vertex. The pointer remains valid during the
* lifecycle of the mesh.
*/
inline vertex* mesh::add_vertex(double x, double y, double z, double nx, double ny, double nz, size_t id)
{
vertex* v;
if(id != std::numeric_limits<size_t>::max())
v = new vertex(x,y,z, nx, ny, nz, id);
else
v = new vertex(x,y,z, nx, ny, nz, V.size()+id_offset);
V.push_back(v);
return(v);
}
/*!
* Adds a vertex to the mesh. If not specified by the user, the vertex ID
* is assigned automatically.
*
* @param pos Position of the new vertex
* @param id Vertex ID (by default, this is set to the largest
* number fitting into a size_t and thus will be ignored)
*
* @warning The vertices are not checked for duplicates because this
* function is assumed to be called from internal methods only.
*
* @return Pointer to new vertex. The pointer remains valid during the
* lifecycle of the mesh.
*/
inline vertex* mesh::add_vertex(const v3ctor& pos, size_t id)
{
return(add_vertex(pos[0], pos[1], pos[2], id));
}
/*!
* Removes a vertex from the list of vertices and frees allocated memory.
* This function invalidates the integrity of the list of edges, so it
* should _only_ be used if all edges have already been processed.
*
* @param v Vertex to remove from the mesh
*/
inline void mesh::remove_vertex(vertex* v)
{
std::remove(V.begin(), V.end(), v);
delete v;
}
/*!
* @return Number of vertices currently stored in the mesh.
*/
inline size_t mesh::num_vertices() const
{
return(V.size());
}
/*!
* @param i Index of desired vertex
*
* @return ith vertex of the mesh. Caller has to ensure that vertex index
* is correct.
*/
inline vertex* mesh::get_vertex(size_t i)
{
return(V[i]);
}
/*!
* @return Number of edges currently stored in the mesh.
*/
inline size_t mesh::num_edges() const
{
return(E.size());
}
/*!
* @param i Index of desired edge
*
* @return ith edge in the mesh. Caller has to ensure that the edge index
* is valid.
*/
inline edge* mesh::get_edge(size_t i)
{
return(E[i]);
}
/*!
* @return Number of faces currently stored in the mesh.
*/
inline size_t mesh::num_faces() const
{
return(F.size());
}
/*!
* @param i Index of desired face
*
* @return ith face in the mesh. Caller has to ensure that the face index
* is valid.
*/
inline face* mesh::get_face(size_t i)
{
return(F[i]);
}
/*!
* Adds a triangular face to the mesh. This function allows the caller to
* specify 3 vertices that will form the new triangle. Thus, specifying a
* vector of pointers is not necessary.
*
* @param v1 Pointer to 1st vertex of new face
* @param v2 Pointer to 2nd vertex of new face
* @param v3 Pointer to 3rd vertex of new face
*
* @param ignore_orientiation_warning Instructs function to ignore
* warnings pertaining to a wrong orientation.
*
* @warning The vertex pointers are not checked for consistency.
*
* @returns Pointer to new face
*/
inline face* mesh::add_face(vertex* v1, vertex* v2, vertex* v3, bool ignore_orientiation_warning)
{
std::vector<vertex*> vertices;
vertices.push_back(v1);
vertices.push_back(v2);
vertices.push_back(v3);
return(add_face(vertices, ignore_orientiation_warning));
}
/*!
* Adds a quadrangular face to the mesh. This function allows the caller
* to specify 4 vertices that will form the new quadrangle. Thus,
* specifying a vector of pointers is not necessary.
*
* @param v1 Pointer to 1st vertex of new face
* @param v2 Pointer to 2nd vertex of new face
* @param v3 Pointer to 3rd vertex of new face
* @param v4 Pointer to 4th vertex of new face
*
* @param ignore_orientiation_warning Instructs function to ignore
* warnings pertaining to a wrong orientation.
*
* @warning The vertex pointers are not checked for consistency and
* planarity.
*
* @returns Pointer to new face
*/
inline face* mesh::add_face(vertex* v1, vertex* v2, vertex* v3, vertex* v4, bool ignore_orientiation_warning)
{
std::vector<vertex*> vertices;
vertices.push_back(v1);
vertices.push_back(v2);
vertices.push_back(v3);
vertices.push_back(v4);
return(add_face(vertices, ignore_orientiation_warning));
}
/*!
* @returns ID of the edge described by vertices u and v, which is given
* as an std::pair sorted by vertex IDs.
*/
inline std::pair<size_t, size_t> mesh::calc_edge_id(const vertex* u, const vertex* v)
{
std::pair<size_t, size_t> id;
size_t u_id = u->get_id();
size_t v_id = v->get_id();
if(u_id < v_id)
{
id.first = u_id;
id.second = v_id;
}
else
{
id.first = v_id;
id.second = u_id;
}
return(id);
}
} // end of namespace "psalm"
#endif