47 #include <OpenMesh/Core/IO/MeshIO.hh> 48 #include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh> 50 #include <OpenMesh/Tools/Utils/getopt.h> 59 #if defined(OM_CC_MIPS) 79 #define ADD_FN( RULE ) \ 80 bool add_ ## RULE( Subdivider& _sub ) \ 81 { return _sub.add< Adaptive:: RULE < MyMesh > >(); } 104 typedef bool (*add_rule_ft)( Subdivider& );
107 struct RuleMap : std::map< std::string, add_rule_ft >
111 #define ADD( RULE ) \ 112 (*this)[ #RULE ] = add_##RULE; 141 std::string basename(
const std::string& _fname );
142 void usage_and_exit(
const std::string& _fname,
int xcode);
147 int main(
int argc,
char **argv)
150 size_t max_nv = std::numeric_limits<size_t>::max();
153 std::string rule_sequence =
"Tvv3 VF FF FVc";
154 bool uniform =
false;
158 while ( (c=getopt(argc, argv,
"hlm:n:r:sU"))!=-1 )
162 case 's': rule_sequence =
"Tvv3 VF FF FVc";
break;
163 case 'l': rule_sequence =
"Tvv4 VdE EVc VdE EVc";
break;
164 case 'n': { std::stringstream s; s << optarg; s >> n_iter; }
break;
165 case 'm': { std::stringstream s; s << optarg; s >> max_nv; }
break;
166 case 'r': rule_sequence = optarg;
break;
167 case 'U': uniform =
true;
break;
168 case 'h': usage_and_exit(argv[0],0);
break;
170 default: usage_and_exit(argv[0],1);
174 if ( optind == argc )
175 usage_and_exit(argv[0],2);
178 ifname = argv[optind++];
181 ofname = argv[optind++];
187 Subdivider subdivider(mesh);
191 std::cout <<
"Input mesh : " << ifname << std::endl;
194 std::cerr <<
" Error reading file!\n";
199 size_t n_vertices = mesh.n_vertices();
200 size_t n_edges = mesh.n_edges();
201 size_t n_faces = mesh.n_faces();
204 std::cout <<
"Desired #iterations: " << n_iter << std::endl;
206 if ( max_nv < std::numeric_limits<size_t>::max() )
208 std::cout <<
"Desired max. #V : " << max_nv << std::endl;
210 n_iter = std::numeric_limits<size_t>::max();
219 RuleMap::iterator it = available_rules.end();
221 for (s << rule_sequence; s >> token; )
223 if ( (it=available_rules.find( token )) != available_rules.end() )
225 it->second( subdivider );
227 else if ( token[0]==
'(' && (subdivider.n_rules() > 0) )
229 std::string::size_type beg(1);
230 if (token.length()==1)
236 std::string::size_type
237 end = token.find_last_of(
')');
238 std::string::size_type
239 size = end==std::string::npos ? token.size()-beg : end-beg;
243 std::cout <<
" " << token << std::endl;
244 std::cout <<
" " << beg <<
" " << end <<
" " << size << std::endl;
245 v << token.substr(beg, size);
247 std::cout <<
" coeffecient " << coeff << std::endl;
248 subdivider.rule( subdivider.n_rules()-1 ).set_coeff(coeff);
250 if (end == std::string::npos)
255 std::cerr <<
"Syntax error: Missing ')'\n";
262 std::cerr <<
"Syntax error: " << token <<
"?\n";
268 std::cout <<
"Rule sequence : " 269 << subdivider.rules_as_string() << std::endl;
272 std::cout <<
"Initialize subdivider\n";
273 if (!subdivider.initialize())
275 std::cerr <<
" Error!\n";
284 std::cout <<
"\nSubdividing...\n";
292 MyMesh::VertexIter v_it;
293 MyMesh::FaceHandle fh;
294 MyMesh::FaceIter f_it;
301 size_t n_rules = subdivider.n_rules();
306 size_t target1 = (n - 1) * n_rules + subdivider.subdiv_rule().number() + 1;
307 size_t target2 = n * n_rules;
309 for (f_it = mesh.faces_begin(); f_it != mesh.faces_end(); ++f_it) {
311 if (mesh.data(*f_it).state() < int(target1) ) {
315 subdivider.refine(fh);
320 for (v_it = mesh.vertices_begin(); v_it != mesh.vertices_end(); ++v_it) {
322 if (mesh.data(*v_it).state() < int(target2) ) {
325 subdivider.refine(vh);
334 MyMesh::FaceIter f_it;
335 MyMesh::FaceHandle fh;
337 std::vector<double> __acos;
338 size_t buckets(3000);
340 double range2bucket(buckets/range);
342 for (i = 0; i < buckets; ++i)
343 __acos.push_back( acos(-1.0 + i * range / buckets) );
348 for (i = 0; i < n_iter && mesh.n_vertices() < max_nv; ++i)
355 fh = *(mesh.faces_begin());
358 for (f_it = mesh.faces_begin(); f_it != mesh.faces_end(); ++f_it) {
360 double face_quality = 0.0;
363 for (ff_it = mesh.ff_iter(*f_it); ff_it.is_valid(); ++ff_it) {
365 double temp_quality =
OpenMesh::dot( mesh.normal(*f_it), mesh.normal(*ff_it) );
367 if (temp_quality >= 1.0)
369 else if (temp_quality <= -1.0)
371 temp_quality = (1.0+temp_quality) * range2bucket;
372 face_quality += __acos[int(temp_quality+.5)];
377 face_quality /= valence;
383 #define heh halfedge_handle 384 #define nheh next_halfedge_handle 385 #define tvh to_vertex_handle 386 #define fvh from_vertex_handle 387 p1 = mesh.point(mesh.tvh(mesh.heh(*f_it)));
388 p2 = mesh.point(mesh.fvh(mesh.heh(*f_it)));
389 p3 = mesh.point(mesh.tvh(mesh.nheh(mesh.heh(*f_it))));
395 area = ((p2 - p1) % (p3 - p1)).norm();
398 face_quality *= pow(
double(area),
double(.1));
401 if (face_quality >= quality && !mesh.is_boundary(*f_it))
403 quality = face_quality;
410 subdivider.refine(fh);
422 for (MyMesh::VertexIter v_it = mesh.vertices_begin();
423 v_it != mesh.vertices_end(); ++v_it)
425 if (mesh.data(*v_it).state() > max_level)
426 max_level = mesh.data(*v_it).state();
431 std::cout <<
"\nDid " << i << (uniform ?
" uniform " :
"" )
432 <<
" subdivision steps in " 434 <<
", " << i/timer.
seconds() <<
" steps/s\n";
435 std::cout <<
" only refinement: " << timer2.
as_string()
436 <<
", " << i/timer2.
seconds() <<
" steps/s\n\n";
438 std::cout <<
"Before: ";
439 std::cout << n_vertices <<
" Vertices, ";
440 std::cout << n_edges <<
" Edges, ";
441 std::cout << n_faces <<
" Faces. \n";
443 std::cout <<
"Now : ";
444 std::cout << mesh.n_vertices() <<
" Vertices, ";
445 std::cout << mesh.n_edges() <<
" Edges, ";
446 std::cout << mesh.n_faces() <<
" Faces. \n\n";
448 std::cout <<
"Maximum quality : " << quality << std::endl;
449 std::cout <<
"Maximum Subdivision Level: " << max_level/subdivider.n_rules()
450 << std::endl << std::endl;
454 if ( ofname.empty() )
458 s <<
"result." << subdivider.rules_as_string(
"_")
459 <<
"-" << i <<
"x.off";
463 std::cout <<
"Output file: '" << ofname <<
"'.\n";
466 std::cerr <<
" Error writing file!\n";
476 void usage_and_exit(
const std::string& _fname,
int xcode)
481 <<
"Usage: " << basename(_fname)
482 <<
" [Options] input-mesh [output-mesh]\n\n";
483 cout <<
"\tAdaptively refine an input-mesh. The refined mesh is stored in\n" 484 <<
"\ta file named \"result.XXX.off\" (binary .off), if not specified\n" 485 <<
"\texplicitely (optional 2nd parameter of command line).\n\n";
486 cout <<
"Options:\n\n";
487 cout <<
"-m <int>\n\tAdaptively refine up to approx. <int> vertices.\n\n" 488 <<
"-n <int>\n\tAdaptively refine <int> times.\n\n" 489 <<
"-r <rule sequence>\n\tDefine a custom rule sequence.\n\n" 490 <<
"-l\n\tUse rule sequence for adaptive Loop.\n\n" 491 <<
"-s\n\tUse rule sequence for adaptive sqrt(3).\n\n" 492 <<
"-U\n\tRefine mesh uniformly (simulates uniform subdivision).\n\n";
497 std::string basename(
const std::string& _f)
499 std::string::size_type
dot = _f.rfind(
"/");
500 if (dot == std::string::npos)
502 return _f.substr(dot+1, _f.length()-(dot+1));
CompositeTraits::state_t state_t
double seconds(void) const
Returns measured time in seconds, if the timer is in state 'Stopped'.
Kernel::Point Point
Coordinate type.
Kernel::Scalar Scalar
Scalar type.
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)
osg::Vec3f::ValueType dot(const osg::Vec3f &_v1, const osg::Vec3f &_v2)
Adapter for osg vector member computing a scalar product.
Kernel::VertexHandle VertexHandle
Handle for referencing the corresponding item.
Kernel::FaceFaceIter FaceFaceIter
Circulator.
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.
void cont(void)
Continue measurement.
void stop(void)
Stop measurement.