Subversion Repositories gelsvn

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
688 khor 1
/* ----------------------------------------------------------------------- *
2
 * This file is part of GEL, http://www.imm.dtu.dk/GEL
3
 * Copyright (C) the authors and DTU Informatics
4
 * For license and list of authors, see ../../doc/intro.pdf
5
 * ----------------------------------------------------------------------- */
6
 
7
/**
8
 * @file Manifold.h
9
 * @brief The Manifold class is the main data structure of HMesh - the actual mesh.
10
 */
11
 
12
#pragma once
13
 
14
#include <algorithm>
15
#include "../CGLA/Vec3d.h"
16
 
17
#include "ConnectivityKernel.h"
18
#include "Iterators.h"
19
#include "Walker.h"
20
#include "AttributeVector.h"
21
 
22
 
23
namespace Geometry
24
{
25
    // forward declaration
26
    class TriMesh;
27
    class IndexedFaceSet;
28
}
29
 
30
namespace HMesh
31
{
32
    /** The Manifold class represents a halfedge based mesh. Since meshes based on the halfedge
33
     representation must be manifold (although exceptions could be made) the class is thus named.
34
     Manifold contains many functions for mesh manipulation and associated the position attribute
35
     with vertices.*/
36
 
37
    class Manifold
38
    {
39
    public:
40
 
41
        /// Vector type used for positions of vertices.
42
        typedef CGLA::Vec3d Vec;
43
 
44
        /// Default constructor
45
        Manifold();
46
 
47
        /** \brief Build a manifold. 
48
        The arguments are the number of vertices, no_vertices, the vector of vertices, vertvec, the number of faces, no_faces. 
49
        facevecis an array where each entry indicates the number of vertices in that face. 
50
        The array indices contains all the corresponding vertex indices in one concatenated list. */
51
        void build( size_t no_vertices,
52
                    const float* vertvec,
53
                    size_t no_faces,
54
                    const int* facevec,
55
                    const int* indices);
56
 
57
        /** \brief Build a manifold.
58
         This function is for vertices given in double precision.
59
         The arguments are the number of vertices, no_vertices, the vector of vertices, vertvec, the number of faces, no_faces.
60
         facevecis an array where each entry indicates the number of vertices in that face.
61
         The array indices contains all the corresponding vertex indices in one concatenated list. */
62
        void build( size_t no_vertices,
63
                   const double* vertvec,
64
                   size_t no_faces,
65
                   const int* facevec,
66
                   const int* indices);
67
 
68
        /// Build a manifold from a TriMesh
69
        void build(const Geometry::TriMesh& mesh);
70
 
71
        /** Add a face to the Manifold.
72
         This function is provided a vector of points in space and transforms it into a single 
73
         polygonal face calling build. It is purely for convenience. */
74
        FaceID add_face(std::vector<Manifold::Vec> points);
75
 
76
        /** Removes a face from the Manifold. If it is an interior face it is simply replaces
77
         by an InvalidFaceID. If the face contains boundary edges, these are removed. Situations
78
         may arise where the mesh is no longer manifold because the situation at a boundary vertex
79
         is not homeomorphic to a half disk. This, we can probably ignore since from the data
80
         structure point of view it is not really a problem that a vertex is incident on two holes - 
81
        a hole can be seen as a special type of face. The function returns false if the FaceID is 
82
         not valid, otherwise the function must complete. */
83
        bool remove_face(FaceID fid);
84
 
85
        /** Remove an edge from the Manifold.
86
            This function will remove the faces on either side and the edge itself in the process. Thus,
87
         it is a simple application of remove_face. */
88
        bool remove_edge(HalfEdgeID hid);
89
 
90
        /** Remove a vertex from the Manifold.
91
         This function merges all faces around the vertex into one and then removes 
92
         this resulting face. */
93
        bool remove_vertex(VertexID vid);
94
 
95
        /// number of  vertices
96
        size_t no_vertices() const { return kernel.no_vertices();}
97
        /// number of active faces
98
        size_t no_faces() const { return kernel.no_faces();}
99
        /// number of active halfedges
100
        size_t no_halfedges() const { return kernel.no_halfedges();}
101
 
102
        /// number of total vertices in kernel
103
        size_t allocated_vertices() const { return kernel.allocated_vertices();}
104
        /// number of total faces in kernel
105
        size_t allocated_faces() const { return kernel.allocated_faces();}
106
        /// number of total halfedges in kernel
107
        size_t allocated_halfedges() const { return kernel.allocated_halfedges();}
108
 
109
        /// check if ID of vertex is in use
110
        bool in_use(VertexID id) const { return kernel.in_use(id);}
111
        /// check if ID of face is in use
112
        bool in_use(FaceID id) const { return kernel.in_use(id);}
113
        /// check if ID of halfedge is in use
114
        bool in_use(HalfEdgeID id) const { return kernel.in_use(id);}
115
 
116
        IDIteratorPair<Vertex> vertices() const {return IDIteratorPair<Vertex>(kernel.vertices_begin(),
117
                                                                         kernel.vertices_end());}
118
        IDIteratorPair<Face> faces() const {return IDIteratorPair<Face>(kernel.faces_begin(),
119
                                                                         kernel.faces_end());}
120
        IDIteratorPair<HalfEdge> halfedges() const {return IDIteratorPair<HalfEdge>(kernel.halfedges_begin(),
121
                                                                         kernel.halfedges_end());}
122
 
123
        /// Iterator to first VertexID, optional argument defines if unused items should be skipped
124
        VertexIDIterator vertices_begin(bool skip = true) const { return kernel.vertices_begin();}
125
        /// Iterator to first FaceID, optional argument defines if unused items should be skipped
126
        FaceIDIterator faces_begin(bool skip = true) const { return kernel.faces_begin();}
127
        /// Iterator to first HalfEdgeID, optional argument defines if unused items should be skipped
128
        HalfEdgeIDIterator halfedges_begin(bool skip = true) const { return kernel.halfedges_begin();}
129
 
130
        /// Iterator to past the end VertexID
131
        VertexIDIterator vertices_end() const { return kernel.vertices_end();}
132
        /// Iterator topast the end FaceID
133
        FaceIDIterator faces_end() const { return kernel.faces_end();}
134
        /// Iterator to past the end HalfEdgeID
135
        HalfEdgeIDIterator halfedges_end() const {return kernel.halfedges_end(); }  
136
 
137
 
138
		/** \brief Bridge f0 and f1 by connecting the vertex pairs given in pairs.
139
		 This function creates a cylindrical connection between f0 and f1. f0 and f1 are removed and the vertices 
140
		 given in pairs are connected by edges. The result is a cylindrical connection that changes the genus of the object.
141
 
142
		 This function leaves all error chethising in the hands of the user (for now). The faces clearly should not have any 
143
		 vertices or edges in common as this will create a non-manifold situation. Also the faces should face towards or away 
144
		 from each other and be in a position where it is reasonable to make the bridge. The connections should also make sense 
145
		 from a geometric point of view and should be in a counter clothiswise loop on f0 and a clothiswise loop on f1. No need to 
146
		 connect all vertices.
147
 
148
		 The function returns a vector of HalfEdgeIDs. Those are, of course, the connecting halfedges - also the opposite edges.
149
		 */
150
		std::vector<HalfEdgeID> bridge_faces(FaceID f0, FaceID f1, const std::vector<std::pair<VertexID, VertexID> >& pairs);
151
 
152
 
153
        /** \brief Collapse the halfedge h.
154
        The argument h is the halfedge being removed. The vertex v=h->opp->vert is the one being removed while h->vert survives.
155
        The final argument indicates whether the surviving vertex should have the average position of the former vertices.
156
        By default false meaning that the surviving vertex retains it position.
157
        This function is not guaranteed to keep the mesh sane unless, precond_collapse_edge has returned true !! */
158
        void collapse_edge(HalfEdgeID h, bool avg_vertices = false);
159
 
160
        /** \brief Split a face.
161
        The face, f, is split by creating an edge with endpoints v0 and v1 (the next two arguments). 
162
        The vertices of the old face between v0 and v1 (in counter clothiswise order) continue to belong to f. 
163
        The vertices between v1 and v0 belong to the new face. A handle to the new face is returned. */
164
        FaceID split_face_by_edge(FaceID f, VertexID v0, VertexID v1);
165
 
166
        /** \brief Split a polygon, f, by inserting a vertex at the barycenter.			
167
        This function is less likely to create flipped triangles than the split_face_triangulate function. 
168
        On the other hand, it introduces more vertices and probably makes the triangles more acute.
169
        A handle to the inserted vertex is returned. */
170
        VertexID split_face_by_vertex(FaceID f);
171
       // VertexID split_face_by_vertex(HalfEdgeID h);
172
 
173
        /** \brief Insert a new vertex on halfedge h.
174
        The new halfedge is insterted as the previous edge to h.
175
        A handle to the inserted vertex is returned. */
176
        VertexID split_edge(HalfEdgeID h);
177
 
178
        /** \brief Stitch two halfedges.
179
         Two boundary halfedges can be stitched together. This can be used to build a complex mesh
180
         from a bunch of simple faces. */
181
        bool stitch_boundary_edges(HalfEdgeID h0, HalfEdgeID h1);
182
 
183
        /** \brief Merges two faces into a single polygon. 
184
        The first face is f. The second face is adjacent to f along the halfedge h. 
185
        This function returns true if the merging was possible and false otherwise. 
186
        Currently merge only fails if the mesh is already illegal. Thus it should, in fact, never fail. */
187
        bool merge_faces(FaceID f, HalfEdgeID h);
188
 
189
		/** \brief Merge all faces in the one ring of a vertex into a single polygon.
190
		The vertex is given by v.
191
 
192
		The return value is the FaceID of the resulting polygonal face. 
193
		InvalidFaceID is returned if 
194
		- the input vertex is not in use or 
195
		- the input vertex has valence less than two which is a degenerate case.
196
		- the input vertex is a boundary vertex of valence two - i.e. adjacent to just one face.
197
		- the same halfedge appears in two faces of the one ring of the input vertex: I.e.
198
		the input vertex is twice adjacent to the same face!
199
 
200
		Note that this function can create some unusual and arguably degenerate meshes. For instance, 
201
		two triangles which share all vertices is collapsed to a single pair of vertices connected by 
202
		a pair of halfedges bounding the same face. */
203
		FaceID merge_one_ring(VertexID v, float max_loop_length = FLT_MAX);
204
 
205
        /** \brief Close hole given by the invalid face of halfedgehandle h.
206
         returns FaceID of the created face or the face that is already there if the 
207
         face was not InvalidFaceID. */
208
        FaceID close_hole(HalfEdgeID h);
209
 
210
        /** \brief Create hole by opening a slit at a vertex.
211
        This function creates a hole by slitting the mesh at a vertex v along a pair of halfedges.
212
        The function returns the vertex created by this operation.
213
        The first halfedge h_in is oriented towards the vertex and the second, h_out, away from the 
214
        vertex. Neither h_in nor h_out may be boundary halfedges for a hole since the result would be
215
        two holes separated by an edge. That is an abomination we should avoid. In particular because
216
        it would be invisible. h_in and h_out also should not be each other's opposite edges. That would 
217
         result in an isolated vertex. */
218
         VertexID slit_vertex(VertexID v, HalfEdgeID h_in, HalfEdgeID h_out);
219
 
220
        /** \brief Create hole by slitting open the mesh along the path given as argument.
221
         This function returns the HalfEdgeID of one of the halfedges bounding the created hole.
222
         The path is specified as a selection set of vertices. If the selected vertices form a closed 
223
         loop, a piece is cut off from the mesh. Surprising results can occur if the selected vertices
224
         can be connected by more than one sequence (or a self intersecting sequence) of edges. */
225
        HalfEdgeID slit_edges(VertexAttributeVector<int>& selection);
226
 
227
        /// \brief Flip an edge h. 
228
        void flip_edge(HalfEdgeID h);
229
 
230
        /// Return reference to position given by VertexID
231
        Vec& pos(VertexID id);
232
        /// Return const reference to position given by VertexID
233
        const Vec& pos(VertexID id) const;
234
 
235
        /// Return a reference to the entire positions attribute vector
236
        VertexAttributeVector<Vec>& positions_attribute_vector();
237
 
238
        /// Return a const reference to the entire positions attribute vector
239
        const VertexAttributeVector<Vec>& positions_attribute_vector() const;
240
 
241
        /// Clear the mesh. Remove all faces, halfedges, and vertices.
242
        void clear();
243
 
244
        /// Remove unused items from Mesh, map argument is to be used for attribute vector cleanups in order to maintain sync.
245
        void cleanup(IDRemap& map);
246
        /// Remove unused items from Mesh
247
        void cleanup();
248
 
249
        /// Returns a Walker to the out halfedge of vertex given by VertexID
250
        Walker walker(VertexID id) const;
251
        /// Returns a Walker to the last halfedge of face given by FaceID
252
        Walker walker(FaceID id) const;
253
        /// Returns a Walker to the halfedge given by HalfEdgeID
254
        Walker walker(HalfEdgeID id) const;
255
 
256
 
257
    private:
258
 
259
        ConnectivityKernel kernel;
260
 
261
        VertexAttributeVector<Vec> positions;
262
 
263
        // private template for building the manifold from various types
264
        template<typename size_type, typename float_type, typename int_type>
265
        void build_template(size_type no_vertices,
266
                            const float_type* vertvec,
267
                            size_type no_faces,
268
                            const int_type* facevec,
269
                            const int_type* indices);
270
 
271
        /// Set the next and prev indices of the first and second argument respectively.
272
        void link(HalfEdgeID h0, HalfEdgeID h1);
273
 
274
        /// Glue halfedges by letting the opp indices point to each other.
275
        void glue(HalfEdgeID h0, HalfEdgeID h1);
276
 
277
        /// Auxiliary function called from collapse
278
        void remove_face_if_degenerate(HalfEdgeID h);
279
 
280
        /// Ensure boundary consistency.
281
        void ensure_boundary_consistency(VertexID v);
282
    };
283
 
284
    /** \brief Verify Manifold Integrity
285
    Performs a series of tests to chethis that this is a valid manifold.
286
    This function is not rigorously constructed but seems to catch all problems so far. 
287
    The function returns true if the mesh is valid and false otherwise. */
288
    bool valid(const Manifold& m);
289
 
290
    /// Calculate the bounding box of the manifold
291
    void bbox(const Manifold& m, Manifold::Vec& pmin, Manifold::Vec& pmax);
292
 
293
    /// Calculate the bounding sphere of the manifold
294
    void bsphere(const Manifold& m, Manifold::Vec& c, float& r);
295
 
296
    /** \brief Test for legal edge collapse.
297
    The argument h is the halfedge we want to collapse. 
298
    If this function does not return true, it is illegal to collapse h. 
299
    The reason is that the collapse would violate the manifold property of the mesh.
300
    The test is as follows:
301
    1.  For the two vertices adjacent to the edge, we generate a list of all their neighbouring vertices. 
302
    We then generate a  list of the vertices that occur in both these lists. 
303
    That is, we find all vertices connected by edges to both endpoints of the edge and store these in a list.
304
    2.  For both faces incident on the edge, chethis whether they are triangular. 
305
    If this is the case, the face will be removed, and it is ok that the the third vertex is connected to both endpoints. 
306
    Thus the third vertex in such a face is removed from the list generated in 1.
307
    3.  If the list is now empty, all is well. 
308
    Otherwise, there would be a vertex in the new mesh with two edges connecting it to the same vertex. Return false.
309
    4.  TETRAHEDRON TEST:
310
    If the valency of both vertices is three, and the incident faces are triangles, we also disallow the operation. 
311
    Reason: A vertex valency of two and two triangles incident on the adjacent vertices makes the construction collapse.
312
    5.  VALENCY 4 TEST:
313
    If a triangle is adjacent to the edge being collapsed, it disappears.
314
    This means the valency of the remaining edge vertex is decreased by one.
315
    A valency two vertex reduced to a valency one vertex is considered illegal.
316
    6.  PREVENT MERGING HOLES:
317
    Collapsing an edge with boundary endpoints and valid faces results in the creation where two holes meet.
318
    A non manifold situation. We could relax this...
319
	7. New test: if the same face is in the one-ring of both vertices but not adjacent to the common edge,
320
	then the result of a collapse would be a one ring where the same face occurs twice. This is disallowed as the resulting
321
	 face would be non-simple.	*/
322
    bool precond_collapse_edge(const Manifold& m, HalfEdgeID h);
323
 
324
    /** \brief Test fpr legal edge flip. 
325
    Returns false if flipping cannot be performed. This is due to one of following: 
326
    1.  one of the two adjacent faces is not a triangle. 
327
    2.  Either end point has valency three.
328
    3.  The vertices that will be connected already are. */
329
    bool precond_flip_edge(const Manifold& m, HalfEdgeID h);
330
 
331
    /// Returns true if the halfedge is a boundary halfedge.
332
    bool boundary(const Manifold& m, HalfEdgeID h);
333
 
334
    /// Return the geometric length of a halfedge.
335
    double length(const Manifold& m, HalfEdgeID h);
336
 
337
    /// Returns true if the vertex is a boundary vertex.
338
    bool boundary(const Manifold& m, VertexID v);
339
 
340
    /// Compute valency, i.e. number of incident edges.
341
    int valency(const Manifold& m, VertexID v);
342
 
343
    /// Compute the vertex normal. This function computes the angle weighted sum of incident face normals.
344
    Manifold::Vec normal(const Manifold& m, VertexID v);
345
 
346
    /// Returns true if the two argument vertices are in each other's one-rings.
347
    bool connected(const Manifold& m, VertexID v0, VertexID v1);
348
 
349
    /// Compute the number of edges of a face
350
    int no_edges(const Manifold& m, FaceID f);
351
 
352
    /** Compute the normal of a face. If the face is not a triangle,
353
    the normal is not defined, but computed using the first three
354
    vertices of the face. */
355
    Manifold::Vec normal(const Manifold& m, FaceID f);
356
 
357
    /// Compute the area of a face. 
358
    double area(const Manifold& m, FaceID f);
359
 
360
    /// Compute the perimeter of a face. 
361
    double perimeter(const Manifold& m, FaceID f);
362
 
363
    /// Compute the centre of a face
364
    Manifold::Vec centre(const Manifold& m, FaceID f);
365
 
366
    /*******************************************************************
367
    * Manifold code
368
    *******************************************************************/
369
 
370
    inline Manifold::Manifold(){}
371
 
372
    inline Manifold::Vec& Manifold::pos(VertexID id)
373
    { return positions[id]; }
374
    inline const Manifold::Vec& Manifold::pos(VertexID id) const
375
    { return positions[id]; }
376
 
377
    inline VertexAttributeVector<Manifold::Vec>& Manifold::positions_attribute_vector()
378
    {
379
        return positions;
380
    }
381
 
382
    inline const VertexAttributeVector<Manifold::Vec>& Manifold::positions_attribute_vector() const
383
    {
384
        return positions;    
385
    }
386
 
387
    inline void Manifold::clear()
388
    { 
389
        kernel.clear();
390
        positions.clear();
391
    }
392
 
393
    inline Walker Manifold::walker(VertexID id) const
394
    { return Walker(kernel, kernel.out(id)); }
395
    inline Walker Manifold::walker(FaceID id) const
396
    { return Walker(kernel, kernel.last(id)); }
397
    inline Walker Manifold::walker(HalfEdgeID id) const
398
    { return Walker(kernel, id); }
399
 
400
 
401
    inline void Manifold::cleanup(IDRemap& map)
402
    {   
403
        kernel.cleanup(map);
404
        positions.cleanup(map.vmap);
405
    }
406
 
407
    inline void Manifold::cleanup()
408
    {
409
        IDRemap map;
410
        Manifold::cleanup(map);
411
    }
412
 
413
    inline int circulate_vertex_ccw(const Manifold& m, VertexID v, std::function<void(Walker&)> f)
414
    {
415
        Walker w = m.walker(v);
416
        for(; !w.full_circle(); w = w.circulate_vertex_ccw()) f(w);
417
        return w.no_steps();
418
    }
419
    inline int circulate_vertex_ccw(const Manifold& m, VertexID v, std::function<void(VertexID)> f)
420
    {
421
        return circulate_vertex_ccw(m, v, (std::function<void(Walker&)>)[&](Walker& w){f(w.vertex());});
422
    }
423
    inline int circulate_vertex_ccw(const Manifold& m, VertexID v, std::function<void(FaceID)> f)
424
    {
425
        return circulate_vertex_ccw(m, v, (std::function<void(Walker&)>)[&](Walker& w){f(w.face());});
426
    }
427
    inline int circulate_vertex_ccw(const Manifold& m, VertexID v, std::function<void(HalfEdgeID)> f)
428
    {
429
        return circulate_vertex_ccw(m, v, (std::function<void(Walker&)>)[&](Walker& w){f(w.halfedge());});
430
    }
431
 
432
    inline int circulate_vertex_cw(const Manifold& m, VertexID v, std::function<void(Walker&)> f)
433
    {
434
        Walker w = m.walker(v);
435
        for(; !w.full_circle(); w = w.circulate_vertex_cw()) f(w);
436
        return w.no_steps();
437
    }
438
    inline int circulate_vertex_cw(const Manifold& m, VertexID v, std::function<void(VertexID)> f)
439
    {
440
        return circulate_vertex_cw(m, v, (std::function<void(Walker&)>)[&](Walker& w){f(w.vertex());});
441
    }
442
    inline int circulate_vertex_cw(const Manifold& m, VertexID v, std::function<void(FaceID)> f)
443
    {
444
        return circulate_vertex_cw(m, v, (std::function<void(Walker&)>)[&](Walker& w){f(w.face());});
445
    }
446
    inline int circulate_vertex_cw(const Manifold& m, VertexID v, std::function<void(HalfEdgeID)> f)
447
    {
448
        return circulate_vertex_cw(m, v, (std::function<void(Walker&)>)[&](Walker& w){f(w.halfedge());});
449
    }
450
 
451
    inline int circulate_face_ccw(const Manifold& m, FaceID f, std::function<void(Walker&)> g)
452
    {
453
        Walker w = m.walker(f);
454
        for(; !w.full_circle(); w = w.circulate_face_ccw()) g(w);
455
        return w.no_steps();
456
    }
457
    inline int circulate_face_ccw(const Manifold& m, FaceID f, std::function<void(VertexID)> g)
458
    {
459
        return circulate_face_ccw(m, f, (std::function<void(Walker&)>)[&](Walker& w){g(w.vertex());});
460
    }
461
    inline int circulate_face_ccw(const Manifold& m, FaceID f, std::function<void(FaceID)> g)
462
    {
463
        return circulate_face_ccw(m, f, (std::function<void(Walker&)>)[&](Walker& w){g(w.opp().face());});
464
    }
465
    inline int circulate_face_ccw(const Manifold& m, FaceID f, std::function<void(HalfEdgeID)> g)
466
    {
467
        return circulate_face_ccw(m, f, (std::function<void(Walker&)>)[&](Walker& w){g(w.halfedge());});
468
    }
469
 
470
    inline int circulate_face_cw(const Manifold& m, FaceID f, std::function<void(Walker&)> g)
471
    {
472
        Walker w = m.walker(f);
473
        for(; !w.full_circle(); w = w.circulate_face_cw()) g(w);
474
        return w.no_steps();
475
    }
476
    inline int circulate_face_cw(const Manifold& m, FaceID f, std::function<void(VertexID)> g)
477
    {
478
        return circulate_face_cw(m, f, (std::function<void(Walker&)>)[&](Walker& w){g(w.vertex());});
479
    }
480
    inline int circulate_face_cw(const Manifold& m, FaceID f, std::function<void(FaceID)> g)
481
    {
482
        return circulate_face_cw(m, f, (std::function<void(Walker&)>)[&](Walker& w){g(w.opp().face());});
483
    }
484
    inline int circulate_face_cw(const Manifold& m, FaceID f, std::function<void(HalfEdgeID)> g)
485
    {
486
        return circulate_face_cw(m, f, (std::function<void(Walker&)>)[&](Walker& w){g(w.halfedge());});
487
    }
488
 
489
 
490
}