Developer Documentation
BaseDecimaterT.cc
1 /* ========================================================================= *
2  * *
3  * OpenMesh *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openmesh.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenMesh. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39  * *
40  * ========================================================================= */
41 
42 /*===========================================================================*\
43  * *
44  * $Revision$ *
45  * $Date$ *
46  * *
47  \*===========================================================================*/
48 
52 //=============================================================================
53 //
54 // CLASS DecimaterT - IMPLEMENTATION
55 //
56 //=============================================================================
57 #define OPENMESH_BASE_DECIMATER_DECIMATERT_CC
58 
59 //== INCLUDES =================================================================
60 
61 #include <vector>
62 #if defined(OM_CC_MIPS)
63 # include <float.h>
64 #else
65 # include <cfloat>
66 #endif
67 
68 //== NAMESPACE ===============================================================
69 
70 namespace OpenMesh {
71 namespace Decimater {
72 
73 //== IMPLEMENTATION ==========================================================
74 
75 template<class Mesh>
76 BaseDecimaterT<Mesh>::BaseDecimaterT(Mesh& _mesh) :
77  mesh_(_mesh), cmodule_(NULL), initialized_(false), observer_(NULL) {
78  // default properties
79  mesh_.request_vertex_status();
80  mesh_.request_edge_status();
81  mesh_.request_face_status();
82 
83 }
84 
85 //-----------------------------------------------------------------------------
86 
87 template<class Mesh>
88 BaseDecimaterT<Mesh>::~BaseDecimaterT() {
89  // default properties
90  mesh_.release_vertex_status();
91  mesh_.release_edge_status();
92  mesh_.release_face_status();
93 
94  // dispose of modules
95  {
96  set_uninitialized();
97  typename ModuleList::iterator m_it, m_end = all_modules_.end();
98  for (m_it = all_modules_.begin(); m_it != m_end; ++m_it)
99  delete *m_it;
100  all_modules_.clear();
101  }
102 }
103 
104 //-----------------------------------------------------------------------------
105 
106 template<class Mesh>
108  // std::clog << "McDecimaterT<>::is_collapse_legal()\n";
109 
110  // locked ?
111  if (mesh_.status(_ci.v0).locked())
112  return false;
113 
114  // this test checks:
115  // is v0v1 deleted?
116  // is v0 deleted?
117  // is v1 deleted?
118  // are both vlv0 and v1vl boundary edges?
119  // are both v0vr and vrv1 boundary edges?
120  // are vl and vr equal or both invalid?
121  // one ring intersection test
122  // edge between two boundary vertices should be a boundary edge
123  if (!mesh_.is_collapse_ok(_ci.v0v1))
124  return false;
125 
126  if (_ci.vl.is_valid() && _ci.vr.is_valid()
127  && mesh_.find_halfedge(_ci.vl, _ci.vr).is_valid()
128  && mesh_.valence(_ci.vl) == 3 && mesh_.valence(_ci.vr) == 3) {
129  return false;
130  }
131  //--- feature test ---
132 
133  if (mesh_.status(_ci.v0).feature()
134  && !mesh_.status(mesh_.edge_handle(_ci.v0v1)).feature())
135  return false;
136 
137  //--- test boundary cases ---
138  if (mesh_.is_boundary(_ci.v0)) {
139 
140  // don't collapse a boundary vertex to an inner one
141  if (!mesh_.is_boundary(_ci.v1))
142  return false;
143 
144  // only one one ring intersection
145  if (_ci.vl.is_valid() && _ci.vr.is_valid())
146  return false;
147  }
148 
149  // there have to be at least 2 incident faces at v0
150  if (mesh_.cw_rotated_halfedge_handle(
151  mesh_.cw_rotated_halfedge_handle(_ci.v0v1)) == _ci.v0v1)
152  return false;
153 
154  // collapse passed all tests -> ok
155  return true;
156 }
157 
158 //-----------------------------------------------------------------------------
159 
160 template<class Mesh>
162  typename ModuleList::iterator m_it, m_end = bmodules_.end();
163 
164  for (m_it = bmodules_.begin(); m_it != m_end; ++m_it) {
165  if ((*m_it)->collapse_priority(_ci) < 0.0)
167  }
168  return cmodule_->collapse_priority(_ci);
169 }
170 
171 //-----------------------------------------------------------------------------
172 
173 template<class Mesh>
175  typename ModuleList::iterator m_it, m_end = bmodules_.end();
176 
177  for (m_it = bmodules_.begin(); m_it != m_end; ++m_it)
178  (*m_it)->postprocess_collapse(_ci);
179 
180  cmodule_->postprocess_collapse(_ci);
181 }
182 
183 //-----------------------------------------------------------------------------
184 
185 template<class Mesh>
187  typename ModuleList::iterator m_it, m_end = bmodules_.end();
188 
189  for (m_it = bmodules_.begin(); m_it != m_end; ++m_it)
190  (*m_it)->preprocess_collapse(_ci);
191 
192  cmodule_->preprocess_collapse(_ci);
193 }
194 
195 //-----------------------------------------------------------------------------
196 
197 template<class Mesh>
199  if (_factor >= 0.0 && _factor <= 1.0) {
200  typename ModuleList::iterator m_it, m_end = bmodules_.end();
201 
202  for (m_it = bmodules_.begin(); m_it != m_end; ++m_it)
203  (*m_it)->set_error_tolerance_factor(_factor);
204 
205  cmodule_->set_error_tolerance_factor(_factor);
206  }
207 }
208 
209 //-----------------------------------------------------------------------------
210 
211 template<class Mesh>
212 void BaseDecimaterT<Mesh>::info(std::ostream& _os) {
213  if (initialized_) {
214  _os << "initialized : yes" << std::endl;
215  _os << "binary modules: " << bmodules_.size() << std::endl;
216  for (ModuleListIterator m_it = bmodules_.begin(); m_it != bmodules_.end();
217  ++m_it) {
218  _os << " " << (*m_it)->name() << std::endl;
219  }
220  _os << "priority module: " << cmodule_->name().c_str() << std::endl;
221  } else {
222  _os << "initialized : no" << std::endl;
223  _os << "available modules: " << all_modules_.size() << std::endl;
224  for (ModuleListIterator m_it = all_modules_.begin();
225  m_it != all_modules_.end(); ++m_it) {
226  _os << " " << (*m_it)->name() << " : ";
227  if ((*m_it)->is_binary()) {
228  _os << "binary";
229  if ((*m_it)->name() == "Quadric") {
230  _os << " and priority (special treatment)";
231  }
232  } else {
233  _os << "priority";
234  }
235  _os << std::endl;
236  }
237  }
238 }
239 
240 //-----------------------------------------------------------------------------
241 
242 template<class Mesh>
244  if (initialized_) {
245  return true;
246  }
247 
248  // FIXME: quadric module shouldn't be treated specially.
249  // Q: Why?
250  // A: It isn't generic and breaks encapsulation. Also, using string
251  // name comparison is not reliable, since you can't guarantee that
252  // no one else will name their custom module "Quadric".
253  // Q: What should be done instead?
254  // A: ModBaseT API should support modules that can be both binary
255  // and priority, or BETTER YET, let the DecimaterT API specify the
256  // priority module explicitly.
257 
258  // find the priority module: either the only non-binary module in the list, or "Quadric"
259  Module *quadric = NULL;
260  Module *pmodule = NULL;
261  for (ModuleListIterator m_it = all_modules_.begin(), m_end =
262  all_modules_.end(); m_it != m_end; ++m_it) {
263  if ((*m_it)->name() == "Quadric")
264  quadric = *m_it;
265 
266  if (!(*m_it)->is_binary()) {
267  if (pmodule) {
268  // only one priority module allowed!
269  set_uninitialized();
270  return false;
271  }
272  pmodule = *m_it;
273  }
274  }
275 
276  // Quadric is used as default priority module (even if it is set to be binary)
277  if (!pmodule && quadric) {
278  pmodule = quadric;
279  }
280 
281  if (!pmodule) {
282  // At least one priority module required
283  set_uninitialized();
284  return false;
285  }
286 
287  // set pmodule as the current priority module
288  cmodule_ = pmodule;
289 
290  for (ModuleListIterator m_it = all_modules_.begin(), m_end =
291  all_modules_.end(); m_it != m_end; ++m_it) {
292  // every module gets initialized
293  (*m_it)->initialize();
294 
295  if (*m_it != pmodule) {
296  // all other modules are binary, and go into bmodules_ list
297  bmodules_.push_back(*m_it);
298  }
299  }
300 
301  return initialized_ = true;
302 }
303 
304 
305 
306 //=============================================================================
307 }// END_NS_DECIMATER
308 } // END_NS_OPENMESH
309 //=============================================================================
310 
Mesh::VertexHandle v1
Remaining vertex.
Mesh::VertexHandle vr
Right vertex.
virtual void initialize()
Initialize module-internal stuff.
Definition: ModBaseT.hh:234
void postprocess_collapse(CollapseInfo &_ci)
Post-process a collapse.
virtual float collapse_priority(const CollapseInfoT< MeshT > &)
Definition: ModBaseT.hh:250
Mesh::VertexHandle vl
Left vertex.
Mesh::HalfedgeHandle v0v1
Halfedge to be collapsed.
Mesh::VertexHandle v0
Vertex to be removed.
void preprocess_collapse(CollapseInfo &_ci)
Pre-process a collapse.
void set_error_tolerance_factor(double _factor)