// If the mesh is a topological disk, extract its longest border, // else compute a very simple cut to make it homeomorphic to a disk. // Return the border of this region (empty on error) // // CAUTION: this cutting algorithm is very naive. Write your own! static Seam cut_mesh(Parameterization_polyhedron_adaptor& mesh_adaptor) { // Helper class to compute genus or extract borders typedef CGAL::Parameterization_mesh_feature_extractor<Parameterization_polyhedron_adaptor> Mesh_feature_extractor; Seam seam; // returned list // Get reference to Polyhedron_3 mesh Polyhedron& mesh = mesh_adaptor.get_adapted_mesh(); // Extract mesh borders and compute genus Mesh_feature_extractor feature_extractor(mesh_adaptor); int nb_borders = feature_extractor.get_nb_borders(); int genus = feature_extractor.get_genus(); // If mesh is a topological disk if (genus == 0 && nb_borders > 0) { // Pick the longest border seam = feature_extractor.get_longest_border(); } else // if mesh is *not* a topological disk, create a virtual cut { const int CUT_LENGTH = 6; // Build consecutive halfedges array Polyhedron::Halfedge_handle seam_halfedges[CUT_LENGTH]; seam_halfedges[0] = mesh.halfedges_begin(); if (seam_halfedges[0] == NULL) return seam; // return empty list int i; for (i=1; i<CUT_LENGTH; i++) { seam_halfedges[i] = seam_halfedges[i-1]->next()->opposite()->next(); if (seam_halfedges[i] == NULL) return seam; // return empty list } // Convert halfedges array to two-ways vertices list for (i=0; i<CUT_LENGTH; i++) seam.push_back(seam_halfedges[i]->vertex()); for (i=CUT_LENGTH-1; i>=0; i--) seam.push_back(seam_halfedges[i]->opposite()->vertex()); } return seam; }
// Cut the mesh to make it homeomorphic to a disk // or extract a region homeomorphic to a disc. // Return the border of this region (empty on error) // // CAUTION: // This method is provided "as is". It is very buggy and simply part of this example. // Developers using this package should implement a more robust cut algorithm! static Seam cut_mesh(Parameterization_polyhedron_adaptor& mesh_adaptor) { // Helper class to compute genus or extract borders typedef CGAL::Parameterization_mesh_feature_extractor<Parameterization_polyhedron_adaptor_ex> Mesh_feature_extractor; typedef Mesh_cutter::Backbone Backbone; Seam seam; // returned list // Get refererence to Polyhedron_3 mesh Polyhedron& mesh = mesh_adaptor.get_adapted_mesh(); // Extract mesh borders and compute genus Mesh_feature_extractor feature_extractor(mesh_adaptor); int nb_borders = feature_extractor.get_nb_borders(); int genus = feature_extractor.get_genus(); // If mesh is a topological disk if (genus == 0 && nb_borders > 0) { // Pick the longest border seam = feature_extractor.get_longest_border(); } else // if mesh is *not* a topological disk, create a virtual cut { Backbone seamingBackbone; // result of cutting Backbone::iterator he; // Compute a cutting path that makes the mesh a "virtual" topological disk mesh.compute_facet_centers(); Mesh_cutter cutter(mesh); if (genus == 0) { // no border, we need to cut the mesh assert (nb_borders == 0); cutter.cut(seamingBackbone); // simple cut } else // genus > 0 -> cut the mesh { cutter.cut_genus(seamingBackbone); } // The Mesh_cutter class is quite buggy // => we check that seamingBackbone is valid // // 1) Check that seamingBackbone is not empty if (seamingBackbone.begin() == seamingBackbone.end()) return seam; // return empty list // // 2) Check that seamingBackbone is a loop and // count occurences of seam halfedges mesh.tag_halfedges(0); // Reset counters for (he = seamingBackbone.begin(); he != seamingBackbone.end(); he++) { // Get next halfedge iterator (looping) Backbone::iterator next_he = he; next_he++; if (next_he == seamingBackbone.end()) next_he = seamingBackbone.begin(); // Check that seamingBackbone is a loop: check that // end of current HE == start of next one if ((*he)->vertex() != (*next_he)->opposite()->vertex()) return seam; // return empty list // Increment counter (in "tag" field) of seam halfedges (*he)->tag( (*he)->tag()+1 ); } // // 3) check that the seamingBackbone is a two-way list for (he = seamingBackbone.begin(); he != seamingBackbone.end(); he++) { // Counter of halfedge and opposite halfedge must be 1 if ((*he)->tag() != 1 || (*he)->opposite()->tag() != 1) return seam; // return empty list } // Convert list of halfedges to a list of vertices for (he = seamingBackbone.begin(); he != seamingBackbone.end(); he++) seam.push_back((*he)->vertex()); } return seam; }