Subversion Repositories gelsvn

Rev

Rev 136 | Rev 336 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 136 Rev 178
Line 17... Line 17...
17
	/** \brief A Data structure representing an open or closed manifold.
17
	/** \brief A Data structure representing an open or closed manifold.
18
			Manifold keeps lists of the entities making up a halfedge mesh
18
			Manifold keeps lists of the entities making up a halfedge mesh
19
			and provides basic functions for creating new faces, halfedges
19
			and provides basic functions for creating new faces, halfedges
20
			and vertices. There are also primitive operations for editing 
20
			and vertices. There are also primitive operations for editing 
21
			such as edge collapse. */
21
			such as edge collapse. */
22
	struct Manifold
22
	class Manifold
23
	{
23
		{
24
		std::list<Vertex> vertex_db;
24
			std::list<Vertex> vertex_db;
25
		std::list<Face> face_db;
25
			std::list<Face> face_db;
26
		std::list<HalfEdge> halfedge_db;
26
			std::list<HalfEdge> halfedge_db;
27
 
27
 
-
 
28
			bool erase_immediately;
-
 
29
			std::vector<VertexIter> unused_vertices;
-
 
30
			std::vector<FaceIter> unused_faces;
-
 
31
			std::vector<HalfEdgeIter> unused_halfedges;
-
 
32
 
-
 
33
 
28
		/** Remove a face if it contains only two edges.
34
			/** Remove a face if it contains only two edges.
29
				This is an auxiliary function called from collapse_halfedge. */
35
					This is an auxiliary function called from collapse_halfedge. */
30
		void remove_face_if_degenerate(HalfEdgeIter);
36
			void remove_face_if_degenerate(HalfEdgeIter);
31
 
37
 
-
 
38
			Manifold(const Manifold&) {}
32
		/** Empty copy constructor.
39
			/**< Empty copy constructor.
33
				Copying a manifold will not work, since faces, vertices, and
40
				 Copying a manifold will not work, since faces, vertices, and
34
				halfedges contain iterators pointing to other faces, vertices,
41
				 halfedges contain iterators pointing to other faces, vertices,
35
				and halfedges. These pointers would need to be changed if the 
42
				 and halfedges. These pointers would need to be changed if the 
36
				mesh were copied. In other words, we would need to walk the
43
				 mesh were copied. In other words, we would need to walk the
37
				entire mesh. This may be required but it should not be an 
44
				 entire mesh. This may be required but it should not be an 
38
				operation that is easily invoked by calling the copy constructor.
45
				 operation that is easily invoked by calling the copy constructor.
39
				Hence, this operator is made private.		*/
46
				 Hence, this operator is made private.		*/
40
		Manifold(const Manifold&) {}
-
 
41
 
47
 
-
 
48
			const Manifold& operator=(const Manifold&) {return *this;}
42
		/** Empty assignment operator.
49
			/**< Empty assignment operator.
43
				The assignment operator is private for the same reason that the
50
				 The assignment operator is private for the same reason that the
44
				copy constructor is private. */
51
				 copy constructor is private. */
45
		const Manifold& operator=(const Manifold&) {return *this;}
-
 
46
 
52
 
47
		public:
53
		public:
48
	
54
 
49
		/// Construct an empty manifold.
-
 
50
		Manifold() {}
-
 
51
 
55
 
52
  	/** Return the bounding box of the manifold. The arguments pmin and pmax
-
 
53
				will contain the extreme corners of the box when the function returns.
56
			Manifold(): erase_immediately(true) {}
54
		 */
-
 
55
		void get_bbox(CGLA::Vec3f& pmin, CGLA::Vec3f& pmax);
57
			///< Construct an empty manifold.
56
 
58
 
-
 
59
			bool is_valid();
57
		/** Get a bounding sphere. When the function returns c contains the 
60
			/**< Performs a series of tests to check that this is a valid manifold.
58
				centre and r the radius. */ 
61
				 This function is not rigorously constructed but seems to catch
59
    void get_bsphere(CGLA::Vec3f& c, float& r);
62
				 all problems so far. The function returns true if the mesh is 
-
 
63
				 valid and false otherwise.	*/
60
 
64
 
-
 
65
			void enumerate_vertices();
61
		/// Clear the manifold - removing all data.
66
			/**< Give each vertex a unique id corresponding to its iterator
62
		void clear()
67
				 position */
63
		{
68
 
64
			vertex_db.clear();
69
			void enumerate_halfedges();
-
 
70
			/**< Give each halfedge a unique id corresponding to its iterator
65
			face_db.clear();
71
				 position */
-
 
72
 
66
			halfedge_db.clear();
73
			void enumerate_faces();
-
 
74
			/**< Give each face a unique id corresponding to its iterator
67
		}
75
				 position */
68
 
76
 
69
		/// Return the number of faces.
-
 
70
		size_t no_faces() const {return face_db.size();}
77
			size_t no_faces() const {return face_db.size();}
-
 
78
			///< Return the number of faces.
71
 
79
 
72
		/// Return the number of halfedges.
-
 
73
		size_t no_halfedges() const {return halfedge_db.size();}
80
			size_t no_halfedges() const {return halfedge_db.size();}
-
 
81
			///< Return the number of halfedges.
74
 
82
 
75
		/// Return the number of vertices
-
 
76
		size_t no_vertices() const {return vertex_db.size();}
83
			size_t no_vertices() const {return vertex_db.size();}
-
 
84
			///< Return the number of vertices
77
 
85
 
78
		/** Create a new vertex. 
-
 
79
				The argument is the position of the vertex, and the 
-
 
80
				function returns an iterator pointing to the vertex. */
-
 
81
		VertexIter create_vertex(const CGLA::Vec3f& pos)
86
			VertexIter create_vertex(const CGLA::Vec3f& pos);
82
		{
-
 
83
			vertex_db.push_back(Vertex(pos));
-
 
84
			return --vertex_db.end();
87
			///< Create a new vertex.
85
		}
-
 
86
 
88
 
-
 
89
			FaceIter create_face();
87
		/** Create a new face. 
90
			/**< Create a new face.
88
				An iterator to the face is returned. */
91
				 An iterator to the face is returned. When a face f is initially
-
 
92
				 created, is_used(f) will return false. */
-
 
93
 
89
		FaceIter create_face()
94
			HalfEdgeIter create_halfedge();
-
 
95
			/**< Create a new halfedge. An iterator to the halfedge is returned.
-
 
96
				 When h is initially created, is_used(h) returns false. */
-
 
97
 
-
 
98
			void clear();
-
 
99
			///< Clear the manifold, removing all data.
90
		{
100
 
91
			face_db.push_back(Face());
101
			void remove_unused();
-
 
102
			/**< Remove unused vertices, edges and faces from the database.
-
 
103
				 If delayed_erase mode is enabled, then until this function 
-
 
104
				 has been called, erased vertices, edges, and faces are just marked
-
 
105
				 as unused but not removed from their respective lists. */
-
 
106
 
92
			return --face_db.end();
107
			void delayed_erase();
-
 
108
			/**< Delay the actual removal of vertices, faces, and edges that
-
 
109
				 are erased.  In many cases, it is a problem if one cannot
-
 
110
				 test whether a vertex, halfedge, or face indicated by an
-
 
111
				 iterator is in use or has been removed from the mesh. One
-
 
112
				 solution to this problem is to delay the actual removal of
-
 
113
				 the vertex, edge or face. Instead when calling, say,
-
 
114
				 erase_face(f), all the iterators of f are assigned the
-
 
115
				 appropriate NULL value to indicate that they are not
-
 
116
				 pointing at anything, and f is added to a vector of faces
-
 
117
				 that need to be physically removed from the face_db.
-
 
118
 
-
 
119
				 Since f is not erased, all iterators pointing at f remain
-
 
120
				 valid! And, importantly, it is possible to test whether f is
-
 
121
				 in use by calling is_used(f).
-
 
122
 
-
 
123
				 When remove_unused is called, the physical removal takes
-
 
124
				 place. Calling immediate_erase switches Manifold back to the
-
 
125
				 state where entities are removed as soon as the appropriate
-
 
126
				 erase function is called, and at the same time calls
-
 
127
				 remove_unused.
93
		}
128
			*/
94
 
129
 
-
 
130
			void immediate_erase();
-
 
131
			/**< Immediately remove erased entities.
-
 
132
				 Calling immediate_erase switches Manifold back to the state
-
 
133
				 where entities are removed as soon as the appropriate erase
-
 
134
				 function is called.
-
 
135
 
-
 
136
				 See delayed_erase for more details, and note that
-
 
137
				 immediate_erase is the default mode.  */
-
 
138
 
-
 
139
			bool is_used(VertexIter v) const;
-
 
140
			/**< Test whether the vertex indicated by the argument v is used.
-
 
141
				 This function returns true if the vertex appears to have a 
-
 
142
				 valid outgoing halfedge iterator. */
-
 
143
 
-
 
144
			bool is_used(FaceIter f) const;
-
 
145
			/**< Test whether the face indicated by the argument f is used.
-
 
146
				 This function returns true if the face appears to have a 
-
 
147
				 valid halfedge iterator. */
-
 
148
 
-
 
149
			bool is_used(HalfEdgeIter h) const;
95
  	/** Create a new halfedge. An iterator to the halfedge is returned. */
150
			/**< Test whether the halfedge indicated by the argument h is used.
-
 
151
				 This function returns true if the halfedge appears to have a 
96
		HalfEdgeIter create_halfedge()
152
				 valid vertex iterator. */
97
		{
153
 
98
			halfedge_db.push_back(HalfEdge());
154
			void erase_halfedge(HalfEdgeIter h);			
99
			return --halfedge_db.end();
155
			/**< Erase halfedge h. 
-
 
156
				 In general, you should never call this function but use the 
-
 
157
				 collapse_halfedge function instead since blindly erasing geometry
-
 
158
				 is most likely to invalidate the Mesh. Quite possibly this function
-
 
159
				 will be removed from the public interface. 
-
 
160
					
-
 
161
				 Note that if delayed_erase has been called, this function does
-
 
162
				 not immediately remove anything from the mesh. Instead the halfedge
-
 
163
				 is reset to its initial state. Thus, iterators are not invalidated,
-
 
164
				 and it is possible to test whether h is used calling:
-
 
165
				 is_used(h). when remove_unused is called, the actual removal
-
 
166
				 takes place.
100
		}
167
			*/
101
 
168
 
-
 
169
			void erase_vertex(VertexIter v);
-
 
170
			/**< Erase vertex v.
102
		/// Erase halfedge h. Assumes it is safe to do so. Use with care.
171
				 In general, you should never call this function but use the 
103
		void erase_halfedge(HalfEdgeIter h)
172
				 collapse_halfedge function to collapse the vertex away.
-
 
173
				 Blindly erasing is extremely likely to invalidate the
-
 
174
				 Mesh. Quite possibly this function will be removed from the
-
 
175
				 public interface. 
104
		{
176
 
-
 
177
				 Note that if delayed_erase has been called, this function does
-
 
178
				 not immediately remove anything from the mesh. Instead the halfedge
-
 
179
				 is reset to its initial state. Thus, iterators are not invalidated,
-
 
180
				 and it is possible to test whether v is used calling:
-
 
181
				 is_used(v). when remove_unused is called, the actual removal
105
			halfedge_db.erase(h);
182
				 takes place.
106
		}
183
			*/
107
 
184
 
108
		/// Erase vertex v. Assumes it is safe to do so. Use with care.
-
 
109
		void erase_vertex(VertexIter v)
-
 
110
		{
-
 
111
			vertex_db.erase(v);
-
 
112
		}
-
 
113
	
185
 
-
 
186
			void erase_face(FaceIter f);
-
 
187
			/**< Erase face f.
114
		/// Erase face f. Assumes it is safe to do so. Use with care.
188
				 In general, you should never call this function but use 
-
 
189
				 collapse_halfedge in conjunction with other functions to
-
 
190
				 remove the face through (Euler) operations which preserve
-
 
191
				 the mesh in a valid state.
-
 
192
				 Blindly erasing is extremely likely to invalidate the
-
 
193
				 Mesh. Quite possibly this function will be removed from the
115
		void erase_face(FaceIter f)
194
				 public interface. 
116
		{
195
 
-
 
196
				 Note that if delayed_erase has been called, this function does
-
 
197
				 not immediately remove anything from the mesh. Instead the face
-
 
198
				 is reset to its initial state. Thus, iterators are not invalidated,
-
 
199
				 and it is possible to test whether f is used calling:
-
 
200
				 is_used(f). when remove_unused is called, the actual removal
117
			face_db.erase(f);
201
				 takes place.
118
		}
202
			*/
119
 
203
 
-
 
204
			HalfEdgeIter halfedges_begin();
120
		/// Return iterator pointing to the first halfedge.
205
			///< Return iterator pointing to the first halfedge.
121
		HalfEdgeIter halfedges_begin() { return halfedge_db.begin();}
-
 
122
 
206
 
-
 
207
			HalfEdgeIter halfedges_end();
123
		/// Return iterator pointing to beyond the last halfedge.
208
			///< Return iterator pointing to beyond the last halfedge.
124
		HalfEdgeIter halfedges_end() { return halfedge_db.end(); }
-
 
125
	
209
 
-
 
210
			VertexIter vertices_begin();
126
		/// Return iterator pointing to the first vertex.
211
			///< Return iterator pointing to the first vertex.
127
		VertexIter vertices_begin() { return vertex_db.begin();}
-
 
128
 
212
 
-
 
213
			VertexIter vertices_end();
129
		/// Return iterator pointing to beyond the last vertex.
214
			///< Return iterator pointing to beyond the last vertex.
130
		VertexIter vertices_end() { return vertex_db.end(); }
-
 
131
 
215
 
-
 
216
			FaceIter faces_begin();
132
		/// Return iterator pointing to the first face.
217
			///< Return iterator pointing to the first face.
133
		FaceIter faces_begin() { return face_db.begin();	}
-
 
134
 
218
 
-
 
219
			FaceIter faces_end();
135
		/// Return iterator pointing to beyond the last face.
220
			///< Return iterator pointing to beyond the last face.
136
		FaceIter faces_end() { return face_db.end(); }
-
 
137
 
221
 
-
 
222
			bool collapse_precond(HalfEdgeIter h);
138
		/** \brief HalfEdge collapse precondition. 
223
			/**< \brief HalfEdge collapse precondition.
139
 
224
 
140
				The first argument, v, is the vertex we want to remove. The
225
			The argument h is the halfedge we want to collapse. 
141
				second, h, is a halfedge pointing away from that vertex.
-
 
142
 
226
 
143
				If this function does not return true, it is illegal to collapse
227
			If this function does not return true, it is illegal to collapse
144
				h. The reason is that the collapse would violate the manifold property
228
			h. The reason is that the collapse would violate the manifold property
145
				of the mesh.
229
			of the mesh.
146
 
230
 
Line 180... Line 264...
180
				6. PREVENT MERGING HOLES:
264
			6. PREVENT MERGING HOLES:
181
				We do not want to collapse an edge if its end points are boundary
265
			We do not want to collapse an edge if its end points are boundary
182
				vertices, but its two adjacent faces are not NULL faces, because
266
			vertices, but its two adjacent faces are not NULL faces, because
183
				in that case we create a vertex where two holes meet. A non manifold
267
			in that case we create a vertex where two holes meet. A non manifold
184
				situation.	*/
268
			situation.	*/
185
		bool collapse_precond(VertexIter v, HalfEdgeIter h);
-
 
186
		
269
 
187
		/** Collapse the halfedge h.
-
 
188
 
270
 
-
 
271
			void collapse_halfedge(HalfEdgeIter h, bool=false);
-
 
272
			/**< Collapse the halfedge h.
-
 
273
 
189
				The first argument, v, is the vertex that is being removed. The
274
			The argument h is the halfedge being removed. The vertex 
190
				second, h, is a halfedge pointing away from that vertex.
275
			v=h->opp->vert is the one being removed while h->vert survives.
191
 
276
 
192
				The final argument is a boolean indicating whether the vertex
277
			The final argument is a boolean indicating whether the vertex
193
				that survives the collapse should have a position which is the
278
			that survives the collapse should have a position which is the
194
				average of its own position and the vertex that is removed.
279
			average of its own position and the vertex that is removed.
-
 
280
			By default false meaning that the surviving vertex retains it 
195
				By default false.
281
			position.
196
 
282
 
197
				This function is not guaranteed to keep the mesh sane unless,
283
			This function is not guaranteed to keep the mesh sane unless,
198
				collapse_precond has returned true.
284
			collapse_precond has returned true !!
199
		*/
285
			*/
200
		void collapse_halfedge(VertexIter v, HalfEdgeIter h, bool=false);
-
 
201
 
286
 
-
 
287
			FaceIter split_face(FaceIter f, VertexIter v0, VertexIter v1);
202
		/** Split a face.
288
			/**< Split a face.
203
		    The face, f, is split by connecting two
289
				 The face, f, is split by connecting two
204
				vertices v0 and v1 (the next two arguments). The vertices of
290
				 vertices v0 and v1 (the next two arguments). The vertices of
205
				the old face between v0 and v1 (in counter clockwise order) 
291
				 the old face between v0 and v1 (in counter clockwise order) 
206
				continue to belong to f. The vertices between v1 and 
292
				 continue to belong to f. The vertices between v1 and 
207
				v0 belong to the new face. An iterator to the new face is 
293
				 v0 belong to the new face. An iterator to the new face is 
208
				returned. */
294
				 returned. */
209
		FaceIter split_face(FaceIter f, VertexIter v0, VertexIter v1);
-
 
210
 
295
 
-
 
296
			VertexIter split_edge(HalfEdgeIter h);
211
		/** Insert a new vertex on halfedge h.
297
			/**< Insert a new vertex on halfedge h.
212
				The new halfedge is insterted as the previous edge to h.
298
				 The new halfedge is insterted as the previous edge to h.
213
				An iterator to the inserted vertex is	returned. */
299
				 An iterator to the inserted vertex is	returned. */
214
		VertexIter Manifold::split_edge(HalfEdgeIter h);
-
 
215
 
300
 
-
 
301
			void triangulate(FaceIter f);
216
		/** Triangulate a polygonal face by repeatedly calling split_face. 
302
			/**< Triangulate a polygonal face by repeatedly calling split_face.
217
				Triangulate iteratively splits triangles off a polygon. The first 
303
				 Triangulate iteratively splits triangles off a polygon. The first 
218
				triangle split off is the one connecting f->last->vert and
304
				 triangle split off is the one connecting f->last->vert and
219
				f->last->next->next->vert.
305
				 f->last->next->next->vert.
220
		*/
306
			*/
221
		void triangulate(FaceIter f);
-
 
222
 
307
 
-
 
308
			VertexIter safe_triangulate(FaceIter f);
223
		/** Triangulate a polygon, f, by inserting a vertex at the barycenter.
309
			/**< Triangulate a polygon, f, by inserting a vertex at the barycenter.
224
				All vertices in f are connected to the new vertex.				
310
				 All vertices in f are connected to the new vertex.				
225
				The word "safe" means that it is less likely to create flipped
311
				 The word "safe" means that it is less likely to create flipped
226
				triangles than the normal triangulate. On the other hand, it 
312
				 triangles than the normal triangulate. On the other hand, it 
227
				introduces more vertices and probably makes the triangles more
313
				 introduces more vertices and probably makes the triangles more
228
				acute. This function simply calls face_insert_point.
314
				 acute. This function simply calls face_insert_point.
229
 
315
 
230
				The inserted vertex is returned.
316
				 The inserted vertex is returned.
231
		*/
317
			*/
232
		VertexIter safe_triangulate(FaceIter f);
-
 
233
 
318
 
-
 
319
			void face_insert_point(FaceIter f, VertexIter v);
234
		/** Insert a new vertex, v, in a face, f.
320
			/**< Insert a new vertex, v, in a face, f.
235
				This operation splits an N-gon into N triangles.
321
				 This operation splits an N-gon into N triangles.
236
				In the current implementation the original face is erased. 
322
				 In the current implementation the original face is erased. 
237
				This means that the iterator is not valid after the function
323
				 This means that the iterator is not valid after the function
238
				returns. 
324
				 returns. 
239
		*/
325
			*/
240
		void face_insert_point(FaceIter f, VertexIter v);
-
 
241
 
326
 
-
 
327
			bool merge_faces(FaceIter f, HalfEdgeIter h);
242
		/** Merges two faces into a single polygon. The first face is f.  The
328
			/**< Merges two faces into a single polygon. The first face is f.  The
243
				second face is adjacent to f along the halfedge h. This function
329
				 second face is adjacent to f along the halfedge h. This function
244
				returns true if the merging was possible and false
330
				 returns true if the merging was possible and false
245
				otherwise. Currently merge only fails if the mesh is already
331
				 otherwise. Currently merge only fails if the mesh is already
246
				illegal. Thus it should, in fact, never fail. */
332
				 illegal. Thus it should, in fact, never fail. */
247
		bool merge_faces(FaceIter f, HalfEdgeIter h);
-
 
248
 
333
 
-
 
334
			bool flip(HalfEdgeIter h);
249
		/** Flip an edge h. Returns false if flipping cannot be performed.
335
			/**< Flip an edge h. Returns false if flipping cannot be performed.
250
				This is either because one of the two adjacent faces is not
336
				 This is either because one of the two adjacent faces is not
251
				a triangle, or because either end point has valency three or
337
				 a triangle, or because either end point has valency three or
252
				because the vertices that will be connected already are. */
338
				 because the vertices that will be connected already are. */
253
		bool flip(HalfEdgeIter h);
-
 
254
 
339
 
255
		/** Performs a series of tests to check that this is a valid manifold.
340
			void get_bbox(CGLA::Vec3f& pmin, CGLA::Vec3f& pmax);
256
				This function is not rigorously constructed but seems to catch
341
			/**< Return the bounding box of the manifold. The arguments pmin and pmax
257
				all problems so far. The function returns true if the mesh is 
342
				 will contain the extreme corners of the box when the function 
258
				valid and false otherwise.
-
 
259
		*/
-
 
260
		bool is_valid();
343
				 returns.	*/
261
 
344
 
-
 
345
			void get_bsphere(CGLA::Vec3f& c, float& r);
262
		/** Give each vertex a unique id corresponding to its iterator 
346
			/**< Get a bounding sphere. When the function returns, c contains the
263
				position */
347
				 centre and r the radius. */ 
264
		void enumerate_vertices();
348
		};
265
 
349
			
266
		/** Give each halfedge a unique id corresponding to its iterator 
-
 
267
				position */
-
 
268
		void enumerate_halfedges();
-
 
269
 
350
 
270
		/** Give each face a unique id corresponding to its iterator 
351
	inline HalfEdgeIter Manifold::halfedges_begin() 
271
				position */
352
		{
272
		void enumerate_faces();
353
			return halfedge_db.begin();
-
 
354
		}
273
		
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;
274
	};
429
		}
275
 
430
 
276
 
431
 
277
}
432
}
278
#endif
433
#endif