Developer Documentation

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

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>
57 #include <OpenMesh/Tools/Utils/Timer.hh>
58 #include <OpenMesh/Tools/Decimater/DecimaterT.hh>
59 #include <OpenMesh/Tools/Decimater/ModBaseT.hh>
60 #include <OpenMesh/Tools/Decimater/ModQuadricT.hh>
61 #include <OpenMesh/Tools/Decimater/ModNormalFlippingT.hh>
62 #include <OpenMesh/Tools/Decimater/ModProgMeshT.hh>
63 #include <OpenMesh/Tools/Decimater/ModIndependentSetsT.hh>
64
65 typedef OpenMesh::TriMesh_ArrayKernelT<> Mesh;
66 typedef OpenMesh::Decimater::DecimaterT<Mesh> DecimaterProgMesh;
67 typedef OpenMesh::Decimater::ModNormalFlippingT<Mesh> ModNormalFlipping;
68 typedef OpenMesh::Decimater::ModQuadricT<Mesh> ModQuadric;
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>
77 class ModBalancerT : public OpenMesh::Decimater::ModQuadricT<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
143 void postprocess_collapse(const CollapseInfo& _ci)
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
165 OpenMesh::VPropHandleT<level_t> level_;
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
178 typedef ModBalancerT<Mesh> ModBalancer;
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 {
279 OpenMesh::Utils::Timer t;
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 }
OpenMesh::Decimater::CollapseInfoT::v1
Mesh::VertexHandle v1
Remaining vertex.
Definition: CollapseInfoT.hh:98
OpenMesh::IO::read_mesh
bool read_mesh(Mesh &_mesh, const std::string &_filename)
Read a mesh from file _filename.
Definition: MeshIO.hh:104
DECIMATING_MODULE
#define DECIMATING_MODULE(Classname, MeshT, Name)
Definition: ModBaseT.hh:154
OpenMesh::Decimater
OpenMesh::Utils::Timer::stop
void stop(void)
Stop measurement.
DecimaterT.hh
OpenMesh::Decimater::CollapseInfoT::v0
Mesh::VertexHandle v0
Vertex to be removed.
Definition: CollapseInfoT.hh:97
OpenMesh::PolyMeshT::update_normal
void update_normal(FaceHandle _fh)
Update normal for face _fh.
Definition: PolyMeshT.hh:259
OpenMesh::Decimater::ModQuadricT
Mesh decimation module computing collapse priority based on error quadrics.
Definition: ModQuadricT.hh:83
OpenMesh::Decimater::DecimaterT
Definition: DecimaterT.hh:83
OpenMesh::TriMesh_ArrayKernelT
Definition: TriMesh_ArrayKernelT.hh:98
ModProgMeshT.hh
ModBalancerT::initialize
void initialize(void)
Initalize the module and prepare the mesh for decimation.
Definition: mkbalancedpm.cc:115
ModBalancerT::collapse_priority
virtual float collapse_priority(const CollapseInfo &_ci)
Definition: mkbalancedpm.cc:122
OpenMesh::Utils::Timer::as_string
std::string as_string(Format format=Automatic)
ModBalancerT::~ModBalancerT
virtual ~ModBalancerT()
Destructor.
Definition: mkbalancedpm.cc:101
OpenMesh::VPropHandleT< level_t >
Timer.hh
OpenMesh::Decimater::CollapseInfoT
Definition: CollapseInfoT.hh:80
ModBaseT.hh
OpenMesh::Utils::Timer::reset
void reset(void)
Reset the timer.
ModBalancerT::set_binary
void set_binary(bool _b)
hide this method
Definition: mkbalancedpm.cc:163
ModBalancerT::ModBalancerT
ModBalancerT(D &_dec)
Constructor.
Definition: mkbalancedpm.cc:92
OpenMesh::Decimater::ModProgMeshT
Definition: ModProgMeshT.hh:85
OpenMesh::Utils::Timer::start
void start(void)
Start measurement.
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:181
ModBalancerT::postprocess_collapse
void postprocess_collapse(const CollapseInfo &_ci)
post-process halfedge collapse (accumulate quadrics)
Definition: mkbalancedpm.cc:143
ModBalancerT
Definition: mkbalancedpm.cc:77
ModQuadricT.hh
std
STL namespace.
OpenMesh::Utils::Timer::cont
void cont(void)
Continue measurement.
OpenMesh::Decimater::ModNormalFlippingT
Definition: ModNormalFlippingT.hh:85
OpenMesh::Decimater::ModIndependentSetsT
Definition: ModIndependentSetsT.hh:76
OpenMesh::Utils::Timer
Definition: Timer.hh:87
ModNormalFlippingT.hh