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> 109 void 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 )
210 template <
typename Mesh,
typename DecimaterType>
212 decimate(
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())
271 if (_opt.EL.is_enabled())
273 decimater.add(modEL);
274 if (_opt.EL.has_value())
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())
301 decimater.module( modND ).set_binary(
false);
306 if (_opt.NF.is_enabled())
308 decimater.add(modNF);
309 if (_opt.NF.has_value())
316 if ( _opt.PM.is_enabled() )
317 decimater.add(modPM);
321 if (_opt.Q.is_enabled())
324 if (_opt.Q.has_value())
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,
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";
441 int 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;
501 std::clog <<
"Begin decimation" << std::endl;
504 bool rc = decimate<ArrayTriMesh, Decimater>( ifname, ofname, opt );
509 std::clog <<
"Decimation failed!" << std::endl;
511 std::clog <<
"Decimation done." << std::endl;
521 void usage_and_exit(
int xcode)
527 case 1: errmsg =
"Option not supported!";
break;
528 case 2: errmsg =
"Invalid output file format!";
break;
531 std::cerr << std::endl;
533 std::cerr <<
"Error " << xcode <<
": " << errmsg << std::endl << std::endl;
535 std::cerr <<
"Usage: decimator [Options] -i input-file -o output-file\n" 536 <<
" Decimating a mesh using quadrics and normal flipping.\n" << std::endl;
537 std::cerr <<
"Options\n" << std::endl;
538 std::cerr <<
" -M \"{Module-Name}[:Value]}\"\n" 539 <<
" Use named module with eventually given parameterization\n" 540 <<
" Several modules can also be used in order to introduce further constraints\n" 541 <<
" Note that -M has to be given before each new module \n" 542 <<
" An example with ModQuadric as a priority module\n" 543 <<
" and ModRoundness as a binary module could look like this:\n" 544 <<
" commandlineDecimater -M Q -M R:40.0 -n 0.1 -i inputfile.obj -o outputfile.obj\n" << std::endl;
545 std::cerr <<
" -n <N>\n" 546 <<
" N >= 1: do N halfedge collapses.\n" 547 <<
" N <=-1: decimate down to |N| vertices.\n" 548 <<
" 0 < N < 1: decimate down to N%.\n" << std::endl;
549 std::cerr << std::endl;
550 std::cerr <<
"Modules:\n\n";
551 std::cerr <<
" AR[:ratio] - ModAspectRatio\n";
552 std::cerr <<
" EL[:legth] - ModEdgeLength*\n";
553 std::cerr <<
" HD[:distance] - ModHausdorff\n";
554 std::cerr <<
" IS - ModIndependentSets\n";
555 std::cerr <<
" ND[:angle] - ModNormalDeviation*\n";
556 std::cerr <<
" NF[:angle] - ModNormalFlipping\n";
557 std::cerr <<
" PM[:file name] - ModProgMesh\n";
558 std::cerr <<
" Q[:error] - ModQuadric*\n";
559 std::cerr <<
" R[:angle] - ModRoundness\n";
560 std::cerr <<
" 0 < angle < 60\n";
561 std::cerr <<
" *: priority module. Decimater needs one of them (not more).\n";
double seconds(void) const
Returns measured time in seconds, if the timer is in state 'Stopped'.
void set_aspect_ratio(float _f)
set aspect ratio
void set_max_normal_deviation(double _d)
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.
std::string as_string(Format format=Automatic)
void set_edge_length(typename Mesh::Scalar _f)
set edge_length
Has (r) / store (w) face normals.
void set_normal_deviation(Scalar _s)
Set normal deviation ( 0 .. 360 )
void set_max_err(double _err, bool _binary=true)
Use Normal deviation to control decimation.
Use edge length to control decimation.
Use Roundness of triangles to control decimation.
Set options for reader/writer modules.
Use aspect ratio to control decimation.
void update_face_normals()
Update normal vectors for all faces.
void start(void)
Start measurement.
bool read_mesh(Mesh &_mesh, const std::string &_filename)
Read a mesh from file _filename.
bool is_binary(void) const
Returns true if criteria returns a binary value.
Mesh decimation module computing collapse priority based on error quadrics.
void stop(void)
Stop measurement.