52 #include <OpenMesh/Core/IO/MeshIO.hh>
53 #include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
55 #include <OpenMesh/Tools/Utils/getopt.h>
64 #if defined(OM_CC_MIPS)
84 #define ADD_FN( RULE ) \
85 bool add_ ## RULE( Subdivider& _sub ) \
86 { return _sub.add< Adaptive:: RULE < MyMesh > >(); }
109 typedef bool (*add_rule_ft)( Subdivider& );
112 struct RuleMap : std::map< std::string, add_rule_ft >
116 #define ADD( RULE ) \
117 (*this)[ #RULE ] = add_##RULE;
146 std::string basename(
const std::string& _fname );
147 void usage_and_exit(
const std::string& _fname,
int xcode);
152 int main(
int argc,
char **argv)
155 size_t max_nv = std::numeric_limits<size_t>::max();
158 std::string rule_sequence =
"Tvv3 VF FF FVc";
159 bool uniform =
false;
163 while ( (c=getopt(argc, argv,
"hlm:n:r:sU"))!=-1 )
167 case 's': rule_sequence =
"Tvv3 VF FF FVc";
break;
168 case 'l': rule_sequence =
"Tvv4 VdE EVc VdE EVc";
break;
169 case 'n': { std::stringstream s; s << optarg; s >> n_iter; }
break;
170 case 'm': { std::stringstream s; s << optarg; s >> max_nv; }
break;
171 case 'r': rule_sequence = optarg;
break;
172 case 'U': uniform =
true;
break;
173 case 'h': usage_and_exit(argv[0],0);
175 default: usage_and_exit(argv[0],1);
179 if ( optind == argc )
180 usage_and_exit(argv[0],2);
183 ifname = argv[optind++];
186 ofname = argv[optind++];
192 Subdivider subdivider(mesh);
196 std::cout <<
"Input mesh : " << ifname << std::endl;
199 std::cerr <<
" Error reading file!\n";
204 size_t n_vertices = mesh.n_vertices();
205 size_t n_edges = mesh.n_edges();
206 size_t n_faces = mesh.n_faces();
209 std::cout <<
"Desired #iterations: " << n_iter << std::endl;
211 if ( max_nv < std::numeric_limits<size_t>::max() )
213 std::cout <<
"Desired max. #V : " << max_nv << std::endl;
215 n_iter = std::numeric_limits<size_t>::max();
224 RuleMap::iterator it = available_rules.end();
226 for (s << rule_sequence; s >> token; )
228 if ( (it=available_rules.find( token )) != available_rules.end() )
230 it->second( subdivider );
232 else if ( token[0]==
'(' && (subdivider.n_rules() > 0) )
234 std::string::size_type beg(1);
235 if (token.length()==1)
241 std::string::size_type
242 end = token.find_last_of(
')');
243 std::string::size_type
244 size = end==std::string::npos ? token.size()-beg : end-beg;
248 std::cout <<
" " << token << std::endl;
249 std::cout <<
" " << beg <<
" " << end <<
" " << size << std::endl;
250 v << token.substr(beg, size);
252 std::cout <<
" coeffecient " << coeff << std::endl;
253 subdivider.rule( subdivider.n_rules()-1 ).set_coeff(coeff);
255 if (end == std::string::npos)
260 std::cerr <<
"Syntax error: Missing ')'\n";
267 std::cerr <<
"Syntax error: " << token <<
"?\n";
273 std::cout <<
"Rule sequence : "
274 << subdivider.rules_as_string() << std::endl;
277 std::cout <<
"Initialize subdivider\n";
278 if (!subdivider.initialize())
280 std::cerr <<
" Error!\n";
289 std::cout <<
"\nSubdividing...\n";
297 MyMesh::VertexIter v_it;
298 MyMesh::FaceHandle fh;
299 MyMesh::FaceIter f_it;
306 size_t n_rules = subdivider.n_rules();
311 size_t target1 = (n - 1) * n_rules + subdivider.subdiv_rule().number() + 1;
312 size_t target2 = n * n_rules;
314 for (f_it = mesh.faces_begin(); f_it != mesh.faces_end(); ++f_it) {
316 if (mesh.data(*f_it).state() < int(target1) ) {
320 subdivider.refine(fh);
325 for (v_it = mesh.vertices_begin(); v_it != mesh.vertices_end(); ++v_it) {
327 if (mesh.data(*v_it).state() < int(target2) ) {
330 subdivider.refine(vh);
339 MyMesh::FaceIter f_it;
340 MyMesh::FaceHandle fh;
342 std::vector<double> __acos;
343 size_t buckets(3000);
345 double range2bucket(buckets/range);
347 for (i = 0; i < buckets; ++i)
348 __acos.push_back( acos(-1.0 + i * range / buckets) );
353 for (i = 0; i < n_iter && mesh.n_vertices() < max_nv; ++i)
360 fh = *(mesh.faces_begin());
363 for (f_it = mesh.faces_begin(); f_it != mesh.faces_end(); ++f_it) {
365 double face_quality = 0.0;
368 for (ff_it = mesh.ff_iter(*f_it); ff_it.is_valid(); ++ff_it) {
370 double temp_quality =
OpenMesh::dot( mesh.normal(*f_it), mesh.normal(*ff_it) );
372 if (temp_quality >= 1.0)
374 else if (temp_quality <= -1.0)
376 temp_quality = (1.0+temp_quality) * range2bucket;
377 face_quality += __acos[int(temp_quality+.5)];
382 face_quality /= valence;
388 #define heh halfedge_handle
389 #define nheh next_halfedge_handle
390 #define tvh to_vertex_handle
391 #define fvh from_vertex_handle
392 p1 = mesh.point(mesh.tvh(mesh.heh(*f_it)));
393 p2 = mesh.point(mesh.fvh(mesh.heh(*f_it)));
394 p3 = mesh.point(mesh.tvh(mesh.nheh(mesh.heh(*f_it))));
400 area = ((p2 - p1) % (p3 - p1)).norm();
403 face_quality *= pow(
double(area),
double(.1));
406 if (face_quality >= quality && !mesh.is_boundary(*f_it))
408 quality = face_quality;
415 subdivider.refine(fh);
427 for (MyMesh::VertexIter v_it = mesh.vertices_begin();
428 v_it != mesh.vertices_end(); ++v_it)
430 if (mesh.data(*v_it).state() > max_level)
431 max_level = mesh.data(*v_it).state();
436 std::cout <<
"\nDid " << i << (uniform ?
" uniform " :
"" )
437 <<
" subdivision steps in "
439 <<
", " << i/timer.
seconds() <<
" steps/s\n";
440 std::cout <<
" only refinement: " << timer2.
as_string()
441 <<
", " << i/timer2.
seconds() <<
" steps/s\n\n";
443 std::cout <<
"Before: ";
444 std::cout << n_vertices <<
" Vertices, ";
445 std::cout << n_edges <<
" Edges, ";
446 std::cout << n_faces <<
" Faces. \n";
448 std::cout <<
"Now : ";
449 std::cout << mesh.n_vertices() <<
" Vertices, ";
450 std::cout << mesh.n_edges() <<
" Edges, ";
451 std::cout << mesh.n_faces() <<
" Faces. \n\n";
453 std::cout <<
"Maximum quality : " << quality << std::endl;
454 std::cout <<
"Maximum Subdivision Level: " << max_level/subdivider.n_rules()
455 << std::endl << std::endl;
459 if ( ofname.empty() )
463 s <<
"result." << subdivider.rules_as_string(
"_")
464 <<
"-" << i <<
"x.off";
468 std::cout <<
"Output file: '" << ofname <<
"'.\n";
471 std::cerr <<
" Error writing file!\n";
481 void usage_and_exit(
const std::string& _fname,
int xcode)
486 <<
"Usage: " << basename(_fname)
487 <<
" [Options] input-mesh [output-mesh]\n\n";
488 cout <<
"\tAdaptively refine an input-mesh. The refined mesh is stored in\n"
489 <<
"\ta file named \"result.XXX.off\" (binary .off), if not specified\n"
490 <<
"\texplicitely (optional 2nd parameter of command line).\n\n";
491 cout <<
"Options:\n\n";
492 cout <<
"-m <int>\n\tAdaptively refine up to approx. <int> vertices.\n\n"
493 <<
"-n <int>\n\tAdaptively refine <int> times.\n\n"
494 <<
"-r <rule sequence>\n\tDefine a custom rule sequence.\n\n"
495 <<
"-l\n\tUse rule sequence for adaptive Loop.\n\n"
496 <<
"-s\n\tUse rule sequence for adaptive sqrt(3).\n\n"
497 <<
"-U\n\tRefine mesh uniformly (simulates uniform subdivision).\n\n";
502 std::string basename(
const std::string& _f)
504 std::string::size_type
dot = _f.rfind(
"/");
505 if (dot == std::string::npos)
507 return _f.substr(dot+1, _f.length()-(dot+1));
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'.
osg::Vec3f::ValueType dot(const osg::Vec3f &_v1, const osg::Vec3f &_v2)
Adapter for osg vector member computing a scalar product.
Kernel::FaceFaceIter FaceFaceIter
Circulator.
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.
CompositeTraits::state_t state_t
Kernel::Point Point
Coordinate type.
bool read_mesh(Mesh &_mesh, const std::string &_filename)
Read a mesh from file _filename.
void stop(void)
Stop measurement.
void cont(void)
Continue measurement.
Kernel::VertexHandle VertexHandle
Handle for referencing the corresponding item.
Kernel::Scalar Scalar
Scalar type.