52 #include <OpenMesh/Core/IO/MeshIO.hh>
53 #include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
55 #include <OpenMesh/Tools/Utils/getopt.h>
63 #if defined(OM_CC_MIPS)
83 #define ADD_FN( RULE ) \
84 bool add_ ## RULE( Subdivider& _sub ) \
85 { return _sub.add< Adaptive:: RULE < MyMesh > >(); }
108 typedef bool (*add_rule_ft)( Subdivider& );
111 struct RuleMap : std::map< std::string, add_rule_ft >
115 #define ADD( RULE ) \
116 (*this)[ #RULE ] = add_##RULE;
145 std::string basename(
const std::string& _fname );
146 void usage_and_exit(
const std::string& _fname,
int xcode);
151 int main(
int argc,
char **argv)
154 size_t max_nv = size_t(-1);
157 std::string rule_sequence =
"Tvv3 VF FF FVc";
158 bool uniform =
false;
162 while ( (c=getopt(argc, argv,
"hlm:n:r:sU"))!=-1 )
166 case 's': rule_sequence =
"Tvv3 VF FF FVc";
break;
167 case 'l': rule_sequence =
"Tvv4 VdE EVc VdE EVc";
break;
168 case 'n': { std::stringstream s; s << optarg; s >> n_iter; }
break;
169 case 'm': { std::stringstream s; s << optarg; s >> max_nv; }
break;
170 case 'r': rule_sequence = optarg;
break;
171 case 'U': uniform =
true;
break;
172 case 'h': usage_and_exit(argv[0],0);
174 default: usage_and_exit(argv[0],1);
178 if ( optind == argc )
179 usage_and_exit(argv[0],2);
182 ifname = argv[optind++];
185 ofname = argv[optind++];
191 Subdivider subdivider(mesh);
195 std::cout <<
"Input mesh : " << ifname << std::endl;
198 std::cerr <<
" Error reading file!\n";
203 size_t n_vertices = mesh.n_vertices();
204 size_t n_edges = mesh.n_edges();
205 size_t n_faces = mesh.n_faces();
208 std::cout <<
"Desired #iterations: " << n_iter << std::endl;
210 if ( max_nv <
size_t(-1) )
212 std::cout <<
"Desired max. #V : " << max_nv << std::endl;
223 RuleMap::iterator it = available_rules.end();
225 for (s << rule_sequence; s >> token; )
227 if ( (it=available_rules.find( token )) != available_rules.end() )
229 it->second( subdivider );
231 else if ( token[0]==
'(' && (subdivider.n_rules() > 0) )
233 std::string::size_type beg(1);
234 if (token.length()==1)
240 std::string::size_type
241 end = token.find_last_of(
')');
242 std::string::size_type
243 size = end==std::string::npos ? token.size()-beg : end-beg;
247 std::cout <<
" " << token << std::endl;
248 std::cout <<
" " << beg <<
" " << end <<
" " << size << std::endl;
249 v << token.substr(beg, size);
251 std::cout <<
" coeffecient " << coeff << std::endl;
252 subdivider.rule( subdivider.n_rules()-1 ).set_coeff(coeff);
254 if (end == std::string::npos)
259 std::cerr <<
"Syntax error: Missing ')'\n";
266 std::cerr <<
"Syntax error: " << token <<
"?\n";
272 std::cout <<
"Rule sequence : "
273 << subdivider.rules_as_string() << std::endl;
276 std::cout <<
"Initialize subdivider\n";
277 if (!subdivider.initialize())
279 std::cerr <<
" Error!\n";
288 std::cout <<
"\nSubdividing...\n";
296 MyMesh::VertexIter v_it;
297 MyMesh::FaceHandle fh;
298 MyMesh::FaceIter f_it;
305 size_t n_rules = subdivider.n_rules();
310 size_t target1 = (n - 1) * n_rules + subdivider.subdiv_rule().number() + 1;
311 size_t target2 = n * n_rules;
313 for (f_it = mesh.faces_begin(); f_it != mesh.faces_end(); ++f_it) {
315 if (mesh.data(*f_it).state() < int(target1) ) {
319 subdivider.refine(fh);
324 for (v_it = mesh.vertices_begin(); v_it != mesh.vertices_end(); ++v_it) {
326 if (mesh.data(*v_it).state() < int(target2) ) {
329 subdivider.refine(vh);
338 MyMesh::FaceIter f_it;
339 MyMesh::FaceHandle fh;
341 std::vector<double> __acos;
342 size_t buckets(3000);
344 double range2bucket(buckets/range);
346 for (i = 0; i < buckets; ++i)
347 __acos.push_back( acos(-1.0 + i * range / buckets) );
352 for (i = 0; i < n_iter && mesh.n_vertices() < max_nv; ++i)
359 fh = *(mesh.faces_begin());
362 for (f_it = mesh.faces_begin(); f_it != mesh.faces_end(); ++f_it) {
364 double face_quality = 0.0;
367 for (ff_it = mesh.ff_iter(*f_it); ff_it.is_valid(); ++ff_it) {
369 double temp_quality =
OpenMesh::dot( mesh.normal(*f_it), mesh.normal(*ff_it) );
371 if (temp_quality >= 1.0)
373 else if (temp_quality <= -1.0)
375 temp_quality = (1.0+temp_quality) * range2bucket;
376 face_quality += __acos[int(temp_quality+.5)];
381 face_quality /= valence;
387 #define heh halfedge_handle
388 #define nheh next_halfedge_handle
389 #define tvh to_vertex_handle
390 #define fvh from_vertex_handle
391 p1 = mesh.point(mesh.tvh(mesh.heh(*f_it)));
392 p2 = mesh.point(mesh.fvh(mesh.heh(*f_it)));
393 p3 = mesh.point(mesh.tvh(mesh.nheh(mesh.heh(*f_it))));
399 area = ((p2 - p1) % (p3 - p1)).norm();
402 face_quality *= pow(
double(area),
double(.1));
405 if (face_quality >= quality && !mesh.is_boundary(*f_it))
407 quality = face_quality;
414 subdivider.refine(fh);
426 for (MyMesh::VertexIter v_it = mesh.vertices_begin();
427 v_it != mesh.vertices_end(); ++v_it)
429 if (mesh.data(*v_it).state() > max_level)
430 max_level = mesh.data(*v_it).state();
435 std::cout <<
"\nDid " << i << (uniform ?
" uniform " :
"" )
436 <<
" subdivision steps in "
438 <<
", " << i/timer.
seconds() <<
" steps/s\n";
439 std::cout <<
" only refinement: " << timer2.
as_string()
440 <<
", " << i/timer2.
seconds() <<
" steps/s\n\n";
442 std::cout <<
"Before: ";
443 std::cout << n_vertices <<
" Vertices, ";
444 std::cout << n_edges <<
" Edges, ";
445 std::cout << n_faces <<
" Faces. \n";
447 std::cout <<
"Now : ";
448 std::cout << mesh.n_vertices() <<
" Vertices, ";
449 std::cout << mesh.n_edges() <<
" Edges, ";
450 std::cout << mesh.n_faces() <<
" Faces. \n\n";
452 std::cout <<
"Maximum quality : " << quality << std::endl;
453 std::cout <<
"Maximum Subdivision Level: " << max_level/subdivider.n_rules()
454 << std::endl << std::endl;
458 if ( ofname.empty() )
462 s <<
"result." << subdivider.rules_as_string(
"_")
463 <<
"-" << i <<
"x.off";
467 std::cout <<
"Output file: '" << ofname <<
"'.\n";
470 std::cerr <<
" Error writing file!\n";
480 void usage_and_exit(
const std::string& _fname,
int xcode)
485 <<
"Usage: " << basename(_fname)
486 <<
" [Options] input-mesh [output-mesh]\n\n";
487 cout <<
"\tAdaptively refine an input-mesh. The refined mesh is stored in\n"
488 <<
"\ta file named \"result.XXX.off\" (binary .off), if not specified\n"
489 <<
"\texplicitely (optional 2nd parameter of command line).\n\n";
490 cout <<
"Options:\n\n";
491 cout <<
"-m <int>\n\tAdaptively refine up to approx. <int> vertices.\n\n"
492 <<
"-n <int>\n\tAdaptively refine <int> times.\n\n"
493 <<
"-r <rule sequence>\n\tDefine a custom rule sequence.\n\n"
494 <<
"-l\n\tUse rule sequence for adaptive Loop.\n\n"
495 <<
"-s\n\tUse rule sequence for adaptive sqrt(3).\n\n"
496 <<
"-U\n\tRefine mesh uniformly (simulates uniform subdivision).\n\n";
501 std::string basename(
const std::string& _f)
503 std::string::size_type
dot = _f.rfind(
"/");
504 if (dot == std::string::npos)
506 return _f.substr(dot+1, _f.length()-(dot+1));
bool read_mesh(Mesh &_mesh, const std::string &_filename)
Read a mesh from file _filename.
void stop(void)
Stop measurement.
Kernel::Point Point
Coordinate type.
std::string as_string(Format format=Automatic)
Kernel::FaceFaceIter FaceFaceIter
Circulator.
void update_face_normals()
Update normal vectors for all faces.
void start(void)
Start measurement.
osg::Vec3f::ValueType dot(const osg::Vec3f &_v1, const osg::Vec3f &_v2)
Adapter for osg vector member computing a scalar product.
Kernel::Scalar Scalar
Scalar type.
Kernel::VertexHandle VertexHandle
Handle for referencing the corresponding item.
double seconds(void) const
Returns measured time in seconds, if the timer is in state 'Stopped'.
void cont(void)
Continue measurement.
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