Developer Documentation
BaseDecimaterT_impl.hh
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 
45 //=============================================================================
46 //
47 // CLASS DecimaterT - IMPLEMENTATION
48 //
49 //=============================================================================
50 #define OPENMESH_BASE_DECIMATER_DECIMATERT_CC
51 
52 //== INCLUDES =================================================================
53 
54 #include <vector>
55 #if defined(OM_CC_MIPS)
56 # include <float.h>
57 #else
58 # include <cfloat>
59 #endif
60 
61 //== NAMESPACE ===============================================================
62 
63 namespace OpenMesh {
64 namespace Decimater {
65 
66 //== IMPLEMENTATION ==========================================================
67 
68 template<class Mesh>
69 BaseDecimaterT<Mesh>::BaseDecimaterT(Mesh& _mesh) :
70  mesh_(_mesh), cmodule_(nullptr), initialized_(false), observer_(nullptr) {
71  // default properties
72  mesh_.request_vertex_status();
73  mesh_.request_edge_status();
74  mesh_.request_face_status();
75 
76 }
77 
78 //-----------------------------------------------------------------------------
79 
80 template<class Mesh>
81 BaseDecimaterT<Mesh>::~BaseDecimaterT() {
82  // default properties
83  mesh_.release_vertex_status();
84  mesh_.release_edge_status();
85  mesh_.release_face_status();
86 
87  // dispose of modules
88  {
90  typename ModuleList::iterator m_it, m_end = all_modules_.end();
91  for (m_it = all_modules_.begin(); m_it != m_end; ++m_it)
92  delete *m_it;
93  all_modules_.clear();
94  }
95 }
96 
97 //-----------------------------------------------------------------------------
98 
99 template<class Mesh>
101  // std::clog << "McDecimaterT<>::is_collapse_legal()\n";
102 
103  // locked ?
104  if (mesh_.status(_ci.v0).locked())
105  return false;
106 
107  // this test checks:
108  // is v0v1 deleted?
109  // is v0 deleted?
110  // is v1 deleted?
111  // are both vlv0 and v1vl boundary edges?
112  // are both v0vr and vrv1 boundary edges?
113  // are vl and vr equal or both invalid?
114  // one ring intersection test
115  // edge between two boundary vertices should be a boundary edge
116  if (!mesh_.is_collapse_ok(_ci.v0v1))
117  return false;
118 
119  if (_ci.vl.is_valid() && _ci.vr.is_valid()
120  && mesh_.find_halfedge(_ci.vl, _ci.vr).is_valid()
121  && mesh_.valence(_ci.vl) == 3 && mesh_.valence(_ci.vr) == 3) {
122  return false;
123  }
124  //--- feature test ---
125 
126  if (mesh_.status(_ci.v0).feature()
127  && !mesh_.status(mesh_.edge_handle(_ci.v0v1)).feature())
128  return false;
129 
130  //--- test boundary cases ---
131  if (mesh_.is_boundary(_ci.v0)) {
132 
133  // don't collapse a boundary vertex to an inner one
134  if (!mesh_.is_boundary(_ci.v1))
135  return false;
136 
137  // only one one ring intersection
138  if (_ci.vl.is_valid() && _ci.vr.is_valid())
139  return false;
140  }
141 
142  // there have to be at least 2 incident faces at v0
143  if (mesh_.cw_rotated_halfedge_handle(
144  mesh_.cw_rotated_halfedge_handle(_ci.v0v1)) == _ci.v0v1)
145  return false;
146 
147  // collapse passed all tests -> ok
148  return true;
149 }
150 
151 //-----------------------------------------------------------------------------
152 
153 template<class Mesh>
155  typename ModuleList::iterator m_it, m_end = bmodules_.end();
156 
157  for (m_it = bmodules_.begin(); m_it != m_end; ++m_it) {
158  if ((*m_it)->collapse_priority(_ci) < 0.0)
160  }
161  return cmodule_->collapse_priority(_ci);
162 }
163 
164 //-----------------------------------------------------------------------------
165 
166 template<class Mesh>
168  typename ModuleList::iterator m_it, m_end = bmodules_.end();
169 
170  for (m_it = bmodules_.begin(); m_it != m_end; ++m_it)
171  (*m_it)->postprocess_collapse(_ci);
172 
174 }
175 
176 //-----------------------------------------------------------------------------
177 
178 template<class Mesh>
180  typename ModuleList::iterator m_it, m_end = bmodules_.end();
181 
182  for (m_it = bmodules_.begin(); m_it != m_end; ++m_it)
183  (*m_it)->preprocess_collapse(_ci);
184 
186 }
187 
188 //-----------------------------------------------------------------------------
189 
190 template<class Mesh>
192  if (_factor >= 0.0 && _factor <= 1.0) {
193  typename ModuleList::iterator m_it, m_end = bmodules_.end();
194 
195  for (m_it = bmodules_.begin(); m_it != m_end; ++m_it)
196  (*m_it)->set_error_tolerance_factor(_factor);
197 
199  }
200 }
201 
202 //-----------------------------------------------------------------------------
203 
204 template<class Mesh>
205 void BaseDecimaterT<Mesh>::info(std::ostream& _os) {
206  if (initialized_) {
207  _os << "initialized : yes" << std::endl;
208  _os << "binary modules: " << bmodules_.size() << std::endl;
209  for (ModuleListIterator m_it = bmodules_.begin(); m_it != bmodules_.end();
210  ++m_it) {
211  _os << " " << (*m_it)->name() << std::endl;
212  }
213  _os << "priority module: " << cmodule_->name().c_str() << std::endl;
214  } else {
215  _os << "initialized : no" << std::endl;
216  _os << "available modules: " << all_modules_.size() << std::endl;
217  for (ModuleListIterator m_it = all_modules_.begin();
218  m_it != all_modules_.end(); ++m_it) {
219  _os << " " << (*m_it)->name() << " : ";
220  if ((*m_it)->is_binary()) {
221  _os << "binary";
222  if ((*m_it)->name() == "Quadric") {
223  _os << " and priority (special treatment)";
224  }
225  } else {
226  _os << "priority";
227  }
228  _os << std::endl;
229  }
230  }
231 }
232 
233 //-----------------------------------------------------------------------------
234 
235 template<class Mesh>
237  if (initialized_) {
238  return true;
239  }
240 
241  // FIXME: quadric module shouldn't be treated specially.
242  // Q: Why?
243  // A: It isn't generic and breaks encapsulation. Also, using string
244  // name comparison is not reliable, since you can't guarantee that
245  // no one else will name their custom module "Quadric".
246  // Q: What should be done instead?
247  // A: ModBaseT API should support modules that can be both binary
248  // and priority, or BETTER YET, let the DecimaterT API specify the
249  // priority module explicitly.
250 
251  // find the priority module: either the only non-binary module in the list, or "Quadric"
252  Module *quadric = nullptr;
253  Module *pmodule = nullptr;
254  for (ModuleListIterator m_it = all_modules_.begin(), m_end =
255  all_modules_.end(); m_it != m_end; ++m_it) {
256  if ((*m_it)->name() == "Quadric")
257  quadric = *m_it;
258 
259  if (!(*m_it)->is_binary()) {
260  if (pmodule) {
261  // only one priority module allowed!
263  return false;
264  }
265  pmodule = *m_it;
266  }
267  }
268 
269  // Quadric is used as default priority module (even if it is set to be binary)
270  if (!pmodule && quadric) {
271  pmodule = quadric;
272  }
273 
274  if (!pmodule) {
275  // At least one priority module required
277  return false;
278  }
279 
280  // set pmodule as the current priority module
281  cmodule_ = pmodule;
282 
283  for (ModuleListIterator m_it = all_modules_.begin(), m_end =
284  all_modules_.end(); m_it != m_end; ++m_it) {
285  // every module gets initialized
286  (*m_it)->initialize();
287 
288  if (*m_it != pmodule) {
289  // all other modules are binary, and go into bmodules_ list
290  bmodules_.push_back(*m_it);
291  }
292  }
293 
294  return initialized_ = true;
295 }
296 
297 
298 
299 //=============================================================================
300 }// END_NS_DECIMATER
301 } // END_NS_OPENMESH
302 //=============================================================================
303 
Module * cmodule_
the current priority module
Mesh::HalfedgeHandle v0v1
Halfedge to be collapsed.
void preprocess_collapse(CollapseInfo &_ci)
Pre-process a collapse.
Mesh::VertexHandle vr
Right vertex.
virtual void set_error_tolerance_factor(double _factor)
Definition: ModBaseT.hh:268
bool is_collapse_legal(const CollapseInfo &_ci)
virtual void initialize()
Initialize module-internal stuff.
Definition: ModBaseT.hh:229
void postprocess_collapse(CollapseInfo &_ci)
Post-process a collapse.
Mesh::VertexHandle vl
Left vertex.
void info(std::ostream &_os)
Print information about modules to _os.
float collapse_priority(const CollapseInfo &_ci)
Calculate priority of an halfedge collapse (using the modules)
ModuleList bmodules_
list of binary modules
ModuleList all_modules_
list of all allocated modules (including cmodule_ and all of bmodules_)
virtual void preprocess_collapse(const CollapseInfoT< MeshT > &)
Definition: ModBaseT.hh:251
Mesh::VertexHandle v0
Vertex to be removed.
Mesh::VertexHandle v1
Remaining vertex.
void set_uninitialized()
Reset the initialized flag, and clear the bmodules_ and cmodule_.
virtual void postprocess_collapse(const CollapseInfoT< MeshT > &)
Definition: ModBaseT.hh:257
virtual const std::string & name() const
Set module&#39;s name.
Definition: ModBaseT.hh:216
virtual float collapse_priority(const CollapseInfoT< MeshT > &)
Definition: ModBaseT.hh:245
Mesh & mesh_
reference to mesh
bool initialized_
Flag if all modules were initialized.