Developer Documentation
StatusAttribT_impl.hh
1#pragma once
2/*===========================================================================*\
3 * *
4 * OpenVolumeMesh *
5 * Copyright (C) 2011 by Computer Graphics Group, RWTH Aachen *
6 * www.openvolumemesh.org *
7 * *
8 *---------------------------------------------------------------------------*
9 * This file is part of OpenVolumeMesh. *
10 * *
11 * OpenVolumeMesh is free software: you can redistribute it and/or modify *
12 * it under the terms of the GNU Lesser General Public License as *
13 * published by the Free Software Foundation, either version 3 of *
14 * the License, or (at your option) any later version with the *
15 * following exceptions: *
16 * *
17 * If other files instantiate templates or use macros *
18 * or inline functions from this file, or you compile this file and *
19 * link it with other files to produce an executable, this file does *
20 * not by itself cause the resulting executable to be covered by the *
21 * GNU Lesser General Public License. This exception does not however *
22 * invalidate any other reasons why the executable file might be *
23 * covered by the GNU Lesser General Public License. *
24 * *
25 * OpenVolumeMesh is distributed in the hope that it will be useful, *
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
28 * GNU Lesser General Public License for more details. *
29 * *
30 * You should have received a copy of the GNU LesserGeneral Public *
31 * License along with OpenVolumeMesh. If not, *
32 * see <http://www.gnu.org/licenses/>. *
33 * *
34\*===========================================================================*/
35
36#include <OpenVolumeMesh/Attribs/StatusAttrib.hh>
37
38#include <OpenVolumeMesh/Core/TopologyKernel.hh>
39#include <OpenVolumeMesh/Core/Properties/PropertyPtr.hh>
40
41#include <map>
42
43namespace OpenVolumeMesh {
44//========================================================================================
45
46template<typename std_API_Container_VHandlePointer,
47 typename std_API_Container_HHandlePointer,
48 typename std_API_Container_HFHandlePointer,
49 typename std_API_Container_CHandlePointer>
50void StatusAttrib::garbage_collection(std_API_Container_VHandlePointer & vh_to_update,
51 std_API_Container_HHandlePointer & hh_to_update,
52 std_API_Container_HFHandlePointer & hfh_to_update,
53 std_API_Container_CHandlePointer & ch_to_update,
54 bool _preserveManifoldness)
55{
56 const auto &status = *this;
57 auto def = kernel_->deferred_deletion_enabled();
58 kernel_->enable_deferred_deletion(true);
59 for (const auto vh: kernel_->vertices()) {
60 if (status[vh].deleted()) {
61 kernel_->delete_vertex(vh);
62 }
63 }
64 for (const auto eh: kernel_->edges()) {
65 if (status[eh].deleted() && !kernel_->is_deleted(eh)) {
66 kernel_->delete_edge(eh);
67 }
68 }
69 for (const auto fh: kernel_->faces()) {
70 if (status[fh].deleted() && !kernel_->is_deleted(fh)) {
71 kernel_->delete_face(fh);
72 }
73 }
74 for (const auto ch: kernel_->cells()) {
75 if (status[ch].deleted() && !kernel_->is_deleted(ch)) {
76 kernel_->delete_cell(ch);
77 }
78 }
79
80
81 if (_preserveManifoldness) {
82 kernel_->enable_bottom_up_incidences(true);
83 for (const auto fh: kernel_->faces()) {
84 if (kernel_->incident_cell(kernel_->halfface_handle(fh, 0)).is_valid()) continue;
85 if (kernel_->incident_cell(kernel_->halfface_handle(fh, 1)).is_valid()) continue;
86 kernel_->delete_face(fh);
87 }
88 for (const auto eh: kernel_->edges()) {
89 if (kernel_->valence(eh) == 0) {
90 kernel_->delete_edge(eh);
91 }
92 }
93 for (const auto vh: kernel_->vertices()) {
94 if (kernel_->valence(vh) == 0) {
95 kernel_->delete_vertex(vh);
96 }
97 }
98 }
99 if (!vh_to_update.empty()
100 || !hh_to_update.empty()
101 || !hfh_to_update.empty()
102 || !ch_to_update.empty())
103 {
104 auto nv = static_cast<int>(kernel_->n_vertices());
105 auto nhe = static_cast<int>(kernel_->n_halfedges());
106 auto nhf = static_cast<int>(kernel_->n_halffaces());
107 auto nc = static_cast<int>(kernel_->n_cells());
108
109 auto old_vh = kernel_->request_vertex_property<int>();
110 for (int i = 0; i < nv; ++i) { old_vh[VertexHandle(i)] = i; }
111 auto old_heh = kernel_->request_halfedge_property<int>();
112 for (int i = 0; i < nhe; ++i) { old_heh[HalfEdgeHandle(i)] = i; }
113 auto old_hfh = kernel_->request_halfface_property<int>();
114 for (int i = 0; i < nhf; ++i) { old_hfh[HalfFaceHandle(i)] = i; }
115 auto old_ch = kernel_->request_cell_property<int>();
116 for (int i = 0; i < nc; ++i) { old_ch[CellHandle(i)] = i; }
117
118 kernel_->collect_garbage();
119
120 std::vector<VertexHandle> new_vh; new_vh.resize(nv);
121 std::vector<CellHandle> new_ch; new_ch.resize(nc);
122 std::vector<HalfEdgeHandle> new_heh; new_heh.resize(nhe);
123 std::vector<HalfFaceHandle> new_hfh; new_hfh.resize(nhf);
124
125 for (const auto vh: kernel_->vertices()) { new_vh[old_vh[vh]] = vh; }
126 for (const auto heh: kernel_->halfedges()) { new_heh[old_heh[heh]] = heh; }
127 for (const auto hfh: kernel_->halffaces()) { new_hfh[old_hfh[hfh]] = hfh; }
128 for (const auto ch: kernel_->cells()) { new_ch[old_ch[ch]] = ch; }
129
130 for (auto *vh: vh_to_update) { if (vh->is_valid()) *vh = new_vh[vh->idx()]; }
131 for (auto *heh: hh_to_update) { if (heh->is_valid()) *heh = new_heh[heh->idx()]; }
132 for (auto *hfh: hfh_to_update) { if (hfh->is_valid()) *hfh = new_hfh[hfh->idx()]; }
133 for (auto *ch: ch_to_update) { if (ch->is_valid()) *ch = new_ch[ch->idx()]; }
134
135 } else {
136 kernel_->collect_garbage();
137 }
138
139 kernel_->enable_deferred_deletion(def);
140
141 // TODO: provide compatibility implementation
142#if 0
143
144 /*
145 * This is not a real garbage collection in its conventional
146 * sense. What happens in this routine are the following steps:
147 *
148 * 1. If an entity of dimension n is marked to be deleted,
149 * also mark all incident entities of dimension n + 1
150 * for deletion. Do this in a bottom-up fashion.
151 * 2. Then delete all entities in top-down manner, so that
152 * no invalid incident higher-dimensional entity is generated.
153 * 3. If desired, search for all isolated entities and mark
154 * them deleted in a top-down manner.
155 * 4. Delete all entities marked deleted in step 4 in order
156 * to prevent manifoldness.
157 */
158
159 // setup tracking so we can update the given handles
160 bool track_vh = !vh_to_update.empty();
161 bool track_hh = !hh_to_update.empty();
162 bool track_hfh = !hfh_to_update.empty();
163 bool track_ch = !ch_to_update.empty();
164 int offset_vh = 0;
165 int offset_hh = 0;
166 int offset_hfh = 0;
167 int offset_ch = 0;
168
169 std::map<int,int> vh_map;
170 std::map<int,int> hh_map;
171 std::map<int,int> hfh_map;
172 std::map<int,int> ch_map;
173
174 // initialise the maps
175 if (track_vh) {
176 typename std_API_Container_VHandlePointer::iterator it = vh_to_update.begin();
177 typename std_API_Container_VHandlePointer::iterator end = vh_to_update.end();
178
179 for (; it != end; ++it) {
180 vh_map[(*it)->idx()] = (*it)->idx();
181 }
182 }
183 if (track_hh) {
184 typename std_API_Container_HHandlePointer::iterator it = hh_to_update.begin();
185 typename std_API_Container_HHandlePointer::iterator end = hh_to_update.end();
186
187 for (; it != end; ++it) {
188 hh_map[(*it)->idx()] = (*it)->idx();
189 }
190 }
191 if (track_hfh) {
192 typename std_API_Container_HFHandlePointer::iterator it = hfh_to_update.begin();
193 typename std_API_Container_HFHandlePointer::iterator end = hfh_to_update.end();
194
195 for (; it != end; ++it) {
196 hfh_map[(*it)->idx()] = (*it)->idx();
197 }
198 }
199 if (track_ch) {
200 typename std_API_Container_CHandlePointer::iterator it = ch_to_update.begin();
201 typename std_API_Container_CHandlePointer::iterator end = ch_to_update.end();
202
203 for (; it != end; ++it) {
204 ch_map[(*it)->idx()] = (*it)->idx();
205 }
206 }
207
208 // Mark all higher-dimensional entities incident to
209 // entities marked as deleted from bottom to top
210 mark_higher_dim_entities();
211
212 std::vector<int> vertexIndexMap(kernel_->n_vertices(), -1);
213
214 // Turn off bottom-up incidences
215 bool v_bu = kernel_->has_vertex_bottom_up_incidences();
216 bool e_bu = kernel_->has_edge_bottom_up_incidences();
217 bool f_bu = kernel_->has_face_bottom_up_incidences();
218
219 kernel_->enable_bottom_up_incidences(false);
220
221 std::vector<bool> tags(kernel_->n_cells(), false);
222 std::vector<bool>::iterator tag_it = tags.begin();
223
224 for(CellIter c_it = kernel_->cells_begin(); c_it != kernel_->cells_end(); ++c_it, ++tag_it) {
225 *tag_it = c_status_[*c_it].deleted();
226
227 if (track_ch) {
228 if (c_status_[*c_it].deleted()) {
229 ++offset_ch;
230 auto it = ch_map.find(c_it->idx());
231 if (it != ch_map.end()) {
232 it->second = -1;
233 }
234 } else {
235 auto it = ch_map.find(c_it->idx());
236 if (it != ch_map.end()) {
237 it->second = c_it->idx() - offset_ch;
238 }
239 }
240 }
241 }
242 kernel_->delete_multiple_cells(tags);
243
244 tags.resize(kernel_->n_faces(), false);
245 tag_it = tags.begin();
246
247 for(FaceIter f_it = kernel_->faces_begin(); f_it != kernel_->faces_end(); ++f_it, ++tag_it) {
248 *tag_it = f_status_[*f_it].deleted();
249
250 if (track_hfh) {
251 int halfface_idx = f_it->idx() * 2;
252 if (f_status_[*f_it].deleted()) {
253 offset_hfh += 2;
254 auto it = hfh_map.find(halfface_idx);
255 if (it != hfh_map.end()) {
256 it->second = -1;
257 }
258 it = hfh_map.find(halfface_idx + 1);
259 if (it != hfh_map.end()) {
260 it->second = -1;
261 }
262 } else {
263 auto it = hfh_map.find(halfface_idx);
264 if (it != hfh_map.end()) {
265 it->second = halfface_idx - offset_hfh;
266 }
267 it = hfh_map.find(halfface_idx + 1);
268 if (it != hfh_map.end()) {
269 it->second = halfface_idx + 1 - offset_hfh;
270 }
271 }
272 }
273 }
274 kernel_->delete_multiple_faces(tags);
275
276 tags.resize(kernel_->n_edges(), false);
277 tag_it = tags.begin();
278
279 for(EdgeIter e_it = kernel_->edges_begin(); e_it != kernel_->edges_end(); ++e_it, ++tag_it) {
280 *tag_it = e_status_[*e_it].deleted();
281
282 if (track_hh) {
283 int halfedge_idx = e_it->idx() * 2;
284 if (e_status_[*e_it].deleted()) {
285 offset_hh += 2;
286 auto it = hh_map.find(halfedge_idx);
287 if (it != hh_map.end()) {
288 it->second = -1;
289 }
290 it = hh_map.find(halfedge_idx + 1);
291 if (it != hh_map.end()) {
292 it->second = -1;
293 }
294 } else {
295 auto it = hh_map.find(halfedge_idx);
296 if (it != hh_map.end()) {
297 it->second = halfedge_idx - offset_hh;
298 }
299 it = hh_map.find(halfedge_idx + 1);
300 if (it != hh_map.end()) {
301 it->second = halfedge_idx + 1 - offset_hh;
302 }
303 }
304 }
305 }
306 kernel_->delete_multiple_edges(tags);
307
308 tags.resize(kernel_->n_vertices(), false);
309 tag_it = tags.begin();
310
311 for(VertexIter v_it = kernel_->vertices_begin(); v_it != kernel_->vertices_end(); ++v_it, ++tag_it) {
312 *tag_it = v_status_[*v_it].deleted();
313
314 if (track_vh) {
315 if (v_status_[*v_it].deleted()) {
316 auto it = vh_map.find(v_it->idx());
317 if (it != vh_map.end()) {
318 ++offset_vh;
319 it->second = -1;
320 }
321 } else {
322 if (vh_map.find(v_it->idx()) != vh_map.end()) {
323 vh_map[v_it->idx()] = v_it->idx() - offset_vh;
324 }
325 }
326 }
327 }
328 kernel_->delete_multiple_vertices(tags);
329
330 // update given handles
331 if (track_vh) {
332 typename std_API_Container_VHandlePointer::iterator it = vh_to_update.begin();
333 typename std_API_Container_VHandlePointer::iterator end = vh_to_update.end();
334
335 for (; it != end; ++it) {
336 *(*it) = VertexHandle( vh_map[(*it)->idx()] );
337 }
338 }
339 if (track_hh) {
340 typename std_API_Container_HHandlePointer::iterator it = hh_to_update.begin();
341 typename std_API_Container_HHandlePointer::iterator end = hh_to_update.end();
342
343 for (; it != end; ++it) {
344 *(*it) = HalfEdgeHandle( hh_map[(*it)->idx()] );
345 }
346 }
347 if (track_hfh) {
348 typename std_API_Container_HFHandlePointer::iterator it = hfh_to_update.begin();
349 typename std_API_Container_HFHandlePointer::iterator end = hfh_to_update.end();
350
351 for (; it != end; ++it) {
352 *(*it) = HalfFaceHandle( hfh_map[(*it)->idx()] );
353 }
354 }
355 if (track_ch) {
356 typename std_API_Container_CHandlePointer::iterator it = ch_to_update.begin();
357 typename std_API_Container_CHandlePointer::iterator end = ch_to_update.end();
358
359 for (; it != end; ++it) {
360 *(*it) = CellHandle( ch_map[(*it)->idx()] );
361 }
362 }
363
364 // Todo: Resize props
365
366 if(v_bu) kernel_->enable_vertex_bottom_up_incidences(true);
367 if(e_bu) kernel_->enable_edge_bottom_up_incidences(true);
368 if(f_bu) kernel_->enable_face_bottom_up_incidences(true);
369
370 // Step 6
371 if(_preserveManifoldness) {
372 if(kernel_->has_full_bottom_up_incidences()) {
373
374 // Go over all faces and find those
375 // that are not incident to any cell
376 for(FaceIter f_it = kernel_->faces_begin(); f_it != kernel_->faces_end(); ++f_it) {
377
378 // Get half-faces
379 HalfFaceHandle hf0 = kernel_->halfface_handle(*f_it, 0);
380 HalfFaceHandle hf1 = kernel_->halfface_handle(*f_it, 1);
381
382 // If neither of the half-faces is incident to a cell, delete face
383 if(kernel_->incident_cell(hf0) == TopologyKernel::InvalidCellHandle &&
384 kernel_->incident_cell(hf1) == TopologyKernel::InvalidCellHandle) {
385
386 f_status_[*f_it].set_deleted(true);
387 }
388 }
389
390 // Go over all edges and find those
391 // whose half-edges are not incident to any half-face
392 for(EdgeIter e_it = kernel_->edges_begin(); e_it != kernel_->edges_end(); ++e_it) {
393
394 // Get half-edges
395 HalfEdgeHandle he = kernel_->halfedge_handle(*e_it, 0);
396
397 // If the half-edge isn't incident to a half-face, delete edge
398 HalfEdgeHalfFaceIter hehf_it = kernel_->hehf_iter(he);
399
400 if(!hehf_it.valid()) {
401
402 e_status_[*e_it].set_deleted(true);
403
404 } else {
405 bool validFace = false;
406 for(; hehf_it.valid(); ++hehf_it) {
407 if(!f_status_[kernel_->face_handle(*hehf_it)].deleted()) {
408 validFace = true;
409 break;
410 }
411 }
412 if(!validFace) {
413 e_status_[*e_it].set_deleted(true);
414 }
415 }
416 }
417
418 // Go over all vertices and find those
419 // that are not incident to any edge
420 for(VertexIter v_it = kernel_->vertices_begin(); v_it != kernel_->vertices_end(); ++v_it) {
421
422 // If neither of the half-edges is incident to a half-face, delete edge
423 VertexOHalfEdgeIter voh_it = kernel_->voh_iter(*v_it);
424
425 if(!voh_it.valid()) {
426
427 v_status_[*v_it].set_deleted(true);
428 } else {
429
430 bool validEdge = false;
431 for(; voh_it.valid(); ++voh_it) {
432 if(!e_status_[kernel_->edge_handle(*voh_it)].deleted()) {
433 validEdge = true;
434 break;
435 }
436 }
437 if(!validEdge) {
438 v_status_[*v_it].set_deleted(true);
439 }
440 }
441 }
442
443 // Recursive call
444 garbage_collection(vh_to_update, hh_to_update, hfh_to_update, ch_to_update, false);
445
446 } else {
447#ifndef NDEBUG
448 std::cerr << "Preservation of three-manifoldness in garbage_collection() "
449 << "requires bottom-up incidences!" << std::endl;
450#endif
451 return;
452 }
453 }
454#endif
455}
456} // namespace OpenVolumeMesh
void garbage_collection(bool _preserveManifoldness=false)
Delete all entities that have been marked as deleted.
size_t valence(VertexHandle _vh) const
Get valence of vertex (number of incident edges)
virtual VertexIter delete_vertex(VertexHandle _h)
Delete vertex from mesh.
CellHandle incident_cell(HalfFaceHandle _halfFaceHandle) const
Get cell that is incident to the given halfface.
size_t n_halfedges() const override
Get number of halfedges in mesh.
static HalfEdgeHandle halfedge_handle(EdgeHandle _h, const unsigned char _subIdx)
Conversion function.
virtual CellIter delete_cell(CellHandle _h)
Delete cell from mesh.
static EdgeHandle edge_handle(HalfEdgeHandle _h)
Handle conversion.
size_t n_vertices() const override
Get number of vertices in mesh.
virtual FaceIter delete_face(FaceHandle _h)
Delete face from mesh.
static HalfFaceHandle halfface_handle(FaceHandle _h, const unsigned char _subIdx)
Conversion function.
size_t n_faces() const override
Get number of faces in mesh.
size_t n_cells() const override
Get number of cells in mesh.
size_t n_edges() const override
Get number of edges in mesh.
virtual EdgeIter delete_edge(EdgeHandle _h)
Delete edge from mesh.
size_t n_halffaces() const override
Get number of halffaces in mesh.
virtual void collect_garbage()
Delete all entities that are marked as deleted.