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";
std::string as_string(Format format=Automatic)
void start(void)
Start measurement.
double seconds(void) const
Returns measured time in seconds, if the timer is in state 'Stopped'.
Has (r) / store (w) face normals.
void update_face_normals()
Update normal vectors for all faces.
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.
Use Roundness of triangles to control decimation.
bool read_mesh(Mesh &_mesh, const std::string &_filename)
Read a mesh from file _filename.
Use edge length to control decimation.
Use aspect ratio to control decimation.
Set options for reader/writer modules.
void stop(void)
Stop measurement.
Use Normal deviation to control decimation.
Mesh decimation module computing collapse priority based on error quadrics.