49#include <OpenMesh/Core/IO/MeshIO.hh>
50#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
51#include <OpenMesh/Tools/Utils/getopt.h>
58#include <OpenMesh/Tools/Decimater/ModIndependentSetsT.hh>
82 typedef size_t level_t;
89 max_level_(0), n_roots_(0), n_vertices_(0)
91 BaseModQ::mesh().add_property( level_ );
98 BaseModQ::mesh().remove_property( level_ );
103 static level_t calc_bits_for_roots(
size_t _n_vertices )
105 return level_t(std::ceil(std::log((
double)_n_vertices)*inv_log2_));
112 BaseModQ::initialize();
113 n_vertices_ = BaseModQ::mesh().n_vertices();
114 n_roots_ = calc_bits_for_roots(n_vertices_);
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);
123 if ( (newroots + newlevel) < 32 )
125 double err = BaseModQ::collapse_priority( _ci );
127 if (err!=BaseModQ::ILLEGAL_COLLAPSE)
129 return float(newlevel + err/(err+1.0));
134 return BaseModQ::ILLEGAL_COLLAPSE;
140 BaseModQ::postprocess_collapse( _ci );
142 BaseModQ::mesh().property( level_, _ci.
v1 ) =
143 std::max( BaseModQ::mesh().property( level_, _ci.
v0 ),
144 BaseModQ::mesh().property( level_, _ci.
v1 ) ) + 1;
146 max_level_ = std::max( BaseModQ::mesh().property( level_, _ci.
v1 ), max_level_ );
147 n_roots_ = calc_bits_for_roots(--n_vertices_);
152 level_t max_level(
void)
const {
return max_level_; }
153 level_t bits_for_roots(
void)
const {
return n_roots_; }
163 static const double inv_log2_;
177replace_extension( std::string& _s,
const std::string& _e )
179 std::string::size_type dot = _s.rfind(
".");
180 if (dot == std::string::npos)
188 const std::string name = _s.substr(0,dot+1);
198basename(
const std::string& _f)
200 std::string::size_type dot = _f.rfind(
"/");
201 if (dot == std::string::npos)
203 return _f.substr(dot+1, _f.length()-(dot+1));
208void usage_and_exit(
int xcode)
213 <<
"Usage: mkbalancedpm [-n <decimation-steps>] [-o <output>] [-N <max. normal deviation>]"
216 <<
" Create a balanced progressive mesh from an input file.\n"
217 <<
" By default decimate as much as possible and write the result\n"
218 <<
" to <input>.pm\n"
222 <<
" -n <decimation-steps>\n"
223 <<
"\tDetermines the maximum number of decimation steps.\n"
224 <<
"\tDecimate as much as possible if the value is equal zero\n"
225 <<
"\tDefault value: 0\n"
228 <<
"\tWrite resulting progressive mesh to the file named <output>\n"
230 <<
" -N <max. normal Deviation>\n"
231 <<
"\tEnable Normal Flipping\n"
234 <<
"\tEnable Independent Sets\n"
241int main(
int argc,
char **argv)
246 std::string ifname, ofname;
248 float normalDev=90.0;
249 bool enable_modNF =
false;
250 bool enable_modIS =
false;
252 while ((c=getopt(argc, argv,
"n:o:N:Ih"))!=-1)
256 case 'o': ofname = optarg;
break;
257 case 'n': { std::stringstream str; str << optarg; str >> decstep; }
break;
258 case 'N': { enable_modNF =
true;
259 std::stringstream str; str << optarg; str >> normalDev; }
break;
260 case 'I': enable_modIS =
true;
break;
272 ifname = argv[optind];
276 std::cerr <<
"Error loading mesh from file '" << ifname <<
"'!\n";
283 DecimaterProgMesh decimater(mesh);
285 ModProgMesh::Handle modPM;
286 ModBalancer::Handle modB;
287 ModNormalFlipping::Handle modNF;
288 ModIndependentSets::Handle modIS;
291 decimater.add(modPM);
292 std::cout <<
"w/ progressive mesh module\n";
294 std::cout <<
"w/ balancer module\n";
298 decimater.add(modNF);
299 decimater.module(modNF).set_max_normal_deviation(normalDev);
301 std::cout <<
"w/" << (modNF.is_valid() ?
' ' :
'o')
302 <<
" normal flipping module (max. normal deviation: " << normalDev <<
")\n";
305 decimater.add(modIS);
306 std::cout <<
"w/" << (modIS.is_valid() ?
' ' :
'o')
307 <<
" independent sets module\n";
309 std::cout <<
"Initialize decimater\n";
311 if ( !decimater.initialize() )
313 std::cerr <<
" Initialization failed!\n";
317 std::cout <<
" done [" << t.
as_string() <<
"]\n";
321 size_t nv = mesh.n_vertices();
323 std::cout <<
"Begin decimation (#V " << nv <<
")\n";
327 if (modIS.is_valid())
332 for (f_it = mesh.faces_begin(); f_it != mesh.faces_end(); ++f_it)
333 if ( !mesh.status(*f_it).deleted() )
336 for (v_it = mesh.vertices_begin(); v_it != mesh.vertices_end(); ++v_it)
337 if ( !mesh.status(*v_it).deleted() )
339 mesh.status(*v_it).set_locked(
false);
345 rc = decimater.decimate(decstep);
348 << (nv-=rc) <<
" (-" << rc <<
") " << std::flush;
353 std::cout <<
"\n done [" << t.
as_string() <<
"]\n";
355 std::cout <<
"Bits for <tree-id, node-id>: <"
356 << decimater.module(modB).bits_for_roots() <<
", "
357 << decimater.module(modB).max_level() <<
">"
360 std::cout <<
"Maximum level reached: "
361 << decimater.module(modB).max_level() << std::endl;
363 if (ofname ==
"." || ofname ==
".." )
364 ofname +=
"/" + basename(ifname);
365 std::string pmfname = ofname.empty() ? ifname : ofname;
366 replace_extension(pmfname,
"pm");
368 std::cout <<
"Write progressive mesh data to file "
369 << pmfname << std::endl;
370 decimater.module(modPM).write( pmfname );
#define DECIMATING_MODULE(Classname, MeshT, Name)
virtual ~ModBalancerT()
Destructor.
ModBalancerT(D &_dec)
Constructor.
void postprocess_collapse(const CollapseInfo &_ci) override
post-process halfedge collapse (accumulate quadrics)
void initialize(void) override
Initalize the module and prepare the mesh for decimation.
virtual float collapse_priority(const CollapseInfo &_ci) override
Mesh decimation module computing collapse priority based on error quadrics.
Kernel::FaceIter FaceIter
Scalar type.
void update_normal(FaceHandle _fh)
Update normal for face _fh.
Kernel::VertexIter VertexIter
Scalar type.
void reset(void)
Reset the timer.
void cont(void)
Continue measurement.
void stop(void)
Stop measurement.
std::string as_string(Format format=Automatic)
void start(void)
Start measurement.
bool read_mesh(Mesh &_mesh, const std::string &_filename)
Read a mesh from file _filename.
Mesh::VertexHandle v1
Remaining vertex.
Mesh::VertexHandle v0
Vertex to be removed.