Developer Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
mkbalancedpm.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 
49 // -------------------- STL
50 #include <iostream>
51 #include <sstream>
52 #include <cmath>
53 // -------------------- OpenMesh
54 #include <OpenMesh/Core/IO/MeshIO.hh>
55 #include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
56 #include <OpenMesh/Tools/Utils/getopt.h>
63 #include <OpenMesh/Tools/Decimater/ModIndependentSetsT.hh>
64 
66 typedef OpenMesh::Decimater::DecimaterT<Mesh> DecimaterProgMesh;
67 typedef OpenMesh::Decimater::ModNormalFlippingT<Mesh> ModNormalFlipping;
69 typedef OpenMesh::Decimater::ModProgMeshT<Mesh> ModProgMesh;
70 typedef OpenMesh::Decimater::ModIndependentSetsT<Mesh> ModIndependentSets;
71 
72 // ----------------------------------------------------------------------------
73 
74 using namespace OpenMesh::Decimater;
75 
76 template <class D>
78 {
79 public:
80 
81  typedef OpenMesh::Decimater::ModQuadricT<D> BaseModQ;
82 
83  DECIMATING_MODULE( ModBalancerT, D, Balancer );
84 
85 public:
86 
87  typedef size_t level_t;
88 
89 public:
90 
92  ModBalancerT( D &_dec )
93  : BaseModQ( _dec ),
94  max_level_(0), n_roots_(0), n_vertices_(0)
95  {
96  BaseModQ::mesh().add_property( level_ );
97  }
98 
99 
101  virtual ~ModBalancerT()
102  {
103  BaseModQ::mesh().remove_property( level_ );
104  }
105 
106 public:
107 
108  static level_t calc_bits_for_roots( size_t _n_vertices )
109  {
110  return level_t(std::ceil(std::log((double)_n_vertices)*inv_log2_));
111  }
112 
113 public: // inherited
114 
115  void initialize(void)
116  {
117  BaseModQ::initialize();
118  n_vertices_ = BaseModQ::mesh().n_vertices();
119  n_roots_ = calc_bits_for_roots(n_vertices_);
120  }
121 
122  virtual float collapse_priority(const CollapseInfo& _ci)
123  {
124  level_t newlevel = std::max( BaseModQ::mesh().property( level_, _ci.v0 ),
125  BaseModQ::mesh().property( level_, _ci.v1 ) )+1;
126  level_t newroots = calc_bits_for_roots(n_vertices_-1);
127 
128  if ( (newroots + newlevel) < 32 )
129  {
130  double err = BaseModQ::collapse_priority( _ci );
131 
132  if (err!=BaseModQ::ILLEGAL_COLLAPSE)
133  {
134  return float(newlevel + err/(err+1.0));
135  }
136 
137 
138  }
139  return BaseModQ::ILLEGAL_COLLAPSE;
140  }
141 
144  {
145  BaseModQ::postprocess_collapse( _ci );
146 
147  BaseModQ::mesh().property( level_, _ci.v1 ) =
148  std::max( BaseModQ::mesh().property( level_, _ci.v0 ),
149  BaseModQ::mesh().property( level_, _ci.v1 ) ) + 1;
150 
151  max_level_ = std::max( BaseModQ::mesh().property( level_, _ci.v1 ), max_level_ );
152  n_roots_ = calc_bits_for_roots(--n_vertices_);
153  }
154 
155 public:
156 
157  level_t max_level(void) const { return max_level_; }
158  level_t bits_for_roots(void) const { return n_roots_; }
159 
160 private:
161 
163  void set_binary(bool _b) {}
164 
166 
167  level_t max_level_; // maximum level reached
168  level_t n_roots_; // minimum bits for root nodes
169  size_t n_vertices_;// number of potential root nodes
170 
171  static const double inv_log2_;
172 
173 };
174 
175 template <typename D>
176 const double ModBalancerT<D>::inv_log2_ = 1.0/std::log(2.0);
177 
179 
180 
181 // ----------------------------------------------------------------------------
182 
183 inline
184 std::string&
185 replace_extension( std::string& _s, const std::string& _e )
186 {
187  std::string::size_type dot = _s.rfind(".");
188  if (dot == std::string::npos)
189  { _s += "." + _e; }
190  else
191  { _s = _s.substr(0,dot+1)+_e; }
192  return _s;
193 }
194 
195 inline
196 std::string
197 basename(const std::string& _f)
198 {
199  std::string::size_type dot = _f.rfind("/");
200  if (dot == std::string::npos)
201  return _f;
202  return _f.substr(dot+1, _f.length()-(dot+1));
203 }
204 
205 // ----------------------------------------------------------------------------
206 
207 void usage_and_exit(int xcode)
208 {
209  using namespace std;
210 
211  cout << endl
212  << "Usage: mkbalancedpm [-n <decimation-steps>] [-o <output>] [-N <max. normal deviation>]"
213  << "<input.ext>\n"
214  << endl
215  << " Create a balanced progressive mesh from an input file.\n"
216  << " By default decimate as much as possible and write the result\n"
217  << " to <input>.pm\n"
218  << endl
219  << "Options:\n"
220  << endl
221  << " -n <decimation-steps>\n"
222  << "\tDetermines the maximum number of decimation steps.\n"
223  << "\tDecimate as much as possible if the value is equal zero\n"
224  << "\tDefault value: 0\n"
225  << endl
226  << " -o <output>\n"
227  << "\tWrite resulting progressive mesh to the file named <output>\n"
228  << endl
229  << " -N <max. normal Deviation>\n"
230  << "\tEnable Normal Flipping\n"
231  << endl
232  << " -I\n"
233  << "\tEnable Independent Sets\n"
234  << endl;
235  exit(xcode);
236 }
237 
238 // ----------------------------------------------------------------------------
239 
240 int main(int argc, char **argv)
241 {
242  Mesh mesh;
243 
244  int c;
245  std::string ifname, ofname;
246  size_t decstep=0;
247  float normalDev=90.0;
248  bool enable_modNF = false;
249  bool enable_modIS = false;
250 
251  while ((c=getopt(argc, argv, "n:o:N:Ih"))!=-1)
252  {
253  switch (c)
254  {
255  case 'o': ofname = optarg; break;
256  case 'n': { std::stringstream str; str << optarg; str >> decstep; } break;
257  case 'N': { enable_modNF = true;
258  std::stringstream str; str << optarg; str >> normalDev; } break;
259  case 'I': enable_modIS = true; break;
260  case 'h':
261  usage_and_exit(0);
262  default:
263  usage_and_exit(1);
264  }
265  }
266 
267  if (optind >= argc)
268  usage_and_exit(1);
269 
270  ifname = argv[optind];
271 
272  if (!OpenMesh::IO::read_mesh(mesh, ifname))
273  {
274  std::cerr << "Error loading mesh from file '" << ifname << "'!\n";
275  return 1;
276  }
277 
278  {
280 
281  DecimaterProgMesh decimater(mesh);
282 
283  ModProgMesh::Handle modPM;
284  ModBalancer::Handle modB;
285  ModNormalFlipping::Handle modNF;
286  ModIndependentSets::Handle modIS;
287 
288 
289  decimater.add(modPM);
290  std::cout << "w/ progressive mesh module\n";
291  decimater.add(modB);
292  std::cout << "w/ balancer module\n";
293 
294  if ( enable_modNF )
295  {
296  decimater.add(modNF);
297  decimater.module(modNF).set_max_normal_deviation(normalDev);
298  }
299  std::cout << "w/" << (modNF.is_valid() ? ' ' : 'o')
300  << " normal flipping module (max. normal deviation: " << normalDev << ")\n";
301 
302  if ( enable_modIS )
303  decimater.add(modIS);
304  std::cout << "w/" << (modIS.is_valid() ? ' ' : 'o')
305  << " independent sets module\n";
306 
307  std::cout << "Initialize decimater\n";
308  t.start();
309  if ( !decimater.initialize() )
310  {
311  std::cerr << " Initialization failed!\n";
312  return 1;
313  }
314  t.stop();
315  std::cout << " done [" << t.as_string() << "]\n";
316  t.reset();
317 
318  size_t rc;
319  size_t nv = mesh.n_vertices();
320 
321  std::cout << "Begin decimation (#V " << nv << ")\n";
322  t.start();
323  do
324  {
325  if (modIS.is_valid())
326  {
327  Mesh::VertexIter v_it;
328  Mesh::FaceIter f_it;
329 
330  for (f_it = mesh.faces_begin(); f_it != mesh.faces_end(); ++f_it)
331  if ( !mesh.status(*f_it).deleted() )
332  mesh.update_normal(*f_it);
333 
334  for (v_it = mesh.vertices_begin(); v_it != mesh.vertices_end(); ++v_it)
335  if ( !mesh.status(*v_it).deleted() )
336  {
337  mesh.status(*v_it).set_locked(false);
338  mesh.update_normal(*v_it);
339  }
340 
341  }
342 
343  rc = decimater.decimate(decstep);
344  t.stop();
345  std::cout << '\r'
346  << (nv-=rc) << " (-" << rc << ") " << std::flush;
347  t.cont();
348  } while (rc > 0);
349  t.stop();
350 
351  std::cout << "\n done [" << t.as_string() << "]\n";
352 
353  std::cout << "Bits for <tree-id, node-id>: <"
354  << decimater.module(modB).bits_for_roots() << ", "
355  << decimater.module(modB).max_level() << ">"
356  << std::endl;
357 
358  std::cout << "Maximum level reached: "
359  << decimater.module(modB).max_level() << std::endl;
360 
361  if (ofname == "." || ofname == ".." )
362  ofname += "/" + basename(ifname);
363  std::string pmfname = ofname.empty() ? ifname : ofname;
364  replace_extension(pmfname, "pm");
365 
366  std::cout << "Write progressive mesh data to file "
367  << pmfname << std::endl;
368  decimater.module(modPM).write( pmfname );
369  }
370 
371 
372  return 0;
373 }
Mesh::VertexHandle v1
Remaining vertex.
bool read_mesh(Mesh &_mesh, const std::string &_filename)
Read a mesh from file _filename.
Definition: MeshIO.hh:104
#define DECIMATING_MODULE(Classname, MeshT, Name)
Definition: ModBaseT.hh:154
void stop(void)
Stop measurement.
Mesh::VertexHandle v0
Vertex to be removed.
void update_normal(FaceHandle _fh)
Update normal for face _fh.
Definition: PolyMeshT.hh:259
Mesh decimation module computing collapse priority based on error quadrics.
Definition: ModQuadricT.hh:83
void initialize(void)
Initalize the module and prepare the mesh for decimation.
virtual float collapse_priority(const CollapseInfo &_ci)
std::string as_string(Format format=Automatic)
virtual ~ModBalancerT()
Destructor.
void reset(void)
Reset the timer.
void set_binary(bool _b)
hide this method
ModBalancerT(D &_dec)
Constructor.
Definition: mkbalancedpm.cc:92
void start(void)
Start measurement.
osg::Vec3f::ValueType dot(const osg::Vec3f &_v1, const osg::Vec3f &_v2)
Adapter for osg vector member computing a scalar product.
void postprocess_collapse(const CollapseInfo &_ci)
post-process halfedge collapse (accumulate quadrics)
STL namespace.
void cont(void)
Continue measurement.