diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/compute_normal.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/compute_normal.h index cf4c8ca2e15..85153072ad9 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/compute_normal.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/compute_normal.h @@ -115,7 +115,10 @@ compute_face_normal(typename boost::graph_traits::face_descriptor f sum_normals(pmesh, f , choose_const_pmap(get_param(np, CGAL::vertex_point), pmesh, CGAL::vertex_point) , normal); - + + if (normal == CGAL::NULL_VECTOR) + return normal; + else return normal / FT( std::sqrt( to_double(normal * normal) ) ); } @@ -223,6 +226,9 @@ compute_vertex_normal(typename boost::graph_traits::vertex_descript he = opposite(next(he, pmesh), pmesh); } while (he != end); + if (normal == CGAL::NULL_VECTOR) + return normal; + else return normal / FT( std::sqrt( to_double(normal * normal) ) ); } diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/remesh_impl.h index 1d77f283dc0..684cc59a7d4 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/remesh_impl.h @@ -677,8 +677,7 @@ namespace internal { void equalize_valences() { #ifdef CGAL_PMP_REMESHING_VERBOSE - std::cout << "Equalize valences..."; - std::cout.flush(); + std::cout << "Equalize valences..." << std::endl; #endif unsigned int nb_flips = 0; BOOST_FOREACH(edge_descriptor e, edges(mesh_)) @@ -700,12 +699,14 @@ namespace internal { CGAL_assertion_code(Halfedge_status s1 = status(he)); CGAL_assertion_code(Halfedge_status s1o = status(opposite(he, mesh_))); - CGAL_assertion(!incident_to_degenerate(he)); - CGAL_assertion(!incident_to_degenerate(opposite(he, mesh_))); CGAL::Euler::flip_edge(he, mesh_); ++nb_flips; - + +#ifdef CGAL_PMP_REMESHING_VERBOSE + std::cout << "\r\t(" << nb_flips << " flips)"; + std::cout.flush(); +#endif CGAL_assertion_code(Halfedge_status s2 = status(he)); CGAL_assertion_code(Halfedge_status s2o = status(opposite(he, mesh_))); CGAL_assertion(s1 == s2 && s1 == PATCH); @@ -746,7 +747,7 @@ namespace internal { } #ifdef CGAL_PMP_REMESHING_VERBOSE - std::cout << "done. ("<< nb_flips << " flips)" << std::endl; + std::cout << "\r\tdone ("<< nb_flips << " flips)" << std::endl; #endif #ifdef CGAL_PMP_REMESHING_DEBUG @@ -894,7 +895,7 @@ namespace internal { BOOST_FOREACH(vertex_descriptor v, vertices(mesh_)) { - if (!is_on_patch(v) && !is_constrained(v)) + if (!is_on_patch(v) || is_constrained(v)) continue; //note if v is constrained, it has not moved @@ -1295,12 +1296,15 @@ private: halfedge_descriptor h = *(degenerate_faces.begin()); degenerate_faces.erase(degenerate_faces.begin()); + if (!PMP::is_degenerated(h, mesh_, vpmap_, GeomTraits())) + //this can happen when flipping h has consequences further in the mesh + continue; + //check that opposite is not also degenerate if (degenerate_faces.find(opposite(h, mesh_)) != degenerate_faces.end()) degenerate_faces.erase(opposite(h, mesh_)); - CGAL_assertion(PMP::is_degenerated(h, mesh_, vpmap_, GeomTraits())); - if (face(h, mesh_) == boost::graph_traits::null_face()) + if(is_border(h, mesh_)) continue; BOOST_FOREACH(halfedge_descriptor hf, @@ -1343,7 +1347,6 @@ private: short_edges.insert(typename Bimap::value_type(hf, sqlen)); } - std::size_t nb_degen = degenerate_faces.size(); if (!is_border(hf, mesh_) && PMP::is_degenerated(hf, mesh_, vpmap_, GeomTraits())) degenerate_faces.insert(hf); @@ -1351,14 +1354,6 @@ private: && PMP::is_degenerated(hfo, mesh_, vpmap_, GeomTraits())) degenerate_faces.insert(hfo); - if (degenerate_faces.size() == nb_degen + 2) - { - //process has failed to remove degeneracies - degenerate_faces.erase(hf); - degenerate_faces.erase(hfo); - std::cerr << "Warning : possible degeneracies remaining " - << "after the edge collapse step" << std::endl; - } break; } } diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp index 5557a588dc7..8dde390d21e 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp @@ -98,18 +98,44 @@ void test_precondition(const char* filename, struct halfedge2edge { - halfedge2edge(const Mesh& m, std::vector& edges) + halfedge2edge(const Mesh& m, std::set& edges) : m_mesh(m), m_edges(edges) {} void operator()(const halfedge_descriptor& h) const { - m_edges.push_back(edge(h, m_mesh)); + m_edges.insert(edge(h, m_mesh)); } const Mesh& m_mesh; - std::vector& m_edges; + std::set& m_edges; }; +struct Constraints_pmap +{ + std::set* set_ptr_; + + typedef edge_descriptor key_type; + typedef bool value_type; + typedef value_type& reference; + typedef boost::read_write_property_map_tag category; + +public: + Constraints_pmap(std::set* set_ptr) + : set_ptr_(set_ptr) + {} + friend bool get(const Constraints_pmap& map, const edge_descriptor& e) + { + CGAL_assertion(map.set_ptr_ != NULL); + return map.set_ptr_->count(e) != 0; + } + friend void put(Constraints_pmap& map, const edge_descriptor& e, const bool is) + { + CGAL_assertion(map.set_ptr_ != NULL); + if (is) map.set_ptr_->insert(e); + else if(get(map, e)) map.set_ptr_->erase(e); + } +}; + int main(int argc, char* argv[]) { #ifdef CGAL_PMP_REMESHING_DEBUG @@ -148,37 +174,47 @@ int main(int argc, char* argv[]) std::cout << "OK." << std::endl; std::cout << "Split border..."; - - std::vector border; + std::set border; + Constraints_pmap ecmap(&border); PMP::border_halfedges(pre_patch, m, boost::make_function_output_iterator(halfedge2edge(m, border))); - PMP::split_long_edges(border, target_edge_length, m); - + PMP::split_long_edges(border, target_edge_length, m + , PMP::parameters::edge_is_constrained_map(ecmap)); std::cout << "done." << std::endl; - //std::cout << "Start remeshing of " << selection_file - // << " (" << patch.size() << " faces)..." << std::endl; + std::cout << "Collect patch..."; + std::vector patch; + face_descriptor seed = face(halfedge(*border.begin(), m), m); + if (is_border(halfedge(*border.begin(), m), m)) + seed = face(opposite(halfedge(*border.begin(), m), m), m); + PMP::connected_component(seed, m, std::back_inserter(patch), + PMP::parameters::edge_is_constrained_map(ecmap)); + std::cout << " done." << std::endl; + + std::cout << "Start remeshing of " << selection_file + << " (" << patch.size() << " faces)..." << std::endl; CGAL::Timer t; - //t.start(); + t.start(); - //PMP::isotropic_remeshing( - // patch, - // target_edge_length, - // m, - // PMP::parameters::number_of_iterations(nb_iter) - // .protect_constraints(false) - // ); - //t.stop(); - //std::cout << "Remeshing patch took " << t.time() << std::endl; + PMP::isotropic_remeshing( + patch, + target_edge_length, + m, + PMP::parameters::number_of_iterations(nb_iter) + .protect_constraints(false) + ); + t.stop(); + std::cout << "Remeshing patch took " << t.time() << std::endl; + t.reset(); t.start(); PMP::isotropic_remeshing(faces(m), 2.*target_edge_length, m, PMP::parameters::number_of_iterations(nb_iter) - .protect_constraints(true) //they have been refined by previous remeshing + .protect_constraints(true) //only borders. they have been refined by previous remeshing ); t.stop(); std::cout << "Remeshing all took " << t.time() << std::endl;