int main() { std::stringstream ss; ss << "\ OFF\n6 4 0\n\ 0 1 0\n\ 0 0 0\n\ 1 0 0\n\ 1 1 0\n\ 2 1 0\n\ 2 0 0\n\ 3 0 1 2\n\ 3 0 2 3\n\ 3 2 5 3\n\ 3 5 4 3\n"; Polyhedron P; ss >> P; assert( P.size_of_vertices() == 6); assert( P.size_of_facets() == 4); assert( P.is_valid() ); //consider vertex 3 and set its halfedge to be on the border Polyhedron::Vertex_iterator vit=P.vertices_begin(); std::advance(vit, 3); assert( vit->point() == K::Point_3(1, 1, 0) ); Polyhedron::Halfedge_handle h=vit->halfedge(); while ( !h->is_border() ) h=h->next()->opposite(); vit->VBase::set_halfedge(h); assert( vit->halfedge()->vertex() == vit ); //consider vertex 4 and set its halfedge to be on the border ++vit; assert( vit->point() == K::Point_3(2, 1, 0) ); h=vit->halfedge(); while ( !h->is_border() ) h=h->next()->opposite(); vit->VBase::set_halfedge(h); assert( vit->halfedge()->vertex() == vit ); //try to append a facet Appender modifier; P.delegate(modifier); assert( P.size_of_vertices() == 7); assert( P.size_of_facets() == 5); assert( P.is_valid() ); }
void geometryUtils::subdivide(Polyhedron& P) { if (P.size_of_facets() == 0) return; // We use that new vertices/halfedges/facets are appended at the end. std::size_t nv = P.size_of_vertices(); Vertex_iterator last_v = P.vertices_end(); --last_v; // the last of the old vertices Edge_iterator last_e = P.edges_end(); --last_e; // the last of the old edges Facet_iterator last_f = P.facets_end(); --last_f; // the last of the old facets Facet_iterator f = P.facets_begin(); // create new center vertices do { geometryUtils::subdivide_create_center_vertex(P, f); } while (f++ != last_f); std::vector<Point_3> pts; // smooth the old vertices pts.reserve(nv); // get intermediate space for the new points ++last_v; // make it the past-the-end position again std::transform(P.vertices_begin(), last_v, std::back_inserter(pts), Smooth_old_vertex()); std::copy(pts.begin(), pts.end(), P.points_begin()); Edge_iterator e = P.edges_begin(); // flip the old edges ++last_e; // make it the past-the-end position again while (e != last_e) { Halfedge_handle h = e; ++e; // careful, incr. before flip since flip destroys current edge geometryUtils::subdivide_flip_edge(P, h); }; CGAL_postcondition(P.is_valid()); };
IGL_INLINE bool igl::mesh_to_polyhedron( const Eigen::MatrixXd & V, const Eigen::MatrixXi & F, Polyhedron & poly) { typedef typename Polyhedron::HalfedgeDS HalfedgeDS; // Postcondition: hds is a valid polyhedral surface. CGAL::Polyhedron_incremental_builder_3<HalfedgeDS> B(poly.hds()); B.begin_surface(V.rows(),F.rows()); typedef typename HalfedgeDS::Vertex Vertex; typedef typename Vertex::Point Point; assert(V.cols() == 3 && "V must be #V by 3"); for(int v = 0;v<V.rows();v++) { B.add_vertex(Point(V(v,0),V(v,1),V(v,2))); } assert(F.cols() == 3 && "F must be #F by 3"); for(int f=0;f<F.rows();f++) { B.begin_facet(); for(int c = 0;c<3;c++) { B.add_vertex_to_facet(F(f,c)); } B.end_facet(); } if(B.error()) { B.rollback(); return false; } B.end_surface(); return poly.is_valid(); }
void test(std::string fname, std::size_t expected_duplicated_vertices) { std::vector<K::Point_3> points; std::vector< std::vector<std::size_t> > polygons; std::ifstream input(fname.c_str()); if (!input) { std::cerr << "Cannot open file " << fname << "\n"; exit(EXIT_FAILURE); } if (!CGAL::read_OFF(input, points, polygons)) { std::cerr << "Error parsing the OFF file " << fname << "\n"; exit(EXIT_FAILURE); } std::size_t initial_nb_points = points.size(); CGAL::orient_polygon_soup(points, polygons); assert(expected_duplicated_vertices == points.size()-initial_nb_points); Polyhedron P; CGAL::polygon_soup_to_polyhedron_3(P, points, polygons); assert(P.is_valid()); std::cout << fname << " OK\n"; }
void test_polygon_soup(std::string fname, bool expected) { typedef CGAL::Polyhedron_3<K> Polyhedron; std::vector<typename K::Point_3> points; std::vector< std::vector<std::size_t> > polygons; std::ifstream input(fname.c_str()); if(!input) { std::cerr << "Error opening file " << fname << "\n"; exit(EXIT_FAILURE); } if(!CGAL::read_OFF(input, points, polygons)) { std::cerr << "Error parsing the OFF file " << fname << "\n"; exit(EXIT_FAILURE); } bool is_mesh = CGAL::Polygon_mesh_processing::is_polygon_soup_a_polygon_mesh(polygons); std::cout << "is_polygon_soup_a_polygon_mesh(" << fname << ") == " << std::boolalpha << is_mesh << ";" << std::endl; assert(is_mesh == expected); if(is_mesh) { Polyhedron p; CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh(points, polygons, p); assert(p.is_valid()); } if(!expected) { CGAL::Polygon_mesh_processing::orient_polygon_soup(points, polygons); bool is_mesh = CGAL::Polygon_mesh_processing::is_polygon_soup_a_polygon_mesh(polygons); std::cout << "After orientation: is_polygon_soup_a_polygon_mesh(" << fname << ") == " << std::boolalpha << is_mesh << ";" << std::endl; if(is_mesh) { Polyhedron p; CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh(points, polygons, p); assert(p.is_valid()); } } std::cout << fname << " OK\n\n\n"; }
void operator()(std::string filename) { std::cout << filename << std::endl; std::list<Weighted_point> l; std::ifstream in(filename.c_str()); assert(in.is_open()); Weighted_point wp; while (in >> wp) l.push_front(wp); Skin_surface_3 skin_surface(l.begin(), l.end(), s); Polyhedron p; CGAL::mesh_skin_surface_3(skin_surface, p); assert(p.is_valid() && p.is_closed()); //std::cout << p << std::endl; }
void subdiv_border( Polyhedron& P) { if ( P.size_of_facets() == 0) return; // We use that new halfedges are appended at the end. Edge_iterator last_e = P.edges_end(); -- last_e; // the last of the old edges Edge_iterator e = P.edges_begin(); // create trisected border edges do { if ( e->opposite()->is_border()) trisect_border_halfedge( P, e->opposite()); else if ( e->is_border()) trisect_border_halfedge( P, e); } while ( e++ != last_e); e = P.edges_begin(); // smooth points on border edges std::vector<Point> pts; // store new smoothed points temporarily do { if ( e->opposite()->is_border()) smooth_border_vertices( e->opposite(), std::back_inserter(pts)); else if ( e->is_border()) smooth_border_vertices( e, std::back_inserter(pts)); } while ( e++ != last_e); e = P.edges_begin(); // copy smoothed points back std::vector<Point>::iterator i = pts.begin(); do { if ( e->opposite()->is_border()) { e->vertex()->point() = *i++; e->opposite()->vertex()->point() = *i++; e->opposite()->next()->vertex()->point() = *i++; } else if ( e->is_border()) { e->opposite()->vertex()->point() = *i++; e->vertex()->point() = *i++; e->next()->vertex()->point() = *i++; } } while ( e++ != last_e); CGAL_assertion( i == pts.end()); CGAL_postcondition( P.is_valid()); }
int main(int argc, char * argv[]) { std::cerr << "PARAMETERIZATION" << std::endl; std::cerr << " Floater parameterization" << std::endl; std::cerr << " Circle border" << std::endl; std::cerr << " Eigen solver" << std::endl; //*************************************** // decode parameters //*************************************** if (argc-1 != 1) { std::cerr << "Usage: " << argv[0] << " input_file.off" << std::endl; return(EXIT_FAILURE); } // File name is: const char* input_filename = argv[1]; //*************************************** // Read the mesh //*************************************** // Read the mesh std::ifstream stream(input_filename); Polyhedron mesh; stream >> mesh; if(!stream || !mesh.is_valid() || mesh.empty()) { std::cerr << "Error: cannot read OFF file " << input_filename << std::endl; return EXIT_FAILURE; } //*************************************** // Create Polyhedron adaptor // Note: no cutting => we support only // meshes that are topological disks //*************************************** typedef CGAL::Parameterization_polyhedron_adaptor_3<Polyhedron> Parameterization_polyhedron_adaptor; Timer t; t.start(); Parameterization_polyhedron_adaptor mesh_adaptor(mesh); //*************************************** // Floater Mean Value Coordinates parameterization // (circular border) with Eigen solver //*************************************** // Circular border parameterizer (the default) typedef CGAL::Circular_border_arc_length_parameterizer_3<Parameterization_polyhedron_adaptor> Border_parameterizer; // Eigen solver typedef CGAL::Eigen_solver_traits<Eigen::BiCGSTAB<CGAL::Eigen_sparse_matrix<double>::EigenType, Eigen::IncompleteLUT< double > > > Solver; // Floater Mean Value Coordinates parameterization // (circular border) with Eigen solver typedef CGAL::Mean_value_coordinates_parameterizer_3<Parameterization_polyhedron_adaptor, Border_parameterizer, Solver> Parameterizer; Parameterizer::Error_code err = CGAL::parameterize(mesh_adaptor, Parameterizer()); t.stop(); switch(err) { case Parameterizer::OK: // Success break; case Parameterizer::ERROR_EMPTY_MESH: // Input mesh not supported case Parameterizer::ERROR_NON_TRIANGULAR_MESH: case Parameterizer::ERROR_NO_TOPOLOGICAL_DISC: case Parameterizer::ERROR_BORDER_TOO_SHORT: std::cerr << "Input mesh not supported: " << Parameterizer::get_error_message(err) << std::endl; return EXIT_FAILURE; break; default: // Error std::cerr << "Error: " << Parameterizer::get_error_message(err) << std::endl; return EXIT_FAILURE; break; }; //*************************************** // Output //*************************************** // Raw output: dump (u,v) pairs Polyhedron::Vertex_const_iterator pVertex; for (pVertex = mesh.vertices_begin(); pVertex != mesh.vertices_end(); pVertex++) { // (u,v) pair is stored in any halfedge double u = mesh_adaptor.info(pVertex->halfedge())->uv().x(); double v = mesh_adaptor.info(pVertex->halfedge())->uv().y(); std::cout << "(u,v) = (" << u << "," << v << ")" << std::endl; } std::cerr << t.time() << "sec." << std::endl; return EXIT_SUCCESS; }
void test_Subdivision_surface_3() { typedef CGAL::Cartesian<double> Kernel; typedef CGAL::Polyhedron_3<Kernel> Polyhedron; // test Catmull-Clark subdivision on quad mesh { ifstream mesh(TESTMESH_QUAD); Polyhedron P; mesh >> P; Subdivision_method_3::CatmullClark_subdivision(P,TEST_DEPTH); assert(P.is_valid()); } // test Catmull-Clark subdivision on 'opened' quad mesh { ifstream mesh(TESTMESH_QUAD_OPEN); Polyhedron P; mesh >> P; Subdivision_method_3::CatmullClark_subdivision(P,TEST_DEPTH); assert(P.is_valid()); } // test Loop subdivision on tri mesh { ifstream mesh(TESTMESH_TRI); Polyhedron P; mesh >> P; Subdivision_method_3::Loop_subdivision(P,TEST_DEPTH); assert(P.is_valid()); } // test Loop subdivision on 'opened' tri mesh { ifstream mesh(TESTMESH_TRI_OPEN); Polyhedron P; mesh >> P; Subdivision_method_3::Loop_subdivision(P,TEST_DEPTH); assert(P.is_valid()); } // test Doo-Sabin subdivision on general mesh { ifstream mesh(TESTMESH_TRI_OPEN); Polyhedron P; mesh >> P; Subdivision_method_3::DooSabin_subdivision(P,TEST_DEPTH); assert(P.is_valid()); } // test Sqrt-3 subdivision on tri mesh { ifstream mesh(TESTMESH_TRI); Polyhedron P; mesh >> P; Subdivision_method_3::Sqrt3_subdivision(P,TEST_DEPTH); assert(P.is_valid()); } }
// a helper method for running different iterators void running_iterators( Polyhedron& P) { if ( P.size_of_facets() == 0) return; std::size_t nv = P.size_of_vertices(); std::cout << "The number of vertices in the Polyhedron: " << nv << std::endl; std::cout << "The number of facets in the Polyhedron: " << P.size_of_facets() << std::endl; std::cout << "The number of half edges in the Polyhedron: " << P.size_of_halfedges() << std::endl; std::cout << std:: endl; Polyhedron::Vertex_iterator last_v = P.vertices_end(); -- last_v; // the last of the old vertices Polyhedron::Edge_iterator last_e = P.edges_end(); -- last_e; // the last of the old edges Polyhedron::Facet_iterator last_f = P.facets_end(); -- last_f; // the last of the old facets int k = 0; Polyhedron::Facet_iterator f = P.facets_begin(); do { std::cout << "Printing a facet index: " << k++ << std::endl; f->halfedge(); } while ( f++ != last_f); std::cout << std::endl; // ------------------------------------------------- // traverse the vertices // ------------------------------------------------- std::cout << "Printing the vertex indices: " << std::endl; int n=0; for (Polyhedron::Vertex_iterator vi = P.vertices_begin(); vi != P.vertices_end(); ++vi) { Kernel::Point_3 p; p = vi->point(); std::cout << "Vertex index: " << n++ << std::endl; std::cout << "p.x() = " << p.x() << std::endl; std::cout << "p.y() = " << p.y() << std::endl; std::cout << "p.z() = " << p.z() << std::endl; } std::cout << std::endl; // ------------------------------------------------- // traverse the edges // ------------------------------------------------- std::cout << "Iterating over the edges.... " << std::endl; n=0; for (Polyhedron::Edge_iterator ei = P.edges_begin(); ei != P.edges_end(); ++ei) { ei->next(); Kernel::Point_3 p; p = ei->vertex()->point(); std::cout << "For edge index: " << n++ << std::endl; std::cout << "p.x() = " << p.x() << std::endl; std::cout << "p.y() = " << p.y() << std::endl; std::cout << "p.z() = " << p.z() << std::endl; } std::cout << std::endl; // ----------------------------------------------- // Do something else with the edge iterators // ----------------------------------------------- Polyhedron::Edge_iterator e = P.edges_begin(); ++ last_e; // make it the past-the-end position again while ( e != last_e) { Polyhedron::Halfedge_handle h = e; ++e; }; CGAL_postcondition( P.is_valid()); }
// ---------------------------------------------------------------------------- // main() // ---------------------------------------------------------------------------- int main(int argc, char * argv[]) { std::cerr << "PARAMETERIZATION" << std::endl; std::cerr << " Discrete Authalic Parameterization" << std::endl; std::cerr << " Circular arclength border" << std::endl; std::cerr << " Eigen solver" << std::endl; std::cerr << " Very simple cut if model is not a topological disk" << std::endl; std::cerr << " Output: EPS" << std::endl; //*************************************** // decode parameters //*************************************** if (argc-1 != 2) { std::cerr << "Usage: " << argv[0] << " input_file.off output_file.eps" << std::endl; return(EXIT_FAILURE); } // File names are: const char* input_filename = argv[1]; const char* output_filename = argv[2]; //*************************************** // Read the mesh //*************************************** // Read the mesh std::ifstream stream(input_filename); Polyhedron mesh; stream >> mesh; if(!stream || !mesh.is_valid() || mesh.empty()) { std::cerr << "Error: cannot read OFF file " << input_filename << std::endl; return EXIT_FAILURE; } //*************************************** // Create Polyhedron adaptor //*************************************** Parameterization_polyhedron_adaptor mesh_adaptor(mesh); //*************************************** // Virtually cut mesh //*************************************** // The parameterization methods support only meshes that // are topological disks => we need to compute a "cutting" of the mesh // that makes it homeomorphic to a disk Seam seam = cut_mesh(mesh_adaptor); if (seam.empty()) { std::cerr << "Input mesh not supported: the example cutting algorithm is too simple to cut this shape" << std::endl; return EXIT_FAILURE; } // Create a second adaptor that virtually "cuts" the mesh following the 'seam' path typedef CGAL::Parameterization_mesh_patch_3<Parameterization_polyhedron_adaptor> Mesh_patch_polyhedron; Mesh_patch_polyhedron mesh_patch(mesh_adaptor, seam.begin(), seam.end()); if (!mesh_patch.is_valid()) { std::cerr << "Input mesh not supported: non manifold shape or invalid cutting" << std::endl; return EXIT_FAILURE; } //*************************************** // Discrete Authalic Parameterization (square border) // with Eigen solver //*************************************** // Border parameterizer typedef CGAL::Circular_border_arc_length_parameterizer_3<Mesh_patch_polyhedron> Border_parameterizer; // Discrete Authalic Parameterization (square border) // with Eigen solver typedef CGAL::Discrete_authalic_parameterizer_3<Mesh_patch_polyhedron, Border_parameterizer> Parameterizer; Parameterizer::Error_code err = CGAL::parameterize(mesh_patch, Parameterizer()); switch(err) { case Parameterizer::OK: // Success break; case Parameterizer::ERROR_EMPTY_MESH: // Input mesh not supported case Parameterizer::ERROR_NON_TRIANGULAR_MESH: case Parameterizer::ERROR_NO_TOPOLOGICAL_DISC: case Parameterizer::ERROR_BORDER_TOO_SHORT: std::cerr << "Input mesh not supported: " << Parameterizer::get_error_message(err) << std::endl; return EXIT_FAILURE; break; default: // Error std::cerr << "Error: " << Parameterizer::get_error_message(err) << std::endl; return EXIT_FAILURE; break; }; //*************************************** // Output //*************************************** // Write Postscript file if ( ! write_file_eps(mesh_adaptor, output_filename) ) { std::cerr << "Error: cannot write file " << output_filename << std::endl; return EXIT_FAILURE; } return EXIT_SUCCESS; }
int main() #endif { CGAL::Timer total_timer; total_timer.start(); std::cerr << "PARAMETERIZATION" << std::endl; //*************************************** // Read options on the command line //*************************************** std::string type; // default: Floater param std::string border; // default: circular border param. std::string solver; // default: OpenNL solver std::string input; // required std::string output; // default: out.eps try { #ifdef CGAL_USE_BOOST_PROGRAM_OPTIONS po::options_description desc("Allowed options"); desc.add_options() ("help,h", "prints this help message") ("type,t", po::value<std::string>(&type)->default_value("floater"), "parameterization method: floater, conformal, barycentric, authalic or lscm") ("border,b", po::value<std::string>(&border)->default_value("circle"), "border shape: circle, square or 2pts (lscm only)") ("solver,s", po::value<std::string>(&solver)->default_value("opennl"), "solver: opennl") ("input,i", po::value<std::string>(&input)->default_value(""), "input mesh (OFF)") ("output,o", po::value<std::string>(&output)->default_value("out.eps"), "output file (EPS or OBJ)") ; po::positional_options_description p; p.add("input", 1); p.add("output", 1); po::variables_map vm; po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), vm); po::notify(vm); if (vm.count("help")) { std::cout << desc << "\n"; return 1; } #else std::cerr << "Command-line options require Boost.ProgramOptions" << std::endl; std::cerr << "Use hard-coded options" << std::endl; border = "square"; type = "floater"; solver = "opennl"; input = "data/rotor.off"; output = "rotor_floater_square_opennl_parameterized.obj"; #endif } catch(std::exception& e) { std::cerr << "error: " << e.what() << "\n"; return 1; } catch(...) { std::cerr << "Exception of unknown type!\n"; throw; } //*************************************** // Read the mesh //*************************************** CGAL::Timer task_timer; task_timer.start(); // Read the mesh std::ifstream stream(input.c_str()); Polyhedron mesh; stream >> mesh; if(!stream || !mesh.is_valid() || mesh.empty()) { std::cerr << "Error: cannot read OFF file " << input << std::endl; return EXIT_FAILURE; } std::cerr << "Read file " << input << ": " << task_timer.time() << " seconds " << "(" << mesh.size_of_facets() << " facets, " << mesh.size_of_vertices() << " vertices)" << std::endl; task_timer.reset(); //*************************************** // Create mesh adaptor //*************************************** // The Surface_mesh_parameterization package needs an adaptor to handle Polyhedron_ex meshes Parameterization_polyhedron_adaptor mesh_adaptor(mesh); // The parameterization methods support only meshes that // are topological disks => we need to compute a cutting path // that makes the mesh a "virtual" topological disk // // 1) Cut the mesh Seam seam = cut_mesh(mesh_adaptor); if (seam.empty()) { std::cerr << "Input mesh not supported: the example cutting algorithm is too simple to cut this shape" << std::endl; return EXIT_FAILURE; } // // 2) Create adaptor that virtually "cuts" a patch in a Polyhedron_ex mesh Mesh_patch_polyhedron mesh_patch(mesh_adaptor, seam.begin(), seam.end()); if (!mesh_patch.is_valid()) { std::cerr << "Input mesh not supported: non manifold shape or invalid cutting" << std::endl; return EXIT_FAILURE; } std::cerr << "Mesh cutting: " << task_timer.time() << " seconds." << std::endl; task_timer.reset(); //*************************************** // switch parameterization //*************************************** std::cerr << "Parameterization..." << std::endl; // Defines the error codes typedef CGAL::Parameterizer_traits_3<Mesh_patch_polyhedron> Parameterizer; Parameterizer::Error_code err; if (solver == std::string("opennl")) { err = parameterize<Mesh_patch_polyhedron, OpenNL::DefaultLinearSolverTraits<double>, OpenNL::SymmetricLinearSolverTraits<double> >(mesh_patch, type, border); } else { std::cerr << "Error: invalid solver parameter " << solver << std::endl; err = Parameterizer::ERROR_WRONG_PARAMETER; } // Report errors switch(err) { case Parameterizer::OK: // Success break; case Parameterizer::ERROR_EMPTY_MESH: // Input mesh not supported case Parameterizer::ERROR_NON_TRIANGULAR_MESH: case Parameterizer::ERROR_NO_TOPOLOGICAL_DISC: case Parameterizer::ERROR_BORDER_TOO_SHORT: std::cerr << "Input mesh not supported: " << Parameterizer::get_error_message(err) << std::endl; return EXIT_FAILURE; break; default: // Error std::cerr << "Error: " << Parameterizer::get_error_message(err) << std::endl; return EXIT_FAILURE; break; }; std::cerr << "Parameterization: " << task_timer.time() << " seconds." << std::endl; task_timer.reset(); //*************************************** // Output //*************************************** // get output file's extension std::string extension = output.substr(output.find_last_of('.')); // Save mesh if (extension == ".eps" || extension == ".EPS") { // write Postscript file if ( ! mesh.write_file_eps(output.c_str()) ) { std::cerr << "Error: cannot write file " << output << std::endl; return EXIT_FAILURE; } } else if (extension == ".obj" || extension == ".OBJ") { // write Wavefront obj file if ( ! mesh.write_file_obj(output.c_str()) ) { std::cerr << "Error: cannot write file " << output << std::endl; return EXIT_FAILURE; } } else { std::cerr << "Error: output format not supported" << output << std::endl; err = Parameterizer::ERROR_WRONG_PARAMETER; return EXIT_FAILURE; } std::cerr << "Write file " << output << ": " << task_timer.time() << " seconds " << std::endl; return EXIT_SUCCESS; }
int main(int argc, char * argv[]) { std::cerr << "PARAMETERIZATION" << std::endl; std::cerr << " Floater parameterization" << std::endl; std::cerr << " Circle border" << std::endl; std::cerr << " OpenNL solver" << std::endl; std::cerr << " Very simple cut if model is not a topological disk" << std::endl; //*************************************** // decode parameters //*************************************** if (argc-1 != 1) { std::cerr << "Usage: " << argv[0] << " input_file.off" << std::endl; return(EXIT_FAILURE); } // File name is: const char* input_filename = argv[1]; //*************************************** // Read the mesh //*************************************** // Read the mesh std::ifstream stream(input_filename); Polyhedron mesh; stream >> mesh; if(!stream || !mesh.is_valid() || mesh.empty()) { std::cerr << "Error: cannot read OFF file " << input_filename << std::endl; return EXIT_FAILURE; } //*************************************** // Create Polyhedron adaptor //*************************************** Parameterization_polyhedron_adaptor mesh_adaptor(mesh); //*************************************** // Virtually cut mesh //*************************************** // The parameterization methods support only meshes that // are topological disks => we need to compute a "cutting" of the mesh // that makes it homeomorphic to a disk Seam seam = cut_mesh(mesh_adaptor); if (seam.empty()) { std::cerr << "Input mesh not supported: the example cutting algorithm is too simple to cut this shape" << std::endl; return EXIT_FAILURE; } // Create a second adaptor that virtually "cuts" the mesh following the 'seam' path typedef CGAL::Parameterization_mesh_patch_3<Parameterization_polyhedron_adaptor> Mesh_patch_polyhedron; Mesh_patch_polyhedron mesh_patch(mesh_adaptor, seam.begin(), seam.end()); if (!mesh_patch.is_valid()) { std::cerr << "Input mesh not supported: non manifold shape or invalid cutting" << std::endl; return EXIT_FAILURE; } //*************************************** // Floater Mean Value Coordinates parameterization //*************************************** typedef CGAL::Parameterizer_traits_3<Mesh_patch_polyhedron> Parameterizer; // Type that defines the error codes Parameterizer::Error_code err = CGAL::parameterize(mesh_patch); switch(err) { case Parameterizer::OK: // Success break; case Parameterizer::ERROR_EMPTY_MESH: // Input mesh not supported case Parameterizer::ERROR_NON_TRIANGULAR_MESH: case Parameterizer::ERROR_NO_TOPOLOGICAL_DISC: case Parameterizer::ERROR_BORDER_TOO_SHORT: std::cerr << "Input mesh not supported: " << Parameterizer::get_error_message(err) << std::endl; return EXIT_FAILURE; break; default: // Error std::cerr << "Error: " << Parameterizer::get_error_message(err) << std::endl; return EXIT_FAILURE; break; }; //*************************************** // Output //*************************************** // Raw output: dump (u,v) pairs Polyhedron::Vertex_const_iterator pVertex; for (pVertex = mesh.vertices_begin(); pVertex != mesh.vertices_end(); pVertex++) { // (u,v) pair is stored in any halfedge double u = mesh_adaptor.info(pVertex->halfedge())->uv().x(); double v = mesh_adaptor.info(pVertex->halfedge())->uv().y(); std::cout << "(u,v) = (" << u << "," << v << ")" << std::endl; } return EXIT_SUCCESS; }
TrianglesList meshSimplification(TrianglesList &triangles, int stopPredicate) { #ifdef MESHSIMPLIFICATION_LOG CGAL::Timer timer; timer.start(); #endif TrianglesList result; try { Polyhedron P; #ifdef MESHSIMPLIFICATION_LOG std::cout << "Start Building Polyhedron surface... " << std::endl; #endif Build_triangle_mesh_coherent_surface<HalfedgeDS> triangle(triangles); P.delegate(triangle); P.normalize_border(); #ifdef MESHSIMPLIFICATION_LOG std::cout << "Completed Building Polyhedron surface:" << std::endl; std::cout << "Polyhedron is_pure_triangle: " << P.is_pure_triangle() << std::endl; std::cout << "Polyhedron is_closed: " << P.is_closed() << std::endl; std::cout << "Polyhedron is_pure_bivalent : " << P.is_pure_bivalent () << std::endl; std::cout << "Polyhedron is_pure_trivalent: " << P.is_pure_trivalent() << std::endl; std::cout << "Polyhedron is_valid 0: " << P.is_valid(false, 0) << std::endl; std::cout << "Polyhedron is_valid 1: " << P.is_valid(false, 1) << std::endl; std::cout << "Polyhedron is_valid 2: " << P.is_valid(false, 2) << std::endl; std::cout << "Polyhedron is_valid 3: " << P.is_valid(false, 3) << std::endl; std::cout << "Polyhedron is_valid 4: " << P.is_valid(false, 4) << std::endl; std::cout << "Polyhedron normalized_border_is_valid : " << P.normalized_border_is_valid(false) << std::endl; #endif #ifdef MESHSIMPLIFICATION_LOG std::cout << "Start edge_collapse... " << std::endl; #endif SMS::Count_stop_predicate<Polyhedron> stop(stopPredicate); int removedEdges = SMS::edge_collapse(P, stop, CGAL::vertex_index_map(boost::get(CGAL::vertex_external_index, P)).edge_index_map(boost::get(CGAL::edge_external_index ,P)) ); #ifdef MESHSIMPLIFICATION_LOG std::cout << "Completed edge_collapse:" << std::endl; std::cout << "Finished with: " << removedEdges << " edges removed and " << (P.size_of_halfedges()/2) << " final edges." << std::endl; #endif //Build output result for ( Polyhedron::Facet_iterator fit( P.facets_begin() ), fend( P.facets_end() ); fit != fend; ++fit ) { if ( fit->is_triangle() ) { PointCGAL verts[3]; int tick = 0; Polyhedron::Halfedge_around_facet_circulator hit( fit->facet_begin() ), hend( hit ); do { if ( tick < 3 ) { verts[tick++] = PointCGAL( hit->vertex()->point().x(), hit->vertex()->point().y(), hit->vertex()->point().z() ); } else { std::cout << "meshSimplification: We've got facets with more than 3 vertices even though the facet reported to be triangular..." << std::endl; } } while( ++hit != hend ); result.push_back( Triangle(verts[0], verts[1], verts[2]) ); } else { std::cout << "meshSimplification: Skipping non-triangular facet" << std::endl; } } } catch (CGAL::Assertion_exception e) { std::cout << "ERROR: meshSimplification CGAL::Assertion_exception" << e.message() << std::endl; } #ifdef MESHSIMPLIFICATION_LOG timer.stop(); std::cout << "meshSimplification result with: " << result.size() << " triangles." << std::endl; std::cout << "Total meshSimplification time: " << timer.time() << std::endl; #endif return result; }