44#if !defined(OM_USE_OSG)
57#include <OpenMesh/Core/IO/MeshIO.hh>
60# include <OpenMesh/Tools/Kernel_OSG/TriMesh_OSGArrayKernelT.hh>
62# include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
64#include <OpenMesh/Core/Utils/vector_cast.hh>
66#include <OpenMesh/Tools/Utils/getopt.h>
76#include <OpenMesh/Tools/Decimater/ModIndependentSetsT.hh>
109void usage_and_exit(
int xcode);
114#include "CmdOption.hh"
136 template <
typename T>
143 std::istringstream istr( _val );
147 if ( (istr >> v).fail() )
156 bool parse_argument(
const std::string& arg )
158 std::string::size_type pos = arg.find(
':');
163 if (pos == std::string::npos)
167 name = arg.substr(0, pos);
168 value = arg.substr(pos+1, arg.size());
173 if (name ==
"AR")
return init(AR, value);
174 if (name ==
"EL")
return init(EL, value);
175 if (name ==
"HD")
return init(HD, value);
176 if (name ==
"IS")
return init(IS, value);
177 if (name ==
"ND")
return init(ND, value);
178 if (name ==
"NF")
return init(NF, value);
179 if (name ==
"PM")
return init(PM, value);
180 if (name ==
"Q")
return init(Q, value);
181 if (name ==
"R")
return init(R, value);
185 std::string& strip(std::string & line)
187 std::string::size_type pos = 0;
189 pos = line.find_last_not_of(
" \t");
191 if ( pos!=0 && pos!=std::string::npos )
194 line.erase( pos, line.length()-pos );
197 pos = line.find_first_not_of(
" \t");
198 if ( pos!=0 && pos!=std::string::npos )
210template <
typename Mesh,
typename DecimaterType>
212decimate(
const std::string &_ifname,
213 const std::string &_ofname,
225 clog <<
"source mesh: ";
229 clog << _ifname << endl;
232 cerr <<
" ERROR: read failed!" << endl;
243 if ( !mesh.has_face_normals() )
244 mesh.request_face_normals();
247 clog <<
" updating face normals" << endl;
252 DecimaterType decimater( mesh );
256 clog <<
" register modules" << endl;
262 if (_opt.AR.is_enabled())
264 decimater.add(modAR);
265 if (_opt.AR.has_value())
266 decimater.module( modAR ).set_aspect_ratio( _opt.AR ) ;
271 if (_opt.EL.is_enabled())
273 decimater.add(modEL);
274 if (_opt.EL.has_value())
275 decimater.module( modEL ).set_edge_length( _opt.EL ) ;
276 decimater.module(modEL).set_binary(
false);
279 typename OpenMesh::Decimater::ModHausdorffT <Mesh>::Handle modHD;
281 if (_opt.HD.is_enabled())
283 decimater.add(modHD);
284 if (_opt.HD.has_value())
285 decimater.module( modHD ).set_tolerance( _opt.HD ) ;
291 if ( _opt.IS.is_enabled() )
292 decimater.add(modIS);
296 if (_opt.ND.is_enabled())
298 decimater.add(modND);
299 if (_opt.ND.has_value())
300 decimater.module( modND ).set_normal_deviation( _opt.ND );
301 decimater.module( modND ).set_binary(
false);
306 if (_opt.NF.is_enabled())
308 decimater.add(modNF);
309 if (_opt.NF.has_value())
310 decimater.module( modNF ).set_max_normal_deviation( _opt.NF );
316 if ( _opt.PM.is_enabled() )
317 decimater.add(modPM);
321 if (_opt.Q.is_enabled())
324 if (_opt.Q.has_value())
325 decimater.module( modQ ).set_max_err( _opt.Q );
326 decimater.module(modQ).set_binary(
false);
331 if ( _opt.R.is_enabled() )
333 decimater.add( modR );
334 if ( _opt.R.has_value() )
335 decimater.module( modR ).set_min_angle( _opt.R,
337 !decimater.module(modQ).is_binary());
343 clog <<
"initializing mesh" << endl;
348 rc = decimater.initialize();
352 std::cerr <<
" initializing failed!" << std::endl;
353 std::cerr <<
" maybe no priority module or more than one were defined!" << std::endl;
358 std::clog <<
" Elapsed time: " << timer.
as_string() << std::endl;
361 decimater.info( clog );
367 std::clog <<
"decimating" << std::endl;
368 std::clog <<
" # vertices: " << mesh.n_vertices() << std::endl;
371 float nv_before = float(mesh.n_vertices());
375 if (_opt.n_collapses < 0.0)
376 rc = decimater.decimate_to(
size_t(-_opt.n_collapses) );
377 else if (_opt.n_collapses >= 1.0 || _opt.n_collapses == 0.0)
378 rc = decimater.decimate(
size_t(_opt.n_collapses) );
379 else if (_opt.n_collapses > 0.0f)
380 rc = decimater.decimate_to(
size_t(mesh.n_vertices()*_opt.n_collapses));
385 if ( _opt.PM.has_value() )
386 decimater.module(modPM).write( _opt.PM );
390 mesh.garbage_collection();
394 std::clog <<
" # executed collapses: " << rc << std::endl;
395 std::clog <<
" # vertices: " << mesh.n_vertices() <<
", "
396 << ( 100.0*mesh.n_vertices()/nv_before ) <<
"%\n";
397 std::clog <<
" Elapsed time: " << timer.
as_string() << std::endl;
398 std::clog <<
" collapses/s : " << rc/timer.
seconds() << std::endl;
404 if ( ! _ofname.empty() )
406 std::string ofname(_ofname);
408 std::string::size_type pos = ofname.rfind(
'.');
409 if (pos == std::string::npos)
412 pos = ofname.rfind(
'.');
415 if ( _opt.decorate_name.is_enabled() )
417 std::stringstream s; s << mesh.n_vertices();
418 std::string n; s >> n;
419 ofname.insert( pos,
"-");
420 ofname.insert(++pos, n );
429 std::cerr <<
" Cannot write decimated mesh to file '"
433 std::clog <<
" Exported decimated mesh to file '" << ofname <<
"'\n";
441int main(
int argc,
char* argv[])
443 std::string ifname, ofname;
449 osg::osgInit( argc, argv );
456 while ( (c=getopt( argc, argv,
"dDhi:M:n:o:v")) != -1 )
460 case 'D': opt.decorate_name =
true;
break;
461 case 'd': gdebug =
true;
break;
462 case 'h': usage_and_exit(0);
break;
463 case 'i': ifname = optarg;
break;
464 case 'M': opt.parse_argument( optarg );
break;
465 case 'n': opt.n_collapses = float(atof(optarg));
break;
466 case 'o': ofname = optarg;
break;
467 case 'v': gverbose =
true;
break;
470 std::cerr <<
"FATAL: cannot process command line option!"
479 if ( (-1.0f < opt.n_collapses) && (opt.n_collapses < 0.0f) )
481 std::cerr <<
"Error: Option -n: invalid value argument!" << std::endl;
489 std::clog <<
" Input file: " << ifname << std::endl;
490 std::clog <<
" Output file: " << ofname << std::endl;
491 std::clog <<
" #collapses: " << opt.n_collapses << std::endl;
497 std::clog <<
"Begin decimation" << std::endl;
500 bool rc = decimate<ArrayTriMesh, Decimater>( ifname, ofname, opt );
505 std::clog <<
"Decimation failed!" << std::endl;
507 std::clog <<
"Decimation done." << std::endl;
518void usage_and_exit(
int xcode)
524 case 1: errmsg =
"Option not supported!";
break;
525 case 2: errmsg =
"Invalid output file format!";
break;
528 std::cerr << std::endl;
530 std::cerr <<
"Error " << xcode <<
": " << errmsg << std::endl << std::endl;
532 std::cerr <<
"Usage: decimator [Options] -i input-file -o output-file\n"
533 <<
" Decimating a mesh using quadrics and normal flipping.\n" << std::endl;
534 std::cerr <<
"Options\n" << std::endl;
535 std::cerr <<
" -M \"{Module-Name}[:Value]}\"\n"
536 <<
" Use named module with eventually given parameterization\n"
537 <<
" Several modules can also be used in order to introduce further constraints\n"
538 <<
" Note that -M has to be given before each new module \n"
539 <<
" An example with ModQuadric as a priority module\n"
540 <<
" and ModRoundness as a binary module could look like this:\n"
541 <<
" commandlineDecimater -M Q -M R:40.0 -n 0.1 -i inputfile.obj -o outputfile.obj\n" << std::endl;
542 std::cerr <<
" -n <N>\n"
543 <<
" N >= 1: do N halfedge collapses.\n"
544 <<
" N <=-1: decimate down to |N| vertices.\n"
545 <<
" 0 < N < 1: decimate down to N%.\n" << std::endl;
546 std::cerr << std::endl;
547 std::cerr <<
"Modules:\n\n";
548 std::cerr <<
" AR[:ratio] - ModAspectRatio\n";
549 std::cerr <<
" EL[:legth] - ModEdgeLength*\n";
550 std::cerr <<
" HD[:distance] - ModHausdorff\n";
551 std::cerr <<
" IS - ModIndependentSets\n";
552 std::cerr <<
" ND[:angle] - ModNormalDeviation*\n";
553 std::cerr <<
" NF[:angle] - ModNormalFlipping\n";
554 std::cerr <<
" PM[:file name] - ModProgMesh\n";
555 std::cerr <<
" Q[:error] - ModQuadric*\n";
556 std::cerr <<
" R[:angle] - ModRoundness\n";
557 std::cerr <<
" 0 < angle < 60\n";
558 std::cerr <<
" *: priority module. Decimater needs one of them (not more).\n";
Use aspect ratio to control decimation.
Use edge length to control decimation.
Use Normal deviation to control decimation.
Mesh decimation module computing collapse priority based on error quadrics.
Use Roundness of triangles to control decimation.
Set options for reader/writer modules.
@ FaceNormal
Has (r) / store (w) face normals.
void update_face_normals()
Update normal vectors for all faces.
void stop(void)
Stop measurement.
double seconds(void) const
Returns measured time in seconds, if the timer is in state 'Stopped'.
std::string as_string(Format format=Automatic)
void start(void)
Start measurement.
bool write_mesh(const Mesh &_mesh, const std::string &_filename, Options _opt=Options::Default, std::streamsize _precision=6)
Write a mesh to the file _filename.
bool read_mesh(Mesh &_mesh, const std::string &_filename)
Read a mesh from file _filename.