49 #if !defined(OM_USE_OSG)
62 #include <OpenMesh/Core/IO/MeshIO.hh>
65 # include <OpenMesh/Tools/Kernel_OSG/TriMesh_OSGArrayKernelT.hh>
67 # include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
69 #include <OpenMesh/Core/Utils/vector_cast.hh>
71 #include <OpenMesh/Tools/Utils/getopt.h>
81 #include <OpenMesh/Tools/Decimater/ModIndependentSetsT.hh>
114 void usage_and_exit(
int xcode);
119 #include "CmdOption.hh"
141 template <
typename T>
148 std::istringstream istr( _val );
152 if ( (istr >> v).fail() )
161 bool parse_argument(
const std::string& arg )
163 std::string::size_type pos = arg.find(
':');
168 if (pos == std::string::npos)
172 name = arg.substr(0, pos);
173 value = arg.substr(pos+1, arg.size());
178 if (name ==
"AR")
return init(AR, value);
179 if (name ==
"EL")
return init(EL, value);
180 if (name ==
"HD")
return init(HD, value);
181 if (name ==
"IS")
return init(IS, value);
182 if (name ==
"ND")
return init(ND, value);
183 if (name ==
"NF")
return init(NF, value);
184 if (name ==
"PM")
return init(PM, value);
185 if (name ==
"Q")
return init(Q, value);
186 if (name ==
"R")
return init(R, value);
190 std::string& strip(std::string & line)
192 std::string::size_type pos = 0;
194 pos = line.find_last_not_of(
" \t");
196 if ( pos!=0 && pos!=std::string::npos )
199 line.erase( pos, line.length()-pos );
202 pos = line.find_first_not_of(
" \t");
203 if ( pos!=0 && pos!=std::string::npos )
215 template <
typename Mesh,
typename DecimaterType>
217 decimate(
const std::string &_ifname,
218 const std::string &_ofname,
230 clog <<
"source mesh: ";
234 clog << _ifname << endl;
237 cerr <<
" ERROR: read failed!" << endl;
248 if ( !mesh.has_face_normals() )
249 mesh.request_face_normals();
252 clog <<
" updating face normals" << endl;
257 DecimaterType decimater( mesh );
261 clog <<
" register modules" << endl;
267 if (_opt.AR.is_enabled())
269 decimater.add(modAR);
270 if (_opt.AR.has_value())
271 decimater.module( modAR ).set_aspect_ratio( _opt.AR ) ;
276 if (_opt.EL.is_enabled())
278 decimater.add(modEL);
279 if (_opt.EL.has_value())
280 decimater.module( modEL ).set_edge_length( _opt.EL ) ;
281 decimater.module(modEL).set_binary(
false);
284 typename OpenMesh::Decimater::ModHausdorffT <Mesh>::Handle modHD;
286 if (_opt.HD.is_enabled())
288 decimater.add(modHD);
289 if (_opt.HD.has_value())
290 decimater.module( modHD ).set_tolerance( _opt.HD ) ;
296 if ( _opt.IS.is_enabled() )
297 decimater.add(modIS);
301 if (_opt.ND.is_enabled())
303 decimater.add(modND);
304 if (_opt.ND.has_value())
305 decimater.module( modND ).set_normal_deviation( _opt.ND );
306 decimater.module( modND ).set_binary(
false);
311 if (_opt.NF.is_enabled())
313 decimater.add(modNF);
314 if (_opt.NF.has_value())
315 decimater.module( modNF ).set_max_normal_deviation( _opt.NF );
321 if ( _opt.PM.is_enabled() )
322 decimater.add(modPM);
326 if (_opt.Q.is_enabled())
329 if (_opt.Q.has_value())
330 decimater.module( modQ ).set_max_err( _opt.Q );
331 decimater.module(modQ).set_binary(
false);
336 if ( _opt.R.is_enabled() )
338 decimater.add( modR );
339 if ( _opt.R.has_value() )
340 decimater.module( modR ).set_min_angle( _opt.R,
342 !decimater.module(modQ).is_binary());
348 clog <<
"initializing mesh" << endl;
353 rc = decimater.initialize();
357 std::cerr <<
" initializing failed!" << std::endl;
358 std::cerr <<
" maybe no priority module or more than one were defined!" << std::endl;
363 std::clog <<
" Elapsed time: " << timer.
as_string() << std::endl;
366 decimater.info( clog );
372 std::clog <<
"decimating" << std::endl;
373 std::clog <<
" # vertices: " << mesh.n_vertices() << std::endl;
376 float nv_before = float(mesh.n_vertices());
380 if (_opt.n_collapses < 0.0)
381 rc = decimater.decimate_to(
size_t(-_opt.n_collapses) );
382 else if (_opt.n_collapses >= 1.0 || _opt.n_collapses == 0.0)
383 rc = decimater.decimate(
size_t(_opt.n_collapses) );
384 else if (_opt.n_collapses > 0.0f)
385 rc = decimater.decimate_to(
size_t(mesh.n_vertices()*_opt.n_collapses));
390 if ( _opt.PM.has_value() )
391 decimater.module(modPM).write( _opt.PM );
395 mesh.garbage_collection();
399 std::clog <<
" # executed collapses: " << rc << std::endl;
400 std::clog <<
" # vertices: " << mesh.n_vertices() <<
", "
401 << ( 100.0*mesh.n_vertices()/nv_before ) <<
"%\n";
402 std::clog <<
" Elapsed time: " << timer.
as_string() << std::endl;
403 std::clog <<
" collapses/s : " << rc/timer.
seconds() << std::endl;
409 if ( ! _ofname.empty() )
411 std::string ofname(_ofname);
413 std::string::size_type pos = ofname.rfind(
'.');
414 if (pos == std::string::npos)
417 pos = ofname.rfind(
'.');
420 if ( _opt.decorate_name.is_enabled() )
422 std::stringstream s; s << mesh.n_vertices();
423 std::string n; s >> n;
424 ofname.insert( pos,
"-");
425 ofname.insert(++pos, n );
434 std::cerr <<
" Cannot write decimated mesh to file '"
438 std::clog <<
" Exported decimated mesh to file '" << ofname <<
"'\n";
446 int main(
int argc,
char* argv[])
448 std::string ifname, ofname;
454 osg::osgInit( argc, argv );
461 while ( (c=getopt( argc, argv,
"dDhi:M:n:o:v")) != -1 )
465 case 'D': opt.decorate_name =
true;
break;
466 case 'd': gdebug =
true;
break;
467 case 'h': usage_and_exit(0);
468 case 'i': ifname = optarg;
break;
469 case 'M': opt.parse_argument( optarg );
break;
470 case 'n': opt.n_collapses = float(atof(optarg));
break;
471 case 'o': ofname = optarg;
break;
472 case 'v': gverbose =
true;
break;
475 std::cerr <<
"FATAL: cannot process command line option!"
484 if ( (-1.0f < opt.n_collapses) && (opt.n_collapses < 0.0f) )
486 std::cerr <<
"Error: Option -n: invalid value argument!" << std::endl;
494 std::clog <<
" Input file: " << ifname << std::endl;
495 std::clog <<
" Output file: " << ofname << std::endl;
496 std::clog <<
" #collapses: " << opt.n_collapses << std::endl;
506 std::clog <<
"Begin decimation" << std::endl;
509 bool rc = decimate<ArrayTriMesh, Decimater>( ifname, ofname, opt );
514 std::clog <<
"Decimation failed!" << std::endl;
516 std::clog <<
"Decimation done." << std::endl;
526 void usage_and_exit(
int xcode)
532 case 1: errmsg =
"Option not supported!";
break;
533 case 2: errmsg =
"Invalid output file format!";
break;
536 std::cerr << std::endl;
538 std::cerr <<
"Error " << xcode <<
": " << errmsg << std::endl << std::endl;
540 std::cerr <<
"Usage: decimator [Options] -i input-file -o output-file\n"
541 <<
" Decimating a mesh using quadrics and normal flipping.\n" << std::endl;
542 std::cerr <<
"Options\n" << std::endl;
543 std::cerr <<
" -M \"{Module-Name}[:Value]}\"\n"
544 <<
" Use named module with eventually given parameterization\n"
545 <<
" Several modules can also be used in order to introduce further constraints\n"
546 <<
" Note that -M has to be given before each new module \n"
547 <<
" An example with ModQuadric as a priority module\n"
548 <<
" and ModRoundness as a binary module could look like this:\n"
549 <<
" commandlineDecimater -M Q -M R:40.0 -n 0.1 -i inputfile.obj -o outputfile.obj\n" << std::endl;
550 std::cerr <<
" -n <N>\n"
551 <<
" N >= 1: do N halfedge collapses.\n"
552 <<
" N <=-1: decimate down to |N| vertices.\n"
553 <<
" 0 < N < 1: decimate down to N%.\n" << std::endl;
554 std::cerr << std::endl;
555 std::cerr <<
"Modules:\n\n";
556 std::cerr <<
" AR[:ratio] - ModAspectRatio\n";
557 std::cerr <<
" EL[:legth] - ModEdgeLength*\n";
558 std::cerr <<
" HD[:distance] - ModHausdorff\n";
559 std::cerr <<
" IS - ModIndependentSets\n";
560 std::cerr <<
" ND[:angle] - ModNormalDeviation*\n";
561 std::cerr <<
" NF[:angle] - ModNormalFlipping\n";
562 std::cerr <<
" PM[:file name] - ModProgMesh\n";
563 std::cerr <<
" Q[:error] - ModQuadric*\n";
564 std::cerr <<
" R[:angle] - ModRoundness\n";
565 std::cerr <<
" 0 < angle < 60\n";
566 std::cerr <<
" *: priority module. Decimater needs one of them (not more).\n";
bool read_mesh(Mesh &_mesh, const std::string &_filename)
Read a mesh from file _filename.
Use Roundness of triangles to control decimation.
void stop(void)
Stop measurement.
Use aspect ratio to control decimation.
Use edge length to control decimation.
Has (r) / store (w) face normals.
Mesh decimation module computing collapse priority based on error quadrics.
Set options for reader/writer modules.
std::string as_string(Format format=Automatic)
void update_face_normals()
Update normal vectors for all faces.
void start(void)
Start measurement.
Use Normal deviation to control decimation.
double seconds(void) const
Returns measured time in seconds, if the timer is in state 'Stopped'.
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.