Developer Documentation

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