Line -... |
Line 1... |
- |
|
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 |
|
1 |
#ifndef __HMESH_MANIFOLD_H
|
12 |
#ifndef __HMESH_MANIFOLD_H__
|
2 |
#define __HMESH_MANIFOLD_H
|
13 |
#define __HMESH_MANIFOLD_H__
|
- |
|
14 |
|
- |
|
15 |
#include <algorithm>
|
- |
|
16 |
#include <CGLA/Vec3d.h>
|
- |
|
17 |
|
- |
|
18 |
#include "ConnectivityKernel.h"
|
- |
|
19 |
#include "Iterators.h"
|
- |
|
20 |
#include "Walker.h"
|
- |
|
21 |
#include "AttributeVector.h"
|
3 |
|
22 |
|
4 |
#include <vector>
|
- |
|
5 |
#include <list>
|
- |
|
6 |
#include <map>
|
- |
|
7 |
|
- |
|
8 |
#include "Vertex.h"
|
- |
|
9 |
#include "HalfEdge.h"
|
- |
|
10 |
#include "Face.h"
|
- |
|
11 |
|
23 |
|
12 |
namespace HMesh
|
24 |
namespace Geometry
|
13 |
{
|
25 |
{
|
14 |
class VertexCirculator;
|
26 |
// forward declaration
|
- |
|
27 |
class TriMesh;
|
15 |
class FaceCirculator;
|
28 |
class IndexedFaceSet;
|
- |
|
29 |
}
|
16 |
|
30 |
|
17 |
/** \brief A Data structure representing an open or closed manifold.
|
31 |
namespace HMesh
|
18 |
Manifold keeps lists of the entities making up a halfedge mesh
|
32 |
{
|
19 |
and provides basic functions for creating new faces, halfedges
|
33 |
/** The Manifold class represents a halfedge based mesh. Since meshes based on the halfedge
|
20 |
and vertices. There are also primitive operations for editing
|
34 |
representation must be manifold (although exceptions could be made) the class is thus named.
|
21 |
such as edge collapse. */
|
35 |
Manifold contains many functions for mesh manipulation and associated the position attribute
|
22 |
class Manifold
|
36 |
with vertices.*/
|
23 |
{
|
37 |
|
24 |
std::list<Vertex> vertex_db;
|
38 |
class Manifold
|
25 |
std::list<Face> face_db;
|
39 |
{
|
26 |
std::list<HalfEdge> halfedge_db;
|
40 |
public:
|
27 |
|
41 |
|
28 |
bool erase_immediately;
|
42 |
/// Vector type used for positions of vertices.
|
29 |
std::vector<VertexIter> unused_vertices;
|
43 |
typedef CGLA::Vec3d Vec;
|
30 |
std::vector<FaceIter> unused_faces;
|
44 |
|
31 |
std::vector<HalfEdgeIter> unused_halfedges;
|
45 |
/// Default constructor
|
32 |
|
46 |
Manifold();
|
33 |
|
47 |
|
34 |
/** Remove a face if it contains only two edges.
|
48 |
/** \brief Build a manifold.
|
35 |
This is an auxiliary function called from collapse_halfedge. */
|
49 |
The arguments are the number of vertices, no_vertices, the vector of vertices, vertvec, the number of faces, no_faces.
|
36 |
void remove_face_if_degenerate(HalfEdgeIter);
|
50 |
facevecis an array where each entry indicates the number of vertices in that face.
|
37 |
|
51 |
The array indices contains all the corresponding vertex indices in one concatenated list. */
|
38 |
Manifold(const Manifold&) {}
|
52 |
void build( size_t no_vertices,
|
39 |
/**< Empty copy constructor.
|
53 |
const float* vertvec,
|
40 |
Copying a manifold will not work, since faces, vertices, and
|
54 |
size_t no_faces,
|
41 |
halfedges contain iterators pointing to other faces, vertices,
|
55 |
const int* facevec,
|
42 |
and halfedges. These pointers would need to be changed if the
|
56 |
const int* indices);
|
43 |
mesh were copied. In other words, we would need to walk the
|
57 |
|
44 |
entire mesh. This may be required but it should not be an
|
58 |
/** \brief Build a manifold.
|
45 |
operation that is easily invoked by calling the copy constructor.
|
59 |
This function is for vertices given in double precision.
|
46 |
Hence, this operator is made private. */
|
60 |
The arguments are the number of vertices, no_vertices, the vector of vertices, vertvec, the number of faces, no_faces.
|
47 |
|
61 |
facevecis an array where each entry indicates the number of vertices in that face.
|
48 |
const Manifold& operator=(const Manifold&) {return *this;}
|
62 |
The array indices contains all the corresponding vertex indices in one concatenated list. */
|
49 |
/**< Empty assignment operator.
|
63 |
void build( size_t no_vertices,
|
50 |
The assignment operator is private for the same reason that the
|
64 |
const double* vertvec,
|
51 |
copy constructor is private. */
|
65 |
size_t no_faces,
|
52 |
|
66 |
const int* facevec,
|
53 |
public:
|
67 |
const int* indices);
|
54 |
|
68 |
|
55 |
|
69 |
/// Build a manifold from a TriMesh
|
56 |
Manifold(): erase_immediately(true) {}
|
70 |
void build(const Geometry::TriMesh& mesh);
|
57 |
///< Construct an empty manifold.
|
71 |
|
58 |
|
72 |
/// Add a face to the Manifold
|
59 |
bool is_valid();
|
73 |
FaceID add_face(std::vector<Manifold::Vec> points);
|
60 |
/**< Performs a series of tests to check that this is a valid manifold.
|
74 |
|
61 |
This function is not rigorously constructed but seems to catch
|
75 |
// /** Removes a face from the Manifold. If it is an interior face it is simply replaces
|
62 |
all problems so far. The function returns true if the mesh is
|
76 |
// by an InvalidFaceID. If the face contains boundary edges, these go away. */
|
63 |
valid and false otherwise. */
|
77 |
// bool remove_face(FaceID fid);
|
64 |
|
78 |
//
|
65 |
void enumerate_vertices();
|
79 |
// /** Remove an edge from the Manifold.
|
66 |
/**< Give each vertex a unique id corresponding to its iterator
|
80 |
// This function will remove the faces on either side and the edge itself in the process. */
|
67 |
position. Value is stored in the touched attribute. */
|
81 |
// bool remove_edge(HalfEdgeID hid);
|
68 |
|
82 |
//
|
69 |
void enumerate_halfedges();
|
83 |
// /** Remove a vertex from the Manifold.
|
70 |
/**< Give each halfedge a unique id corresponding to its iterator
|
84 |
// This function merges all faces around the vertex into one and then removes
|
71 |
position. Value is stored in the touched attribute. */
|
85 |
// this resulting face. */
|
72 |
|
86 |
// bool remove_vertex(VertexID vid);
|
73 |
void enumerate_faces();
|
87 |
|
74 |
/**< Give each face a unique id corresponding to its iterator
|
88 |
/// number of vertices
|
75 |
position. Value is stored in the touched attribute. */
|
89 |
size_t no_vertices() const { return kernel.no_vertices();}
|
76 |
|
90 |
/// number of active faces
|
77 |
size_t no_faces() const {return face_db.size();}
|
91 |
size_t no_faces() const { return kernel.no_faces();}
|
78 |
///< Return the number of faces.
|
92 |
/// number of active halfedges
|
79 |
|
93 |
size_t no_halfedges() const { return kernel.no_halfedges();}
|
80 |
size_t no_halfedges() const {return halfedge_db.size();}
|
94 |
|
81 |
///< Return the number of halfedges.
|
95 |
/// number of total vertices in kernel
|
82 |
|
96 |
size_t allocated_vertices() const { return kernel.allocated_vertices();}
|
83 |
size_t no_vertices() const {return vertex_db.size();}
|
97 |
/// number of total faces in kernel
|
84 |
///< Return the number of vertices
|
98 |
size_t allocated_faces() const { return kernel.allocated_faces();}
|
85 |
|
99 |
/// number of total halfedges in kernel
|
86 |
VertexIter create_vertex(const CGLA::Vec3f& pos);
|
100 |
size_t allocated_halfedges() const { return kernel.allocated_halfedges();}
|
87 |
///< Create a new vertex.
|
101 |
|
88 |
|
102 |
/// check if ID of vertex is in use
|
89 |
FaceIter create_face();
|
103 |
bool in_use(VertexID id) const { return kernel.in_use(id);}
|
90 |
/**< Create a new face.
|
104 |
/// check if ID of face is in use
|
91 |
An iterator to the face is returned. When a face f is initially
|
105 |
bool in_use(FaceID id) const { return kernel.in_use(id);}
|
92 |
created, is_used(f) will return false. */
|
106 |
/// check if ID of halfedge is in use
|
93 |
|
107 |
bool in_use(HalfEdgeID id) const { return kernel.in_use(id);}
|
94 |
HalfEdgeIter create_halfedge();
|
108 |
|
95 |
/**< Create a new halfedge. An iterator to the halfedge is returned.
|
109 |
/// Iterator to first VertexID, optional argument defines if unused items should be skipped
|
96 |
When h is initially created, is_used(h) returns false. */
|
110 |
VertexIDIterator vertices_begin(bool skip = true) const { return kernel.vertices_begin();}
|
97 |
|
111 |
/// Iterator to first FaceID, optional argument defines if unused items should be skipped
|
98 |
void clear();
|
112 |
FaceIDIterator faces_begin(bool skip = true) const { return kernel.faces_begin();}
|
99 |
///< Clear the manifold, removing all data.
|
113 |
/// Iterator to first HalfEdgeID, optional argument defines if unused items should be skipped
|
100 |
|
114 |
HalfEdgeIDIterator halfedges_begin(bool skip = true) const { return kernel.halfedges_begin();}
|
101 |
void remove_unused();
|
115 |
|
102 |
/**< Remove unused vertices, edges and faces from the database.
|
116 |
/// Iterator to past the end VertexID
|
103 |
If delayed_erase mode is enabled, then until this function
|
117 |
VertexIDIterator vertices_end() const { return kernel.vertices_end();}
|
104 |
has been called, erased vertices, edges, and faces are just marked
|
118 |
/// Iterator topast the end FaceID
|
105 |
as unused but not removed from their respective lists. */
|
119 |
FaceIDIterator faces_end() const { return kernel.faces_end();}
|
106 |
|
120 |
/// Iterator to past the end HalfEdgeID
|
107 |
void delayed_erase();
|
121 |
HalfEdgeIDIterator halfedges_end() const {return kernel.halfedges_end(); }
|
108 |
/**< Delay the actual removal of vertices, faces, and edges that
|
122 |
|
109 |
are erased. In many cases, it is a problem if one cannot
|
123 |
|
110 |
test whether a vertex, halfedge, or face indicated by an
|
124 |
/** \brief Bridge f0 and f1 by connecting the vertex pairs given in pairs.
|
111 |
iterator is in use or has been removed from the mesh. One
|
125 |
This function creates a cylindrical connection between f0 and f1. f0 and f1 are removed and the vertices
|
112 |
solution to this problem is to delay the actual removal of
|
126 |
given in pairs are connected by edges. The result is a cylindrical connection that changes the genus of the object.
|
113 |
the vertex, edge or face. Instead when calling, say,
|
127 |
|
114 |
erase_face(f), all the iterators of f are assigned the
|
128 |
This function leaves all error chethising in the hands of the user (for now). The faces clearly should not have any
|
115 |
appropriate NULL value to indicate that they are not
|
129 |
vertices or edges in common as this will create a non-manifold situation. Also the faces should face towards or away
|
116 |
pointing at anything, and f is added to a vector of faces
|
130 |
from each other and be in a position where it is reasonable to make the bridge. The connections should also make sense
|
117 |
that need to be physically removed from the face_db.
|
131 |
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
|
118 |
|
132 |
connect all vertices.
|
119 |
Since f is not erased, all iterators pointing at f remain
|
133 |
|
120 |
valid! And, importantly, it is possible to test whether f is
|
134 |
The function returns a vector of HalfEdgeIDs. Those are, of course, the connecting halfedges - also the opposite edges.
|
121 |
in use by calling is_used(f).
|
135 |
*/
|
122 |
|
136 |
std::vector<HalfEdgeID> bridge_faces(FaceID f0, FaceID f1, const std::vector<std::pair<VertexID, VertexID> >& pairs);
|
123 |
When remove_unused is called, the physical removal takes
|
137 |
|
124 |
place. Calling immediate_erase switches Manifold back to the
|
138 |
|
125 |
state where entities are removed as soon as the appropriate
|
139 |
/** \brief Collapse the halfedge h.
|
126 |
erase function is called, and at the same time calls
|
140 |
The argument h is the halfedge being removed. The vertex v=h->opp->vert is the one being removed while h->vert survives.
|
127 |
remove_unused.
|
141 |
The final argument indicates whether the surviving vertex should have the average position of the former vertices.
|
128 |
*/
|
142 |
By default false meaning that the surviving vertex retains it position.
|
129 |
|
143 |
This function is not guaranteed to keep the mesh sane unless, precond_collapse_edge has returned true !! */
|
130 |
void immediate_erase();
|
144 |
void collapse_edge(HalfEdgeID h, bool avg_vertices = false);
|
131 |
/**< Immediately remove erased entities.
|
145 |
|
132 |
Calling immediate_erase switches Manifold back to the state
|
146 |
/** \brief Split a face.
|
133 |
where entities are removed as soon as the appropriate erase
|
147 |
The face, f, is split by creating an edge with endpoints v0 and v1 (the next two arguments).
|
134 |
function is called.
|
148 |
The vertices of the old face between v0 and v1 (in counter clothiswise order) continue to belong to f.
|
135 |
|
149 |
The vertices between v1 and v0 belong to the new face. A handle to the new face is returned. */
|
136 |
See delayed_erase for more details, and note that
|
150 |
FaceID split_face_by_edge(FaceID f, VertexID v0, VertexID v1);
|
137 |
immediate_erase is the default mode. */
|
151 |
|
138 |
|
152 |
/** \brief Split a polygon, f, by inserting a vertex at the barycenter.
|
139 |
bool is_used(VertexIter v) const;
|
153 |
This function is less likely to create flipped triangles than the split_face_triangulate function.
|
140 |
/**< Test whether the vertex indicated by the argument v is used.
|
154 |
On the other hand, it introduces more vertices and probably makes the triangles more acute.
|
141 |
This function returns true if the vertex appears to have a
|
155 |
A handle to the inserted vertex is returned. */
|
142 |
valid outgoing halfedge iterator. */
|
156 |
VertexID split_face_by_vertex(FaceID f);
|
143 |
|
157 |
// VertexID split_face_by_vertex(HalfEdgeID h);
|
144 |
bool is_used(FaceIter f) const;
|
158 |
|
145 |
/**< Test whether the face indicated by the argument f is used.
|
159 |
/** \brief Insert a new vertex on halfedge h.
|
146 |
This function returns true if the face appears to have a
|
160 |
The new halfedge is insterted as the previous edge to h.
|
147 |
valid halfedge iterator. */
|
161 |
A handle to the inserted vertex is returned. */
|
148 |
|
162 |
VertexID split_edge(HalfEdgeID h);
|
149 |
bool is_used(HalfEdgeIter h) const;
|
163 |
|
150 |
/**< Test whether the halfedge indicated by the argument h is used.
|
164 |
/** \brief Stitch two halfedges.
|
151 |
This function returns true if the halfedge appears to have a
|
165 |
Two boundary halfedges can be stitched together. This can be used to build a complex mesh
|
152 |
valid vertex iterator. */
|
166 |
from a bunch of simple faces. */
|
153 |
|
167 |
bool stitch_boundary_edges(HalfEdgeID h0, HalfEdgeID h1);
|
154 |
void erase_halfedge(HalfEdgeIter h);
|
168 |
|
155 |
/**< Erase halfedge h.
|
169 |
/** \brief Merges two faces into a single polygon.
|
156 |
In general, you should never call this function but use the
|
170 |
The first face is f. The second face is adjacent to f along the halfedge h.
|
157 |
collapse_halfedge function instead since blindly erasing geometry
|
171 |
This function returns true if the merging was possible and false otherwise.
|
158 |
is most likely to invalidate the Mesh. Quite possibly this function
|
172 |
Currently merge only fails if the mesh is already illegal. Thus it should, in fact, never fail. */
|
159 |
will be removed from the public interface.
|
173 |
bool merge_faces(FaceID f, HalfEdgeID h);
|
160 |
|
174 |
|
161 |
Note that if delayed_erase has been called, this function does
|
175 |
/** \brief Merge all faces in the one ring of a vertex into a single polygon.
|
162 |
not immediately remove anything from the mesh. Instead the halfedge
|
176 |
The vertex is given by v.
|
163 |
is reset to its initial state. Thus, iterators are not invalidated,
|
177 |
|
164 |
and it is possible to test whether h is used calling:
|
178 |
The return value is the FaceID of the resulting polygonal face.
|
165 |
is_used(h). when remove_unused is called, the actual removal
|
179 |
InvalidFaceID is returned if
|
166 |
takes place.
|
180 |
- the input vertex is not in use or
|
167 |
*/
|
181 |
- the input vertex has valence less than two which is a degenerate case.
|
168 |
|
182 |
- the input vertex is a boundary vertex of valence two - i.e. adjacent to just one face.
|
169 |
void erase_vertex(VertexIter v);
|
183 |
- the same halfedge appears in two faces of the one ring of the input vertex: I.e.
|
170 |
/**< Erase vertex v.
|
184 |
the input vertex is twice adjacent to the same face!
|
171 |
In general, you should never call this function but use the
|
185 |
|
172 |
collapse_halfedge function to collapse the vertex away.
|
186 |
Note that this function can create some unusual and arguably degenerate meshes. For instance,
|
173 |
Blindly erasing is extremely likely to invalidate the
|
187 |
two triangles which share all vertices is collapsed to a single pair of vertices connected by
|
174 |
Mesh. Quite possibly this function will be removed from the
|
188 |
a pair of halfedges bounding the same face. */
|
175 |
public interface.
|
189 |
FaceID merge_one_ring(VertexID v, float max_loop_length = FLT_MAX);
|
176 |
|
190 |
|
177 |
Note that if delayed_erase has been called, this function does
|
191 |
/** \brief Close hole given by the invalid face of halfedgehandle h.
|
178 |
not immediately remove anything from the mesh. Instead the halfedge
|
192 |
returns FaceID of the created face or the face that is already there if the
|
179 |
is reset to its initial state. Thus, iterators are not invalidated,
|
193 |
face was not InvalidFaceID. */
|
180 |
and it is possible to test whether v is used calling:
|
194 |
FaceID close_hole(HalfEdgeID h);
|
181 |
is_used(v). when remove_unused is called, the actual removal
|
195 |
|
182 |
takes place.
|
196 |
/// \brief Flip an edge h.
|
183 |
*/
|
197 |
void flip_edge(HalfEdgeID h);
|
184 |
|
198 |
|
185 |
|
199 |
/// Return reference to position given by VertexID
|
186 |
void erase_face(FaceIter f);
|
200 |
Vec& pos(VertexID id);
|
187 |
/**< Erase face f.
|
201 |
/// Return const reference to position given by VertexID
|
188 |
In general, you should never call this function but use
|
202 |
const Vec& pos(VertexID id) const;
|
189 |
collapse_halfedge in conjunction with other functions to
|
203 |
|
190 |
remove the face through (Euler) operations which preserve
|
204 |
/// Clear the mesh. Remove all faces, halfedges, and vertices.
|
191 |
the mesh in a valid state.
|
205 |
void clear();
|
192 |
Blindly erasing is extremely likely to invalidate the
|
206 |
|
193 |
Mesh. Quite possibly this function will be removed from the
|
207 |
/// Remove unused items from Mesh, map argument is to be used for attribute vector cleanups in order to maintain sync.
|
194 |
public interface.
|
208 |
void cleanup(IDRemap& map);
|
195 |
|
209 |
/// Remove unused items from Mesh
|
196 |
Note that if delayed_erase has been called, this function does
|
210 |
void cleanup();
|
197 |
not immediately remove anything from the mesh. Instead the face
|
211 |
|
198 |
is reset to its initial state. Thus, iterators are not invalidated,
|
212 |
/// Returns a Walker to the out halfedge of vertex given by VertexID
|
199 |
and it is possible to test whether f is used calling:
|
213 |
Walker walker(VertexID id) const;
|
200 |
is_used(f). when remove_unused is called, the actual removal
|
214 |
/// Returns a Walker to the last halfedge of face given by FaceID
|
201 |
takes place.
|
215 |
Walker walker(FaceID id) const;
|
202 |
*/
|
216 |
/// Returns a Walker to the halfedge given by HalfEdgeID
|
203 |
|
217 |
Walker walker(HalfEdgeID id) const;
|
204 |
HalfEdgeIter halfedges_begin();
|
218 |
|
205 |
///< Return iterator pointing to the first halfedge.
|
219 |
|
206 |
|
220 |
private:
|
207 |
HalfEdgeIter halfedges_end();
|
221 |
|
208 |
///< Return iterator pointing to beyond the last halfedge.
|
222 |
ConnectivityKernel kernel;
|
209 |
|
223 |
|
210 |
VertexIter vertices_begin();
|
224 |
VertexAttributeVector<Vec> positions;
|
211 |
///< Return iterator pointing to the first vertex.
|
225 |
|
212 |
|
226 |
// private template for building the manifold from various types
|
213 |
VertexIter vertices_end();
|
227 |
template<typename size_type, typename float_type, typename int_type>
|
214 |
///< Return iterator pointing to beyond the last vertex.
|
228 |
void build_template(size_type no_vertices,
|
215 |
|
229 |
const float_type* vertvec,
|
216 |
FaceIter faces_begin();
|
230 |
size_type no_faces,
|
217 |
///< Return iterator pointing to the first face.
|
231 |
const int_type* facevec,
|
218 |
|
232 |
const int_type* indices);
|
219 |
FaceIter faces_end();
|
233 |
|
220 |
///< Return iterator pointing to beyond the last face.
|
234 |
/// Set the next and prev indices of the first and second argument respectively.
|
221 |
|
235 |
void link(HalfEdgeID h0, HalfEdgeID h1);
|
222 |
bool collapse_precond(HalfEdgeIter h);
|
236 |
|
223 |
/**< \brief HalfEdge collapse precondition.
|
237 |
/// Glue halfedges by letting the opp indices point to each other.
|
224 |
|
238 |
void glue(HalfEdgeID h0, HalfEdgeID h1);
|
225 |
The argument h is the halfedge we want to collapse.
|
239 |
|
226 |
|
240 |
/// Auxiliary function called from collapse
|
227 |
If this function does not return true, it is illegal to collapse
|
241 |
void remove_face_if_degenerate(HalfEdgeID h);
|
228 |
h. The reason is that the collapse would violate the manifold property
|
242 |
|
229 |
of the mesh.
|
243 |
/// Ensure boundary consistency.
|
230 |
|
244 |
void ensure_boundary_consistency(VertexID v);
|
231 |
The test is as follows.
|
245 |
};
|
232 |
|
246 |
|
233 |
1. For the two vertices adjacent to the edge, we generate
|
247 |
/** \brief Verify Manifold Integrity
|
234 |
a list of all their neighbouring vertices. We then generate a
|
248 |
Performs a series of tests to chethis that this is a valid manifold.
|
235 |
list of the vertices that occur in both these lists. That is,
|
249 |
This function is not rigorously constructed but seems to catch all problems so far.
|
236 |
we find all vertices connected by edges to both endpoints
|
250 |
The function returns true if the mesh is valid and false otherwise. */
|
237 |
of the edge and store these in a list.
|
251 |
bool valid(const Manifold& m);
|
238 |
|
252 |
|
239 |
2. For both faces incident on the edge, check whether they
|
253 |
/// Calculate the bounding box of the manifold
|
240 |
are triangular. If this is the case, the face will be removed,
|
254 |
void bbox(const Manifold& m, Manifold::Vec& pmin, Manifold::Vec& pmax);
|
241 |
and it is ok that the the third vertex is connected to both
|
255 |
|
242 |
endpoints. Thus the third vertex in such a face is removed
|
256 |
/// Calculate the bounding sphere of the manifold
|
243 |
from the list generated in 1.
|
257 |
void bsphere(const Manifold& m, Manifold::Vec& c, float& r);
|
244 |
|
258 |
|
245 |
3. If the list is now empty, all is well. Otherwise, there
|
259 |
/** \brief Test for legal edge collapse.
|
246 |
would be a vertex in the new mesh with two edges connecting
|
260 |
The argument h is the halfedge we want to collapse.
|
247 |
it to the same vertex. Return false.
|
261 |
If this function does not return true, it is illegal to collapse h.
|
248 |
|
262 |
The reason is that the collapse would violate the manifold property of the mesh.
|
249 |
4. TETRAHEDRON TEST:
|
263 |
The test is as follows:
|
250 |
If the valency of both vertices is
|
264 |
1. For the two vertices adjacent to the edge, we generate a list of all their neighbouring vertices.
|
251 |
three, and the incident faces are triangles, we also disallow
|
265 |
We then generate a list of the vertices that occur in both these lists.
|
252 |
the operation. Reason: It introduces a vertex of valency two
|
266 |
That is, we find all vertices connected by edges to both endpoints of the edge and store these in a list.
|
253 |
and if the final two polygons incident on the vertices
|
267 |
2. For both faces incident on the edge, chethis whether they are triangular.
|
254 |
that are adjacent to the edge being collapsed are triangles, then
|
268 |
If this is the case, the face will be removed, and it is ok that the the third vertex is connected to both endpoints.
|
255 |
the construction will collapse
|
269 |
Thus the third vertex in such a face is removed from the list generated in 1.
|
256 |
|
270 |
3. If the list is now empty, all is well.
|
257 |
5. VALENCY 4 TEST:
|
271 |
Otherwise, there would be a vertex in the new mesh with two edges connecting it to the same vertex. Return false.
|
258 |
If a face adjacent to the edge being collapsed is a triangle,
|
272 |
4. TETRAHEDRON TEST:
|
259 |
it will disappear, and the valency of the final vertex beloning to
|
273 |
If the valency of both vertices is three, and the incident faces are triangles, we also disallow the operation.
|
260 |
this edge will be reduced by one. Hence this valency should be at
|
274 |
Reason: A vertex valency of two and two triangles incident on the adjacent vertices makes the construction collapse.
|
261 |
least 4. A valency three vertex will be reduced to a valency two
|
275 |
5. VALENCY 4 TEST:
|
262 |
vertex which is considered illegal.
|
276 |
If a triangle is adjacent to the edge being collapsed, it disappears.
|
263 |
|
277 |
This means the valency of the remaining edge vertex is decreased by one.
|
264 |
6. PREVENT MERGING HOLES:
|
278 |
A valency two vertex reduced to a valency one vertex is considered illegal.
|
265 |
We do not want to collapse an edge if its end points are boundary
|
279 |
6. PREVENT MERGING HOLES:
|
266 |
vertices, but its two adjacent faces are not NULL faces, because
|
280 |
Collapsing an edge with boundary endpoints and valid faces results in the creation where two holes meet.
|
267 |
in that case we create a vertex where two holes meet. A non manifold
|
281 |
A non manifold situation. We could relax this...
|
268 |
situation. */
|
282 |
7. New test: if the same face is in the one-ring of both vertices but not adjacent to the common edge,
|
269 |
|
283 |
then the result of a collapse would be a one ring where the same face occurs twice. This is disallowed as the resulting
|
270 |
|
284 |
face would be non-simple. */
|
271 |
void collapse_halfedge(HalfEdgeIter h, bool=false);
|
285 |
bool precond_collapse_edge(const Manifold& m, HalfEdgeID h);
|
272 |
/**< Collapse the halfedge h.
|
286 |
|
273 |
|
287 |
/** \brief Test fpr legal edge flip.
|
274 |
The argument h is the halfedge being removed. The vertex
|
288 |
Returns false if flipping cannot be performed. This is due to one of following:
|
275 |
v=h->opp->vert is the one being removed while h->vert survives.
|
289 |
1. one of the two adjacent faces is not a triangle.
|
276 |
|
290 |
2. Either end point has valency three.
|
277 |
The final argument is a boolean indicating whether the vertex
|
291 |
3. The vertices that will be connected already are. */
|
278 |
that survives the collapse should have a position which is the
|
292 |
bool precond_flip_edge(const Manifold& m, HalfEdgeID h);
|
279 |
average of its own position and the vertex that is removed.
|
293 |
|
280 |
By default false meaning that the surviving vertex retains it
|
294 |
/// Returns true if the halfedge is a boundary halfedge.
|
281 |
position.
|
295 |
bool boundary(const Manifold& m, HalfEdgeID h);
|
282 |
|
296 |
|
283 |
This function is not guaranteed to keep the mesh sane unless,
|
297 |
/// Return the geometric length of a halfedge.
|
284 |
collapse_precond has returned true !!
|
298 |
float length(const Manifold& m, HalfEdgeID h);
|
285 |
*/
|
299 |
|
286 |
|
300 |
/// Returns true if the vertex is a boundary vertex.
|
287 |
FaceIter split_face(FaceIter f, VertexIter v0, VertexIter v1);
|
301 |
bool boundary(const Manifold& m, VertexID v);
|
288 |
/**< Split a face.
|
302 |
|
289 |
The face, f, is split by connecting two
|
303 |
/// Compute valency, i.e. number of incident edges.
|
290 |
vertices v0 and v1 (the next two arguments). The vertices of
|
304 |
int valency(const Manifold& m, VertexID v);
|
291 |
the old face between v0 and v1 (in counter clockwise order)
|
305 |
|
292 |
continue to belong to f. The vertices between v1 and
|
306 |
/// Compute the vertex normal. This function computes the angle weighted sum of incident face normals.
|
293 |
v0 belong to the new face. An iterator to the new face is
|
307 |
Manifold::Vec normal(const Manifold& m, VertexID v);
|
294 |
returned. */
|
308 |
|
295 |
|
309 |
/// Returns true if the two argument vertices are in each other's one-rings.
|
296 |
VertexIter split_edge(HalfEdgeIter h);
|
310 |
bool connected(const Manifold& m, VertexID v0, VertexID v1);
|
297 |
/**< Insert a new vertex on halfedge h.
|
311 |
|
298 |
The new halfedge is insterted as the previous edge to h.
|
312 |
/// Compute the number of edges of a face
|
299 |
An iterator to the inserted vertex is returned. */
|
313 |
int no_edges(const Manifold& m, FaceID f);
|
300 |
|
314 |
|
301 |
void triangulate(FaceIter f);
|
315 |
/** Compute the normal of a face. If the face is not a triangle,
|
302 |
/**< Triangulate a polygonal face by repeatedly calling split_face.
|
316 |
the normal is not defined, but computed using the first three
|
303 |
Triangulate iteratively splits triangles off a polygon. The first
|
317 |
vertices of the face. */
|
304 |
triangle split off is the one connecting f->last->vert and
|
318 |
Manifold::Vec normal(const Manifold& m, FaceID f);
|
305 |
f->last->next->next->vert.
|
319 |
|
306 |
*/
|
320 |
/// Compute the area of a face.
|
307 |
|
321 |
float area(const Manifold& m, FaceID f);
|
308 |
VertexIter safe_triangulate(FaceIter f);
|
322 |
|
309 |
/**< Triangulate a polygon, f, by inserting a vertex at the barycenter.
|
323 |
/// Compute the perimeter of a face.
|
310 |
All vertices in f are connected to the new vertex.
|
324 |
float perimeter(const Manifold& m, FaceID f);
|
311 |
The word "safe" means that it is less likely to create flipped
|
325 |
|
312 |
triangles than the normal triangulate. On the other hand, it
|
326 |
/// Compute the centre of a face
|
313 |
introduces more vertices and probably makes the triangles more
|
327 |
Manifold::Vec centre(const Manifold& m, FaceID f);
|
314 |
acute. This function simply calls face_insert_point.
|
328 |
|
315 |
|
329 |
/*******************************************************************
|
316 |
The inserted vertex is returned.
|
330 |
* Manifold code
|
317 |
*/
|
331 |
*******************************************************************/
|
318 |
|
332 |
|
319 |
void face_insert_point(FaceIter f, VertexIter v);
|
333 |
inline Manifold::Manifold(){}
|
320 |
/**< Insert a new vertex, v, in a face, f.
|
334 |
|
321 |
This operation splits an N-gon into N triangles.
|
335 |
inline Manifold::Vec& Manifold::pos(VertexID id)
|
322 |
In the current implementation the original face is erased.
|
336 |
{ return positions[id]; }
|
323 |
This means that the iterator is not valid after the function
|
337 |
inline const Manifold::Vec& Manifold::pos(VertexID id) const
|
324 |
returns.
|
338 |
{ return positions[id]; }
|
325 |
*/
|
339 |
|
326 |
|
340 |
|
327 |
bool merge_faces(FaceIter f, HalfEdgeIter h);
|
341 |
inline void Manifold::clear()
|
328 |
/**< Merges two faces into a single polygon. The first face is f. The
|
342 |
{
|
329 |
second face is adjacent to f along the halfedge h. This function
|
343 |
kernel.clear();
|
330 |
returns true if the merging was possible and false
|
344 |
positions.clear();
|
331 |
otherwise. Currently merge only fails if the mesh is already
|
345 |
}
|
332 |
illegal. Thus it should, in fact, never fail. */
|
346 |
|
333 |
|
347 |
inline Walker Manifold::walker(VertexID id) const
|
334 |
bool flip(HalfEdgeIter h);
|
348 |
{ return Walker(kernel, kernel.out(id)); }
|
335 |
/**< Flip an edge h. Returns false if flipping cannot be performed.
|
349 |
inline Walker Manifold::walker(FaceID id) const
|
336 |
This is either because one of the two adjacent faces is not
|
350 |
{ return Walker(kernel, kernel.last(id)); }
|
337 |
a triangle, or because either end point has valency three or
|
351 |
inline Walker Manifold::walker(HalfEdgeID id) const
|
338 |
because the vertices that will be connected already are. */
|
352 |
{ return Walker(kernel, id); }
|
339 |
|
353 |
|
340 |
void get_bbox(CGLA::Vec3f& pmin, CGLA::Vec3f& pmax);
|
354 |
|
341 |
/**< Return the bounding box of the manifold. The arguments pmin and pmax
|
355 |
inline void Manifold::cleanup(IDRemap& map)
|
342 |
will contain the extreme corners of the box when the function
|
356 |
{
|
343 |
returns. */
|
357 |
kernel.cleanup(map);
|
344 |
|
358 |
positions.cleanup(map.vmap);
|
345 |
void get_bsphere(CGLA::Vec3f& c, float& r);
|
359 |
}
|
346 |
/**< Get a bounding sphere. When the function returns, c contains the
|
360 |
|
347 |
centre and r the radius. */
|
361 |
inline void Manifold::cleanup()
|
348 |
};
|
362 |
{
|
349 |
|
363 |
IDRemap map;
|
350 |
|
364 |
Manifold::cleanup(map);
|
351 |
inline HalfEdgeIter Manifold::halfedges_begin()
|
365 |
}
|
352 |
{
|
366 |
}
|
353 |
return halfedge_db.begin();
|
- |
|
354 |
}
|
- |
|
355 |
|
- |
|
356 |
inline HalfEdgeIter Manifold::halfedges_end()
|
- |
|
357 |
{
|
- |
|
358 |
return halfedge_db.end();
|
- |
|
359 |
}
|
- |
|
360 |
|
- |
|
361 |
inline VertexIter Manifold::vertices_begin()
|
- |
|
362 |
{
|
- |
|
363 |
return vertex_db.begin();
|
- |
|
364 |
}
|
- |
|
365 |
|
- |
|
366 |
inline VertexIter Manifold::vertices_end()
|
- |
|
367 |
{
|
- |
|
368 |
return vertex_db.end();
|
- |
|
369 |
}
|
- |
|
370 |
|
- |
|
371 |
inline FaceIter Manifold::faces_begin()
|
- |
|
372 |
{
|
- |
|
373 |
return face_db.begin();
|
- |
|
374 |
}
|
- |
|
375 |
|
- |
|
376 |
inline FaceIter Manifold::faces_end()
|
- |
|
377 |
{
|
- |
|
378 |
return face_db.end();
|
- |
|
379 |
}
|
- |
|
380 |
|
- |
|
381 |
inline VertexIter Manifold::create_vertex(const CGLA::Vec3f& pos)
|
- |
|
382 |
{
|
- |
|
383 |
vertex_db.push_back(Vertex(pos));
|
- |
|
384 |
return --vertex_db.end();
|
- |
|
385 |
}
|
- |
|
386 |
|
- |
|
387 |
inline FaceIter Manifold::create_face()
|
- |
|
388 |
{
|
- |
|
389 |
face_db.push_back(Face());
|
- |
|
390 |
return --face_db.end();
|
- |
|
391 |
}
|
- |
|
392 |
|
- |
|
393 |
inline HalfEdgeIter Manifold::create_halfedge()
|
- |
|
394 |
{
|
- |
|
395 |
halfedge_db.push_back(HalfEdge());
|
- |
|
396 |
return --halfedge_db.end();
|
- |
|
397 |
}
|
- |
|
398 |
|
- |
|
399 |
inline void Manifold::delayed_erase()
|
- |
|
400 |
{
|
- |
|
401 |
erase_immediately = false;
|
- |
|
402 |
}
|
- |
|
403 |
|
- |
|
404 |
inline void Manifold::immediate_erase()
|
- |
|
405 |
{
|
- |
|
406 |
erase_immediately = true;
|
- |
|
407 |
remove_unused();
|
- |
|
408 |
}
|
- |
|
409 |
|
- |
|
410 |
inline bool Manifold::is_used(VertexIter v) const
|
- |
|
411 |
{
|
- |
|
412 |
if(v->he == NULL_HALFEDGE_ITER)
|
- |
|
413 |
return false;
|
- |
|
414 |
return true;
|
- |
|
415 |
}
|
- |
|
416 |
|
- |
|
417 |
inline bool Manifold::is_used(FaceIter f) const
|
- |
|
418 |
{
|
- |
|
419 |
if(f->last == NULL_HALFEDGE_ITER)
|
- |
|
420 |
return false;
|
- |
|
421 |
return true;
|
- |
|
422 |
}
|
- |
|
423 |
|
- |
|
424 |
inline bool Manifold::is_used(HalfEdgeIter h) const
|
- |
|
425 |
{
|
- |
|
426 |
if(h->vert == NULL_VERTEX_ITER)
|
- |
|
427 |
return false;
|
- |
|
428 |
return true;
|
- |
|
429 |
}
|
- |
|
430 |
|
367 |
|
431 |
|
368 |
|
432 |
}
|
- |
|
433 |
#endif
|
369 |
#endif
|
434 |
|
370 |
|