From 510a041aede2344e2ce67be9f0a650d0989c93c3 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Fri, 26 May 2017 14:33:59 +0300 Subject: [PATCH 001/102] setup simple example for basic angle smoothing --- .../Polygon_mesh_processing/CMakeLists.txt | 2 + .../angle_smoothing_example.cpp | 36 ++++++++ .../Polygon_mesh_processing/angle_smoothing.h | 89 +++++++++++++++++++ 3 files changed, 127 insertions(+) create mode 100644 Polygon_mesh_processing/examples/Polygon_mesh_processing/angle_smoothing_example.cpp create mode 100644 Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt index 8560602f720..f2025c727c5 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt @@ -34,6 +34,7 @@ include( ${CGAL_USE_FILE} ) # Boost and its components +set(BOOST_ROOT "/home/kon/Libs/build-boost") find_package( Boost REQUIRED ) if ( NOT Boost_FOUND ) @@ -101,6 +102,7 @@ create_single_source_cgal_program( "corefinement_consecutive_bool_op.cpp" ) create_single_source_cgal_program( "corefinement_difference_remeshed.cpp" ) create_single_source_cgal_program( "corefinement_mesh_union.cpp" ) create_single_source_cgal_program( "corefinement_polyhedron_union.cpp" ) +create_single_source_cgal_program( "angle_smoothing_example.cpp") if(OpenMesh_FOUND) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/angle_smoothing_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/angle_smoothing_example.cpp new file mode 100644 index 00000000000..775682e3ef4 --- /dev/null +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/angle_smoothing_example.cpp @@ -0,0 +1,36 @@ +#include +#include + +#include +#include + +#include + + +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; +typedef CGAL::Surface_mesh Mesh; + + +int main(int argc, char* argv[]){ + + + std::cout<<"hello\n"; + + const char* filename = "data/polygon.off"; + std::ifstream input(filename); + + Mesh mesh; + if (!input || !(input >> mesh) || mesh.is_empty()) { + std::cerr << "Not a valid .off file." << std::endl; + return 1; + } + + + CGAL::Polygon_mesh_processing::Angle_remesher remesher(mesh); + remesher.angle_relaxation(); + + + + + return 0; +} diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h new file mode 100644 index 00000000000..a86987aca20 --- /dev/null +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h @@ -0,0 +1,89 @@ +#ifndef ANGLE_SMOOTHING_H +#define ANGLE_SMOOTHING_H + + +#include +#include +#include + +//#include +#include + + +namespace CGAL { + +namespace Polygon_mesh_processing { + + + +template +class Angle_remesher +{ + + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + + +public: + Angle_remesher(PolygonMesh& pmesh) : mesh_(pmesh) + {} + + + + + void angle_relaxation() + { + + BOOST_FOREACH(vertex_descriptor v, vertices(mesh_)) + { + + if(!is_border(v, mesh_)) + { + std::cout<<"vertex inside: "; + std::cout<< v << std::endl; + } + + } + + + } + + + + + + +private: + PolygonMesh& mesh_; + +}; + + + + + + + + + + + + + + + + + + + + + +} // namespace Polygon_mesh_processing +} //namespace CGAL + + + + + + +#endif // ANGLE_SMOOTHING_H From f14c28d9334a64042c58ed29ecf117cc5782238c Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Fri, 26 May 2017 14:40:54 +0300 Subject: [PATCH 002/102] typo --- .../examples/Polygon_mesh_processing/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt index f2025c727c5..86737fcf46f 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt @@ -34,7 +34,6 @@ include( ${CGAL_USE_FILE} ) # Boost and its components -set(BOOST_ROOT "/home/kon/Libs/build-boost") find_package( Boost REQUIRED ) if ( NOT Boost_FOUND ) From 992a37e7be2baee09eaa5af1fca73c9d53147f92 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Sun, 28 May 2017 21:52:55 +0300 Subject: [PATCH 003/102] angle bisection --- .../angle_smoothing_example.cpp | 3 + .../Polygon_mesh_processing/angle_smoothing.h | 72 ++++++++++++++++++- 2 files changed, 72 insertions(+), 3 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/angle_smoothing_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/angle_smoothing_example.cpp index 775682e3ef4..4dd2e750d19 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/angle_smoothing_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/angle_smoothing_example.cpp @@ -11,6 +11,7 @@ typedef CGAL::Exact_predicates_inexact_constructions_kernel K; typedef CGAL::Surface_mesh Mesh; + int main(int argc, char* argv[]){ @@ -26,6 +27,8 @@ int main(int argc, char* argv[]){ } + + CGAL::Polygon_mesh_processing::Angle_remesher remesher(mesh); remesher.angle_relaxation(); diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h index a86987aca20..1e8daf2e5ba 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h @@ -1,13 +1,20 @@ #ifndef ANGLE_SMOOTHING_H #define ANGLE_SMOOTHING_H +#include #include #include #include +#include +#include +#include +#include //#include -#include +//#include + + namespace CGAL { @@ -23,6 +30,15 @@ class Angle_remesher typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef CGAL::Halfedge_around_source_iterator halfedge_around_source_iterator; + + typedef CGAL::Line_2 Line; + typedef CGAL::Point_2 Point; + + + + + public: Angle_remesher(PolygonMesh& pmesh) : mesh_(pmesh) @@ -39,8 +55,38 @@ public: if(!is_border(v, mesh_)) { - std::cout<<"vertex inside: "; - std::cout<< v << std::endl; + std::cout<<"processing vertex: "<< v << std::endl; + + // gather lines adjacent to angles + halfedge_around_source_iterator hi, he; + halfedge_descriptor hnext; + std::vector he_lines; //lines stored here + for(boost::tie(hi, he) = halfedges_around_source(v, mesh_); hi != he; ++hi) + { + hnext = next(*hi, mesh_); + he_lines.push_back(hnext); //TODO: avoid push_back + } + + // take a look + vertex_descriptor vs, vt; + for(int i=0; i #include #include #include #include -#include -#include -#include - -//#include -//#include +#include +#include namespace CGAL { @@ -23,25 +18,23 @@ namespace Polygon_mesh_processing { -template + + +template class Angle_remesher { typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - typedef CGAL::Halfedge_around_source_iterator halfedge_around_source_iterator; - typedef CGAL::Line_2 Line; - typedef CGAL::Point_2 Point; - - - + typedef typename GeomTraits::Point_3 Point; + typedef typename GeomTraits::Vector_3 Vector; public: - Angle_remesher(PolygonMesh& pmesh) : mesh_(pmesh) + Angle_remesher(PolygonMesh& pmesh, VertexPointMap& vpmap) : mesh_(pmesh), vpmap_(vpmap) {} @@ -50,6 +43,8 @@ public: void angle_relaxation() { + std::map barycenters; + BOOST_FOREACH(vertex_descriptor v, vertices(mesh_)) { @@ -57,41 +52,84 @@ public: { std::cout<<"processing vertex: "<< v << std::endl; - // gather lines adjacent to angles - halfedge_around_source_iterator hi, he; - halfedge_descriptor hnext; - std::vector he_lines; //lines stored here - for(boost::tie(hi, he) = halfedges_around_source(v, mesh_); hi != he; ++hi) + // gather incident lines to a map + // > + typedef std::pair He_pair; + typedef std::map Edges_around_map; + Edges_around_map he_map; + + + for(halfedge_descriptor hi : halfedges_around_source(v, mesh_)) { - hnext = next(*hi, mesh_); - he_lines.push_back(hnext); //TODO: avoid push_back + he_map[hi] = He_pair(next(hi, mesh_), prev(opposite(hi, mesh_) ,mesh_)); + //std::cout<<"edges: "<second; + Point eq_d_p1 = get(vpmap_, target(he_pair.first, mesh_)); + Point eq_d_p2 = get(vpmap_, source(he_pair.second, mesh_)); + Point m = CGAL::midpoint(eq_d_p1, eq_d_p2); + + Point s = get(vpmap_, source(he_pair.first, mesh_)); + typename GeomTraits::Segment_3 bisector(s, m); + + // scale + halfedge_descriptor main_he = it->first; + double len = CGAL::sqrt(sqlength(main_he)); + typename GeomTraits::Aff_transformation_3 t_scale(CGAL::SCALING, len); + bisector = bisector.transform(t_scale); + + // translate + Vector vec(bisector.source(), s); + typename GeomTraits::Aff_transformation_3 t_translate(CGAL::TRANSLATION, vec); + bisector = bisector.transform(t_translate); + + move += Vector(bisector.target(), bisector.source()); + + } + + + barycenters[v] = get(vpmap_, v) + (move / (double)he_map.size()); + + + } // if is not on border + } // for each v - - - } - + // perform moves + typedef typename std::map::value_type VP; + for(const VP& vp : barycenters) + { + std::cout << "from: "<< get(vpmap_, vp.first); + put(vpmap_, vp.first, vp.second); + std::cout<<" moved at: "<< vp.second << std::endl; } + + + + + } @@ -101,23 +139,20 @@ public: private: PolygonMesh& mesh_; - //VertexPointMap& vpmap_; + VertexPointMap& vpmap_; - Line bisector(halfedge_descriptor h1, halfedge_descriptor h2) const - { - Line l1 (mesh_.point(source(h1, mesh_)), mesh_.point(target(h1, mesh_))); - Line l2 (mesh_.point(source(h2, mesh_)), mesh_.point(target(h2, mesh_))); - return CGAL::bisector(l1, l2); - } - - double sqlength(const vertex_descriptor& v1, const vertex_descriptor& v2) const { - // TO FIX with vpmap - //return to_double(CGAL::squared_distance(get(vpmap_, v1), get(vpmap_, v2))); - return to_double(CGAL::squared_distance(mesh_.point(v1), mesh_.point(v2))); + return to_double(CGAL::squared_distance(get(vpmap_, v1), get(vpmap_, v2))); + } + + double sqlength(const halfedge_descriptor& h) const + { + vertex_descriptor v1 = target(h, mesh_); + vertex_descriptor v2 = source(h, mesh_); + return sqlength(v1, v2); } @@ -132,9 +167,35 @@ private: +template +void angle_remeshing(PolygonMesh& pmesh, const NamedParameters& np) +{ + //CGAL_PMP_NP_CLASS np; + //np = CGAL::Polygon_mesh_processing::parameters::all_default(); + + using boost::choose_param; + using boost::get_param; + + typedef typename GetVertexPointMap::const_type VertexPointMap; + VertexPointMap vpmap = choose_param(get_param(np, internal_np::vertex_point), + get_const_property_map(CGAL::vertex_point, pmesh)); + + + typedef typename GetGeomTraits::type Traits; + + + CGAL::Polygon_mesh_processing::Angle_remesher remesher(pmesh, vpmap); + remesher.angle_relaxation(); + + + + +} + + From 62a1989a654968fcf503509a447a8b108928bb78 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Sun, 4 Jun 2017 17:46:31 +0300 Subject: [PATCH 005/102] project to tangent plane --- .../Polygon_mesh_processing/angle_smoothing.h | 78 +++++++++++++------ 1 file changed, 56 insertions(+), 22 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h index 3eb6115c1c2..4a04d02cc31 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h @@ -2,11 +2,7 @@ #define ANGLE_SMOOTHING_H -#include -#include -#include -#include - +#include #include #include @@ -31,6 +27,7 @@ class Angle_remesher typedef typename GeomTraits::Point_3 Point; typedef typename GeomTraits::Vector_3 Vector; + typedef typename GeomTraits::Segment_3 Segment; public: @@ -44,14 +41,27 @@ public: { std::map barycenters; + boost::vector_property_map n_map; - BOOST_FOREACH(vertex_descriptor v, vertices(mesh_)) + + for(vertex_descriptor v : vertices(mesh_)) { + if(!is_border(v, mesh_)) { std::cout<<"processing vertex: "<< v << std::endl; + + + // compute normal to v + Vector vn = compute_vertex_normal(v, mesh_, + Polygon_mesh_processing::parameters::vertex_point_map(vpmap_) + .geom_traits(GeomTraits())); + n_map[v] = vn; + + + // gather incident lines to a map // > typedef std::pair He_pair; @@ -82,42 +92,49 @@ public: for(it = he_map.begin(); it != he_map.end(); ++it) { - + // find midpoint He_pair he_pair = it->second; Point eq_d_p1 = get(vpmap_, target(he_pair.first, mesh_)); Point eq_d_p2 = get(vpmap_, source(he_pair.second, mesh_)); Point m = CGAL::midpoint(eq_d_p1, eq_d_p2); - Point s = get(vpmap_, source(he_pair.first, mesh_)); + // get common vertex around which the edge is rotated + halfedge_descriptor main_he = it->first; + Point s = get(vpmap_, target(main_he, mesh_)); + + // create segment which bisects angle typename GeomTraits::Segment_3 bisector(s, m); - // scale - halfedge_descriptor main_he = it->first; - double len = CGAL::sqrt(sqlength(main_he)); - typename GeomTraits::Aff_transformation_3 t_scale(CGAL::SCALING, len); - bisector = bisector.transform(t_scale); - - // translate - Vector vec(bisector.source(), s); - typename GeomTraits::Aff_transformation_3 t_translate(CGAL::TRANSLATION, vec); - bisector = bisector.transform(t_translate); + // correct segment position and length + correct_position(bisector, main_he); move += Vector(bisector.target(), bisector.source()); } - barycenters[v] = get(vpmap_, v) + (move / (double)he_map.size()); - } // if is not on border + } // not on border } // for each v - // perform moves + // compute locations to tangent plane typedef typename std::map::value_type VP; - for(const VP& vp : barycenters) + std::map new_locations; + for(const VP& vp: barycenters) + { + Point q = vp.second; + Point p = get(vpmap_, vp.first); + Vector n = n_map[vp.first]; + + new_locations[vp.first] = q + ( n * Vector(q, p) ) * n ; + } + + + // perform moves + for(const VP& vp : new_locations) { std::cout << "from: "<< get(vpmap_, vp.first); put(vpmap_, vp.first, vp.second); @@ -156,6 +173,23 @@ private: } + void correct_position(Segment& bisector, const halfedge_descriptor& he_c) + { + // common vertex + Point s = get(vpmap_, target(he_c, mesh_)); + + // scale + typename GeomTraits::Aff_transformation_3 t_scale(CGAL::SCALING, CGAL::sqrt(sqlength(he_c))); + bisector = bisector.transform(t_scale); + + // translate + Vector vec(bisector.source(), s); + typename GeomTraits::Aff_transformation_3 t_translate(CGAL::TRANSLATION, vec); + bisector = bisector.transform(t_translate); + + } + + }; From 1d5754ccf8c61f1f6d3815233b4f8834309d14b7 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Mon, 5 Jun 2017 10:55:59 +0300 Subject: [PATCH 006/102] fix scaling of bisector to correct length --- .../Polygon_mesh_processing/angle_smoothing.h | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h index 4a04d02cc31..58a8ef53357 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h @@ -83,7 +83,10 @@ public: halfedge_descriptor main_he = it->first; He_pair he_pair = it->second; std::cout<< "main: " << main_he; - std::cout<< " - incident: "<< he_pair.first <<" and " << he_pair.second <"<< target(he_pair.first, mesh_)<<")"; + std::cout<<" and " << he_pair.second; + std::cout<<" ("<"<< target(he_pair.second, mesh_)<<")"< Date: Tue, 6 Jun 2017 23:23:14 +0300 Subject: [PATCH 008/102] add on gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index cf6ea13ac18..739ad5e0c20 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ /*build* /*/*/*/build +/*/*/build* AABB_tree/demo/AABB_tree/AABB_demo AABB_tree/demo/AABB_tree/Makefile AABB_tree/examples/AABB_tree/*.kdev* From b66b27a1ae028cb688e9a60785573a6fe12f9fc3 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Sat, 10 Jun 2017 13:31:33 +0300 Subject: [PATCH 009/102] area smoothing 3D stable without projection --- .../area_smoothing_example.cpp | 42 +++ .../Polygon_mesh_processing/angle_smoothing.h | 2 +- .../Polygon_mesh_processing/area_smoothing.h | 331 ++++++++++++++++++ .../internal/parameters_interface.h | 1 + 4 files changed, 375 insertions(+), 1 deletion(-) create mode 100644 Polygon_mesh_processing/examples/Polygon_mesh_processing/area_smoothing_example.cpp create mode 100644 Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/area_smoothing.h diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/area_smoothing_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/area_smoothing_example.cpp new file mode 100644 index 00000000000..efa91957db4 --- /dev/null +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/area_smoothing_example.cpp @@ -0,0 +1,42 @@ +#include +#include + +#include +#include + +#include + + +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; +typedef CGAL::Surface_mesh Mesh; + + + +int main(int argc, char* argv[]){ + + + std::cout<<"hello\n"; + + const char* filename = "data/polygon.off"; + std::ifstream input(filename); + + Mesh mesh; + if (!input || !(input >> mesh) || mesh.is_empty()) { + std::cerr << "Not a valid .off file." << std::endl; + return 1; + } + + + + CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + + + + std::ofstream output("data/area_smoothed_polygon.off"); + output << mesh; + output.close(); + + + + return 0; +} diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h index 58a8ef53357..ee3aee82b8b 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h @@ -123,7 +123,7 @@ public: - // compute locations to tangent plane + // compute locations on tangent plane typedef typename std::map::value_type VP; std::map new_locations; for(const VP& vp: barycenters) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/area_smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/area_smoothing.h new file mode 100644 index 00000000000..9cb660982ec --- /dev/null +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/area_smoothing.h @@ -0,0 +1,331 @@ +#ifndef AREA_SMOOTHING_H +#define AREA_SMOOTHING_H + +#include + +#include +#include + +#include +#include +#include + + +namespace CGAL { + +namespace Polygon_mesh_processing { + + + + +template +class Area_remesher +{ + + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::face_descriptor face_descriptor; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + + typedef typename GeomTraits::Point_3 Point; + typedef typename GeomTraits::Vector_3 Vector; + + + typedef CGAL::AABB_face_graph_triangle_primitive Primitive; + typedef CGAL::AABB_traits Traits; + typedef CGAL::AABB_tree Tree; + + + +public: + Area_remesher(PolygonMesh& pmesh, VertexPointMap& vpmap) : mesh_(pmesh), vpmap_(vpmap) + {} + + + + + + + void area_relaxation() + { + + Tree tree(faces(mesh_).first, faces(mesh_).second, mesh_); + //tree.rebuild(faces(mesh_).first, faces(mesh_).second, mesh_);// + tree.accelerate_distance_queries(); + + + + for(vertex_descriptor v : vertices(mesh_)) + { + + if(!is_border(v, mesh_)) + { + std::cout<<"processing vertex: "<< v << std::endl; + + //std::cout<<"point moved from: "< precision || previous_step_size_y > precision || previous_step_size_z > precision) + { + + dFdx=0, dFdy=0, dFdz=0; + compute_derivatives(dFdx, dFdy, dFdz, v, S_av); + + x_new = x - eta * dFdx; + y_new = y - eta * dFdy; + z_new = z - eta * dFdz; + + + Point moved(x_new, y_new, z_new); + + //if(do_project) + //{ + // put(vpmap_, v, tree.closest_point(moved)); + //} + //else + //{ + put(vpmap_, v, moved); + //} + + + + previous_step_size_x = CGAL::abs(x_new - x); + previous_step_size_y = CGAL::abs(y_new - y); + previous_step_size_z = CGAL::abs(z_new - z); + //std::cout<<"previous_step_size_x: "< +void area_remeshing(PolygonMesh& pmesh, const NamedParameters& np) +{ + + + using boost::choose_param; + using boost::get_param; + + typedef typename GetVertexPointMap::const_type VertexPointMap; + VertexPointMap vpmap = choose_param(get_param(np, internal_np::vertex_point), + get_const_property_map(CGAL::vertex_point, pmesh)); + + + typedef typename GetGeomTraits::type GeomTraits; + + //bool do_project = choose_param(get_param(np, internal_np::do_project), true); + + + CGAL::Polygon_mesh_processing::Area_remesher remesher(pmesh, vpmap); + remesher.area_relaxation(); + + +} + + + + + + + + + + +} // namespace Polygon_mesh_processing +} //namespace CGAL + + + + + + + + +#endif // AREA_SMOOTHING_H + + diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/parameters_interface.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/parameters_interface.h index 8feab1527d8..9e2d3c20238 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/parameters_interface.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/parameters_interface.h @@ -46,6 +46,7 @@ CGAL_add_named_parameter(nb_points_per_area_unit_t, nb_points_per_area_unit, num CGAL_add_named_parameter(nb_points_per_distance_unit_t, nb_points_per_distance_unit, number_of_points_per_distance_unit) //to be documented CGAL_add_named_parameter(face_normal_t, face_normal, face_normal_map) +CGAL_add_named_parameter(do_project_t, do_project, do_project) //internal CGAL_add_named_parameter(weight_calculator_t, weight_calculator, weight_calculator) From 3ff37e0ff604c1a2f90d27ef9cbbaa49e329d1af Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Sun, 11 Jun 2017 23:24:17 +0300 Subject: [PATCH 010/102] project to surface with an Incremental remesher --- .../area_smoothing_example.cpp | 6 +- .../Polygon_mesh_processing/area_smoothing.h | 132 +++++++++++++++--- 2 files changed, 117 insertions(+), 21 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/area_smoothing_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/area_smoothing_example.cpp index efa91957db4..f4465d7d2f4 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/area_smoothing_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/area_smoothing_example.cpp @@ -17,7 +17,7 @@ int main(int argc, char* argv[]){ std::cout<<"hello\n"; - const char* filename = "data/polygon.off"; + const char* filename = "data/polygon3D.off"; std::ifstream input(filename); Mesh mesh; @@ -28,11 +28,11 @@ int main(int argc, char* argv[]){ - CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); - std::ofstream output("data/area_smoothed_polygon.off"); + std::ofstream output("data/area_smoothed_polygon3D.off"); output << mesh; output.close(); diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/area_smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/area_smoothing.h index 9cb660982ec..72bf3511ed7 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/area_smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/area_smoothing.h @@ -5,10 +5,17 @@ #include #include +//#include + #include #include -#include +#include +//#include + + +#include + namespace CGAL { @@ -18,6 +25,10 @@ namespace Polygon_mesh_processing { + + + + template class Area_remesher { @@ -28,11 +39,15 @@ class Area_remesher typedef typename GeomTraits::Point_3 Point; typedef typename GeomTraits::Vector_3 Vector; + typedef typename GeomTraits::Triangle_3 Triangle; + + + //typedef CGAL::AABB_face_graph_triangle_primitive Primitive; + //typedef CGAL::AABB_traits Traits; + //typedef CGAL::AABB_tree Tree; + - typedef CGAL::AABB_face_graph_triangle_primitive Primitive; - typedef CGAL::AABB_traits Traits; - typedef CGAL::AABB_tree Tree; @@ -44,13 +59,12 @@ public: - void area_relaxation() { - Tree tree(faces(mesh_).first, faces(mesh_).second, mesh_); + //Tree tree(faces(mesh_).first, faces(mesh_).second, mesh_); //tree.rebuild(faces(mesh_).first, faces(mesh_).second, mesh_);// - tree.accelerate_distance_queries(); + //tree.accelerate_distance_queries(); @@ -67,15 +81,15 @@ public: - std::cout<<"point before projection: "< -void area_remeshing(PolygonMesh& pmesh, const NamedParameters& np) + + + + + + + +template +void area_remeshing(PolygonMesh& pmesh, const NamedParameters& np, const FaceRange& faces) { @@ -298,13 +327,80 @@ void area_remeshing(PolygonMesh& pmesh, const NamedParameters& np) typedef typename GetGeomTraits::type GeomTraits; + //bool do_project = choose_param(get_param(np, internal_np::do_project), true); + + + //typedef PolygonMesh PM; + using PM = PolygonMesh; + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + using boost::get_param; + using boost::choose_param; + + + typedef typename GetGeomTraits::type GT; + + //typedef typename GetVertexPointMap::type VPMap; + //VPMap vpmap = choose_param(get_param(np, internal_np::vertex_point), + // get_property_map(vertex_point, pmesh)); + + typedef typename GetFaceIndexMap::type FIMap; + FIMap fimap = choose_param(get_param(np, internal_np::face_index), + get_property_map(face_index, pmesh)); + + typedef typename boost::lookup_named_param_def < + internal_np::edge_is_constrained_t, + NamedParameters, + internal::Border_constraint_pmap//default + > ::type ECMap; + ECMap ecmap = (boost::is_same >::value) + //avoid constructing the Border_constraint_pmap if it's not used + ? choose_param(get_param(np, internal_np::edge_is_constrained) + , internal::Border_constraint_pmap(pmesh, faces, fimap)) + : choose_param(get_param(np, internal_np::edge_is_constrained) + , internal::Border_constraint_pmap()); + + typedef typename boost::lookup_named_param_def < + internal_np::vertex_is_constrained_t, + NamedParameters, + internal::No_constraint_pmap//default + > ::type VCMap; + VCMap vcmap = choose_param(get_param(np, internal_np::vertex_is_constrained), + internal::No_constraint_pmap()); + + typedef typename boost::lookup_named_param_def < + internal_np::face_patch_t, + NamedParameters, + internal::Connected_components_pmap//default + > ::type FPMap; + FPMap fpmap = (boost::is_same >::value) + ? choose_param(get_param(np, internal_np::face_patch), + internal::Connected_components_pmap(pmesh, ecmap, fimap)) + : choose_param(get_param(np, internal_np::face_patch), + internal::Connected_components_pmap());//do not compute cc's + + bool protect = choose_param(get_param(np, internal_np::protect_constraints), false); + + + + + + + CGAL::Polygon_mesh_processing::internal::Incremental_remesher + inc_remesher(pmesh, vpmap, protect, ecmap, vcmap, fpmap, fimap); + inc_remesher.init_remeshing(faces); + + CGAL::Polygon_mesh_processing::Area_remesher remesher(pmesh, vpmap); remesher.area_relaxation(); + inc_remesher.project_to_surface(); + + + } From cd7e7e44026d7b2ceb62f050f2f059463ee7a4d2 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Tue, 13 Jun 2017 13:51:05 +0300 Subject: [PATCH 012/102] area smoothing - projection with tree constructed with copied triangles --- .../Polygon_mesh_processing/area_smoothing.h | 148 ++++++------------ 1 file changed, 44 insertions(+), 104 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/area_smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/area_smoothing.h index 72bf3511ed7..a9104bd9101 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/area_smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/area_smoothing.h @@ -5,7 +5,6 @@ #include #include -//#include #include @@ -14,7 +13,6 @@ //#include -#include @@ -41,10 +39,12 @@ class Area_remesher typedef typename GeomTraits::Vector_3 Vector; typedef typename GeomTraits::Triangle_3 Triangle; + typedef std::vector Triangle_list; - //typedef CGAL::AABB_face_graph_triangle_primitive Primitive; - //typedef CGAL::AABB_traits Traits; - //typedef CGAL::AABB_tree Tree; + + typedef CGAL::AABB_triangle_primitive Primitive; + typedef CGAL::AABB_traits AABB_Traits; + typedef CGAL::AABB_tree Tree; @@ -55,19 +55,29 @@ public: Area_remesher(PolygonMesh& pmesh, VertexPointMap& vpmap) : mesh_(pmesh), vpmap_(vpmap) {} + ~Area_remesher() + { + delete tree_ptr_; + } + template + void init_remeshing(const FaceRange& face_range) + { + for(face_descriptor f : face_range) + input_triangles_.push_back(triangle(f)); + + + tree_ptr_ = new Tree(input_triangles_.begin(), input_triangles_.end()); + tree_ptr_->accelerate_distance_queries(); + + } + void area_relaxation() { - //Tree tree(faces(mesh_).first, faces(mesh_).second, mesh_); - //tree.rebuild(faces(mesh_).first, faces(mesh_).second, mesh_);// - //tree.accelerate_distance_queries(); - - - for(vertex_descriptor v : vertices(mesh_)) { @@ -75,32 +85,25 @@ public: { std::cout<<"processing vertex: "<< v << std::endl; - //std::cout<<"point moved from: "<closest_point(p_query); + //do the projection + put(vpmap_, v, projected); - //std::cout<<"point before projection: "<::vertex_descriptor vertex_descriptor; - using boost::get_param; - using boost::choose_param; - - - typedef typename GetGeomTraits::type GT; - - //typedef typename GetVertexPointMap::type VPMap; - //VPMap vpmap = choose_param(get_param(np, internal_np::vertex_point), - // get_property_map(vertex_point, pmesh)); - - typedef typename GetFaceIndexMap::type FIMap; - FIMap fimap = choose_param(get_param(np, internal_np::face_index), - get_property_map(face_index, pmesh)); - - typedef typename boost::lookup_named_param_def < - internal_np::edge_is_constrained_t, - NamedParameters, - internal::Border_constraint_pmap//default - > ::type ECMap; - ECMap ecmap = (boost::is_same >::value) - //avoid constructing the Border_constraint_pmap if it's not used - ? choose_param(get_param(np, internal_np::edge_is_constrained) - , internal::Border_constraint_pmap(pmesh, faces, fimap)) - : choose_param(get_param(np, internal_np::edge_is_constrained) - , internal::Border_constraint_pmap()); - - typedef typename boost::lookup_named_param_def < - internal_np::vertex_is_constrained_t, - NamedParameters, - internal::No_constraint_pmap//default - > ::type VCMap; - VCMap vcmap = choose_param(get_param(np, internal_np::vertex_is_constrained), - internal::No_constraint_pmap()); - - typedef typename boost::lookup_named_param_def < - internal_np::face_patch_t, - NamedParameters, - internal::Connected_components_pmap//default - > ::type FPMap; - FPMap fpmap = (boost::is_same >::value) - ? choose_param(get_param(np, internal_np::face_patch), - internal::Connected_components_pmap(pmesh, ecmap, fimap)) - : choose_param(get_param(np, internal_np::face_patch), - internal::Connected_components_pmap());//do not compute cc's - - bool protect = choose_param(get_param(np, internal_np::protect_constraints), false); - - - - - - - CGAL::Polygon_mesh_processing::internal::Incremental_remesher - inc_remesher(pmesh, vpmap, protect, ecmap, vcmap, fpmap, fimap); - inc_remesher.init_remeshing(faces); - - CGAL::Polygon_mesh_processing::Area_remesher remesher(pmesh, vpmap); + remesher.init_remeshing(faces); remesher.area_relaxation(); - inc_remesher.project_to_surface(); + From aaa91aa3ed3cd7fdf3e7b43bba2843004a624aa2 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Wed, 14 Jun 2017 13:14:52 +0300 Subject: [PATCH 013/102] handle degenerate cases and tests --- .../Polygon_mesh_processing/angle_smoothing.h | 147 +++++--- .../Polygon_mesh_processing/CMakeLists.txt | 1 + .../test_comp_remeshing.cpp | 330 ++++++++++++++++++ 3 files changed, 435 insertions(+), 43 deletions(-) create mode 100644 Polygon_mesh_processing/test/Polygon_mesh_processing/test_comp_remeshing.cpp diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h index ee3aee82b8b..10146de71a6 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h @@ -6,7 +6,7 @@ #include #include - +#include namespace CGAL { @@ -30,6 +30,13 @@ class Angle_remesher typedef typename GeomTraits::Segment_3 Segment; + + // gather incident lines to a map + // + typedef std::pair He_pair; + typedef std::map Edges_around_map; + + public: Angle_remesher(PolygonMesh& pmesh, VertexPointMap& vpmap) : mesh_(pmesh), vpmap_(vpmap) {} @@ -43,15 +50,14 @@ public: std::map barycenters; boost::vector_property_map n_map; - + unsigned int count = 0; for(vertex_descriptor v : vertices(mesh_)) { if(!is_border(v, mesh_)) { - std::cout<<"processing vertex: "<< v << std::endl; - + //std::cout<<"processing vertex: "<< v << std::endl; // compute normal to v @@ -62,56 +68,40 @@ public: - // gather incident lines to a map - // > - typedef std::pair He_pair; - typedef std::map Edges_around_map; Edges_around_map he_map; + typename Edges_around_map::iterator it; - - for(halfedge_descriptor hi : halfedges_around_source(v, mesh_)) - { + for(halfedge_descriptor hi : halfedges_around_source(v, mesh_)) // or make it around target he_map[hi] = He_pair(next(hi, mesh_), prev(opposite(hi, mesh_) ,mesh_)); - //std::cout<<"edges: "<first; He_pair he_pair = it->second; std::cout<< "main: " << main_he; + std::cout<<" ("<"<< target(main_he, mesh_)<<")"; std::cout<< " - incident: "<< he_pair.first; std::cout<<" ("<"<< target(he_pair.first, mesh_)<<")"; std::cout<<" and " << he_pair.second; std::cout<<" ("<"<< target(he_pair.second, mesh_)<<")"<second; - Point eq_d_p1 = get(vpmap_, target(he_pair.first, mesh_)); - Point eq_d_p2 = get(vpmap_, source(he_pair.second, mesh_)); - Point m = CGAL::midpoint(eq_d_p1, eq_d_p2); - - // get common vertex around which the edge is rotated halfedge_descriptor main_he = it->first; - Point s = get(vpmap_, target(main_he, mesh_)); + He_pair incident_pair = it->second; - // create segment which bisects angle - typename GeomTraits::Segment_3 bisector(s, m); + Vector rotated_edge = rotate_edge(main_he, incident_pair); - // correct segment position and length - correct_position(bisector, main_he); - - move += Vector(bisector.target(), bisector.source()); + move += rotated_edge; } @@ -147,9 +137,6 @@ public: - - - } @@ -176,34 +163,108 @@ private: } - void correct_position(Segment& bisector, const halfedge_descriptor& he_c) + Vector rotate_edge(const halfedge_descriptor& main_he, const He_pair& incd_edges) { - // common vertex - Point s = get(vpmap_, target(he_c, mesh_)); + double tol = 1e-14; + double precision = 1e-3; + double magnifier = 1e+3; + + // get common vertex around which the edge is rotated + Point s = get(vpmap_, target(main_he, mesh_)); + + // get "equidistant" points - actualy ther are at equal angles + Point equidistant_p1 = get(vpmap_, target(incd_edges.first, mesh_)); + Point equidistant_p2 = get(vpmap_, source(incd_edges.second, mesh_)); + + Vector edge1(s, equidistant_p1); + Vector edge2(s, equidistant_p2); + + internal::normalize(edge1, GeomTraits()); + internal::normalize(edge2, GeomTraits()); + + // get bisector! + Vector bisector = CGAL::NULL_VECTOR; + + // but be aware of stupid numerical errors - check possible overflow? + bisector = edge1 * magnifier + edge2 * magnifier; + + + // handle degenerate cases + if(bisector.squared_length() < precision) + { + // pv is the vertex that is being moved + Point pv = get(vpmap_, source(main_he, mesh_)); + + if(s == pv) + { + // s, end_v, and equidistant points are almcollinear. + CGAL_assertion(CGAL::collinear(s, pv, equidistant_p1)); + CGAL_assertion(CGAL::collinear(s, pv, equidistant_p2)); + return Vector(CGAL::NULL_VECTOR); + } + else + { + // s and equidistant points are collinear + //CGAL_assertion(CGAL::collinear(s, equidistant_p1, equidistant_p2)); // any overload with some tolerance? + Vector n(s, pv); + bisector = n; + } + + } + + correct_bisector(bisector, main_he); + + + double target_length = CGAL::sqrt(sqlength(main_he)); + double bisector_length = CGAL::sqrt(bisector.squared_length()); + + if( ! ( ( target_length - tol < bisector_length ) && + ( bisector_length < target_length + tol ) ) ) + { + std::cerr<<"problem"; + } + + CGAL_assertion( ( target_length - tol < bisector_length ) && + ( bisector_length < target_length + tol ) ); + + + return bisector; + + + } + + + + void correct_bisector(Vector& bisector_vec, const halfedge_descriptor& main_he) + { + + // get common vertex around which the edge is rotated + Point s = get(vpmap_, target(main_he, mesh_)); + + // create a segment to be able to translate - avoid it? + Segment bisector(s, s + bisector_vec); // scale - double scale_factor = CGAL::sqrt( sqlength(he_c) / bisector.squared_length() ); + double scale_factor = CGAL::sqrt( sqlength(main_he) / bisector.squared_length() ); typename GeomTraits::Aff_transformation_3 t_scale(CGAL::SCALING, scale_factor); bisector = bisector.transform(t_scale); - // translate Vector vec(bisector.source(), s); typename GeomTraits::Aff_transformation_3 t_translate(CGAL::TRANSLATION, vec); bisector = bisector.transform(t_translate); - - double tol = 10e-15; - double target_length = CGAL::sqrt(sqlength(he_c)); - double bisector_length = CGAL::sqrt(bisector.squared_length()); - CGAL_assertion( ( target_length - tol < bisector_length ) && - ( bisector_length < target_length + tol ) ); + // take the opposite so that their sum is the overall displacement + bisector_vec = -Vector(bisector); } + + + }; diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt index d17771b0c98..dc947f78233 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt @@ -95,3 +95,4 @@ endif(EIGEN3_FOUND) create_single_source_cgal_program("test_does_bound_a_volume.cpp") create_single_source_cgal_program("test_pmp_clip.cpp") create_single_source_cgal_program("triangulate_hole_polyline_test.cpp") + create_single_source_cgal_program("test_comp_remeshing.cpp") diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_comp_remeshing.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_comp_remeshing.cpp new file mode 100644 index 00000000000..496551942d7 --- /dev/null +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_comp_remeshing.cpp @@ -0,0 +1,330 @@ +#include +#include + +#include +#include + +#include + + +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; +typedef CGAL::Surface_mesh Mesh; + + + +int main(int argc, char* argv[]){ + + + std::cout<<"hello\n"; + + const char* filename; + std::ifstream input; + std::ofstream output; + Mesh mesh; + + + /// + filename = "data/blobby_3cc.off"; + input.open(filename); + + + if (!input || !(input >> mesh) || mesh.is_empty()) { + std::cerr << "Not a valid .off file." << std::endl; + return 1; + } + + CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + + input.close(); + + //output.open("data/smoothed_blobby_3cc.off"); + //output << mesh; + //output.close(); + + + /// + filename = "data/cube_quad.off"; + input.open(filename); + + + if (!input || !(input >> mesh) || mesh.is_empty()) { + std::cerr << "Not a valid .off file." << std::endl; + return 1; + } + + CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + + input.close(); + + //output.open("data/smoothed_cube_quad.off"); + //output << mesh; + //output.close(); + + + /// + filename = "data/elephant.off"; + input.open(filename); + + + if (!input || !(input >> mesh) || mesh.is_empty()) { + std::cerr << "Not a valid .off file." << std::endl; + return 1; + } + + CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + + input.close(); + + //output.open("data/smoothed_elephant.off"); + //output << mesh; + //output.close(); + + + filename = "data/degenerate_polygon.off"; + input.open(filename); + + + if (!input || !(input >> mesh) || mesh.is_empty()) { + std::cerr << "Not a valid .off file." << std::endl; + return 1; + } + + CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + + input.close(); + + //output.open("data/smoothed_degenerate_polygon.off"); + //output << mesh; + //output.close(); + + + filename = "data/sneaky_degenerate_polygon.off"; + input.open(filename); + + + if (!input || !(input >> mesh) || mesh.is_empty()) { + std::cerr << "Not a valid .off file." << std::endl; + return 1; + } + + CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + + input.close(); + + //output.open("data/smoothed_sneaky_degenerate_polygon.off"); + //output << mesh; + //output.close(); + + + /// + filename = "data/joint_refined.off"; + input.open(filename); + + + if (!input || !(input >> mesh) || mesh.is_empty()) { + std::cerr << "Not a valid .off file." << std::endl; + return 1; + } + + CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + + input.close(); + + //output.open("data/smoothed_joint_refined.off"); + //output << mesh; + //output.close(); + + + /// + filename = "data/mannequin-devil.off"; + input.open(filename); + + + if (!input || !(input >> mesh) || mesh.is_empty()) { + std::cerr << "Not a valid .off file." << std::endl; + return 1; + } + + CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + + input.close(); + + //output.open("data/smoothed_mannequin-devil.off"); + //output << mesh; + //output.close(); + + + /// + filename = "data/mech-holes-shark.off"; + input.open(filename); + + + if (!input || !(input >> mesh) || mesh.is_empty()) { + std::cerr << "Not a valid .off file." << std::endl; + return 1; + } + + CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + + input.close(); + + //output.open("data/smoothed_mech-holes-shark.off"); + //output << mesh; + //output.close(); + + + /// + filename = "data/non_manifold_vertex.off"; + input.open(filename); + + + if (!input || !(input >> mesh) || mesh.is_empty()) { + std::cerr << "Not a valid .off file." << std::endl; + return 1; + } + CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + + input.close(); + + //output.open("data/smoothed_non_manifold_vertex.off"); + //output << mesh; + //output.close(); + + + /// + filename = "data/overlapping_triangles.off"; + input.open(filename); + + + if (!input || !(input >> mesh) || mesh.is_empty()) { + std::cerr << "Not a valid .off file." << std::endl; + return 1; + } + + CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + + input.close(); + + //output.open("data/smoothed_overlapping_triangles.off"); + //output << mesh; + //output.close(); + + + /// + filename = "data/tetra1.off"; + input.open(filename); + + + if (!input || !(input >> mesh) || mesh.is_empty()) { + std::cerr << "Not a valid .off file." << std::endl; + return 1; + } + + CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + + input.close(); + + //output.open("data/smoothed_tetra1.off"); + //output << mesh; + //output.close(); + + + /// + filename = "data/tetra2.off"; + input.open(filename); + + + if (!input || !(input >> mesh) || mesh.is_empty()) { + std::cerr << "Not a valid .off file." << std::endl; + return 1; + } + + CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + + input.close(); + + //output.open("data/smoothed_tetra2.off"); + //output << mesh; + //output.close(); + + + /// + filename = "data/tetra3.off"; + input.open(filename); + + + if (!input || !(input >> mesh) || mesh.is_empty()) { + std::cerr << "Not a valid .off file." << std::endl; + return 1; + } + + CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + + input.close(); + + //output.open("data/smoothed_tetra3.off"); + //output << mesh; + //output.close(); + + + /// + filename = "data/tetra4.off"; + input.open(filename); + + + if (!input || !(input >> mesh) || mesh.is_empty()) { + std::cerr << "Not a valid .off file." << std::endl; + return 1; + } + + CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + + input.close(); + + //output.open("data/smoothed_tetra4.off"); + //output << mesh; + //output.close(); + + + /// + filename = "data/two_tris_collinear.off"; + input.open(filename); + + + if (!input || !(input >> mesh) || mesh.is_empty()) { + std::cerr << "Not a valid .off file." << std::endl; + return 1; + } + + CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + + input.close(); + + //output.open("data/smoothed_two_tris_collinear.off"); + //output << mesh; + //output.close(); + + + /// + filename = "data/U.off"; + input.open(filename); + + + if (!input || !(input >> mesh) || mesh.is_empty()) { + std::cerr << "Not a valid .off file." << std::endl; + return 1; + } + + CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + + input.close(); + + //output.open("data/smoothed_U.off"); + //output << mesh; + //output.close(); + + + + + return 0; +} From 6903ab9bf0cb1b4536886b1d140aab78c82fc48f Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Wed, 14 Jun 2017 14:56:22 +0300 Subject: [PATCH 014/102] fix nan degenerate case --- .../include/CGAL/Polygon_mesh_processing/angle_smoothing.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h index 10146de71a6..0f348edcc02 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h @@ -6,7 +6,6 @@ #include #include -#include namespace CGAL { @@ -180,8 +179,10 @@ private: Vector edge1(s, equidistant_p1); Vector edge2(s, equidistant_p2); - internal::normalize(edge1, GeomTraits()); - internal::normalize(edge2, GeomTraits()); + if(edge1 != CGAL::NULL_VECTOR) + internal::normalize(edge1, GeomTraits()); + if(edge2 != CGAL::NULL_VECTOR) + internal::normalize(edge2, GeomTraits()); // get bisector! Vector bisector = CGAL::NULL_VECTOR; From 8c196474b1a9d36ef9d4c59f9a6420c348961c2a Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Thu, 15 Jun 2017 00:36:30 +0300 Subject: [PATCH 015/102] better approach to degenerate cases --- .../Polygon_mesh_processing/angle_smoothing.h | 80 +++++++++++++++++-- 1 file changed, 74 insertions(+), 6 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h index 0f348edcc02..8ae4e4c0c9e 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h @@ -49,14 +49,23 @@ public: std::map barycenters; boost::vector_property_map n_map; + unsigned int count = 0; + + for(vertex_descriptor v : vertices(mesh_)) { + count++; + std::cout<<"count: "< Date: Thu, 15 Jun 2017 07:27:31 +0300 Subject: [PATCH 016/102] fix tolerance on 180 degrees degenerate case --- .../Polygon_mesh_processing/angle_smoothing.h | 91 +++---------------- 1 file changed, 14 insertions(+), 77 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h index 8ae4e4c0c9e..53578b920c8 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h @@ -50,23 +50,14 @@ public: boost::vector_property_map n_map; - unsigned int count = 0; - - for(vertex_descriptor v : vertices(mesh_)) { - count++; - std::cout<<"count: "<first; @@ -96,7 +87,7 @@ public: std::cout<<" and " << he_pair.second; std::cout<<" ("<"<< target(he_pair.second, mesh_)<<")"< Date: Fri, 16 Jun 2017 16:11:07 +0300 Subject: [PATCH 017/102] fix degenerate cases on angle smoothing --- .../Polygon_mesh_processing/angle_smoothing.h | 82 ++++-- .../test_comp_remeshing.cpp | 253 +++++++++++++----- 2 files changed, 240 insertions(+), 95 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h index 53578b920c8..ede27dacf69 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h @@ -1,12 +1,13 @@ #ifndef ANGLE_SMOOTHING_H #define ANGLE_SMOOTHING_H - +//#define CGAL_ANGLE_BASE_SMOOTHING_DEBUG #include #include #include + namespace CGAL { namespace Polygon_mesh_processing { @@ -19,6 +20,7 @@ template class Angle_remesher { + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef CGAL::Halfedge_around_source_iterator halfedge_around_source_iterator; @@ -49,7 +51,6 @@ public: std::map barycenters; boost::vector_property_map n_map; - for(vertex_descriptor v : vertices(mesh_)) { @@ -59,6 +60,7 @@ public: std::cout<<"processing vertex: "<< v << std::endl; #endif + // compute normal to v Vector vn = compute_vertex_normal(v, mesh_, Polygon_mesh_processing::parameters::vertex_point_map(vpmap_) @@ -181,43 +183,51 @@ private: Point equidistant_p1 = get(vpmap_, target(incd_edges.first, mesh_)); Point equidistant_p2 = get(vpmap_, source(incd_edges.second, mesh_)); - Vector bisector = CGAL::NULL_VECTOR; Vector edge1(s, equidistant_p1); Vector edge2(s, equidistant_p2); - + Vector s_pv(s, pv); // check degenerate cases - if( (edge1 == CGAL::NULL_VECTOR || edge2 == CGAL::NULL_VECTOR) || - (CGAL::collinear(s, pv, equidistant_p1) && CGAL::collinear(s, pv, equidistant_p2)) ) + double tolerance = 1e-5; // to think about it + + if ( edge1.squared_length() < tolerance || + edge2.squared_length() < tolerance || + sqlength(main_he) < tolerance || + (edge1 - s_pv).squared_length() < tolerance || + (edge2 - s_pv).squared_length() < tolerance ) { - // angle is 0 return CGAL::NULL_VECTOR; } - else + CGAL_assertion(s_pv.squared_length() > tolerance); + + // get bisector + Vector bisector = CGAL::NULL_VECTOR; + internal::normalize(edge1, GeomTraits()); + internal::normalize(edge2, GeomTraits()); + bisector = edge1 + edge2; + + + // under 2 degrees deviation consider it flat + if( bisector.squared_length() < 0.001 ) // sin(theta) = 0.0316 => theta = 1.83 { - // normal case - internal::normalize(edge1, GeomTraits()); - internal::normalize(edge2, GeomTraits()); - bisector = edge1 + edge2; + // angle is (almost) 180 degrees, take the perpendicular + Vector normal_vec = find_perpendicular(edge1, s, pv); // normal to edge and found on (s-pv)'s plane - if ( (CGAL::collinear(s, equidistant_p1, equidistant_p2)) || - (bisector.squared_length()) < 0.01 ) // sin(theta) = 0.01 + CGAL_assertion(normal_vec != CGAL::NULL_VECTOR); + CGAL_assertion(CGAL::scalar_product(edge1, normal_vec) < tolerance); + + Segment b_segment(s, s + normal_vec); + Point b_segment_end = b_segment.target(); + + if(CGAL::angle(b_segment_end, s, pv) == CGAL::OBTUSE) { - //angle is (almost) 180 degrees, take the perpendicular - Vector edge(s, equidistant_p1); - Vector normal_vec(-edge.y(), edge.x(), edge.z()); - Segment b_segment(s, s + normal_vec); - Point b_segment_end = b_segment.target(); - - if(CGAL::angle(b_segment_end, s, pv) == CGAL::OBTUSE) - b_segment = b_segment.opposite(); - - bisector = Vector(b_segment); + b_segment = b_segment.opposite(); } + bisector = Vector(b_segment); } @@ -229,10 +239,9 @@ private: double bisector_length = CGAL::sqrt(bisector.squared_length()); - double tol = 1e-2; // temp; set dependant on the mesh - maybe min of edges - CGAL_assertion( ( target_length - tol < bisector_length ) && - ( bisector_length < target_length + tol ) ); + CGAL_assertion( ( target_length - tolerance < bisector_length ) && + ( bisector_length < target_length + tolerance ) ); return bisector; @@ -241,6 +250,22 @@ private: } + Vector find_perpendicular(const Vector& input_vec, const Point& s, const Point& pv) + { + Vector s_pv(s, pv); + Vector aux_normal = CGAL::cross_product(input_vec, s_pv); + + return CGAL::cross_product(aux_normal, input_vec); + + } + + Vector max_vector(const Vector& vec1, const Vector& vec2) + { + if (vec1.squared_length() > vec2.squared_length()) + return vec1; + else + return vec2; + } void correct_bisector(Vector& bisector_vec, const halfedge_descriptor& main_he) { @@ -248,7 +273,7 @@ private: // get common vertex around which the edge is rotated Point s = get(vpmap_, target(main_he, mesh_)); - // create a segment to be able to translate - avoid it? + // create a segment to be able to translate Segment bisector(s, s + bisector_vec); // scale @@ -328,3 +353,4 @@ void angle_remeshing(PolygonMesh& pmesh, const NamedParameters& np) #endif // ANGLE_SMOOTHING_H + diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_comp_remeshing.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_comp_remeshing.cpp index 496551942d7..6d51ff6dec5 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_comp_remeshing.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_comp_remeshing.cpp @@ -5,8 +5,12 @@ #include #include +#include +#define CGAL_TEST_COMP_REMESHING_DEBUG +//#define CGAL_TEST_COMP_REMESHING_OUTPUT + typedef CGAL::Exact_predicates_inexact_constructions_kernel K; typedef CGAL::Surface_mesh Mesh; @@ -15,18 +19,47 @@ typedef CGAL::Surface_mesh Mesh; int main(int argc, char* argv[]){ - std::cout<<"hello\n"; const char* filename; std::ifstream input; - std::ofstream output; Mesh mesh; +#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT + std::ofstream output; +#endif + + /// + filename = "data/polygon3D.off"; + input.open(filename); + +#ifdef CGAL_TEST_COMP_REMESHING_DEBUG +std::cout<<"case: "<< filename << std::endl; +#endif + + if (!input || !(input >> mesh) || mesh.is_empty()) { + std::cerr << "Not a valid .off file." << std::endl; + return 1; + } + + CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + //CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); + + + input.close(); + +#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT + output.open("data/polygon3D_smoothed.off"); + output << mesh; + output.close(); +#endif /// filename = "data/blobby_3cc.off"; input.open(filename); +#ifdef CGAL_TEST_COMP_REMESHING_DEBUG +std::cout<<"case: "<< filename << std::endl; +#endif if (!input || !(input >> mesh) || mesh.is_empty()) { std::cerr << "Not a valid .off file." << std::endl; @@ -34,18 +67,24 @@ int main(int argc, char* argv[]){ } CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + //CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); + input.close(); - //output.open("data/smoothed_blobby_3cc.off"); - //output << mesh; - //output.close(); - +#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT + output.open("data/blobby_3cc_smoothed.off"); + output << mesh; + output.close(); +#endif /// filename = "data/cube_quad.off"; input.open(filename); +#ifdef CGAL_TEST_COMP_REMESHING_DEBUG +std::cout<<"case: "<< filename << std::endl; +#endif if (!input || !(input >> mesh) || mesh.is_empty()) { std::cerr << "Not a valid .off file." << std::endl; @@ -53,18 +92,24 @@ int main(int argc, char* argv[]){ } CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + //CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); + input.close(); - //output.open("data/smoothed_cube_quad.off"); - //output << mesh; - //output.close(); - +#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT + output.open("data/cube_quad_smoothed.off"); + output << mesh; + output.close(); +#endif /// filename = "data/elephant.off"; input.open(filename); +#ifdef CGAL_TEST_COMP_REMESHING_DEBUG +std::cout<<"case: "<< filename << std::endl; +#endif if (!input || !(input >> mesh) || mesh.is_empty()) { std::cerr << "Not a valid .off file." << std::endl; @@ -75,14 +120,18 @@ int main(int argc, char* argv[]){ input.close(); - //output.open("data/smoothed_elephant.off"); - //output << mesh; - //output.close(); - +#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT + output.open("data/elephant_smoothed.off"); + output << mesh; + output.close(); +#endif filename = "data/degenerate_polygon.off"; input.open(filename); +#ifdef CGAL_TEST_COMP_REMESHING_DEBUG +std::cout<<"case: "<< filename << std::endl; +#endif if (!input || !(input >> mesh) || mesh.is_empty()) { std::cerr << "Not a valid .off file." << std::endl; @@ -93,14 +142,18 @@ int main(int argc, char* argv[]){ input.close(); - //output.open("data/smoothed_degenerate_polygon.off"); - //output << mesh; - //output.close(); - +#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT + output.open("data/degenerate_polygon_smoothed.off"); + output << mesh; + output.close(); +#endif filename = "data/sneaky_degenerate_polygon.off"; input.open(filename); +#ifdef CGAL_TEST_COMP_REMESHING_DEBUG +std::cout<<"case: "<< filename << std::endl; +#endif if (!input || !(input >> mesh) || mesh.is_empty()) { std::cerr << "Not a valid .off file." << std::endl; @@ -111,15 +164,19 @@ int main(int argc, char* argv[]){ input.close(); - //output.open("data/smoothed_sneaky_degenerate_polygon.off"); - //output << mesh; - //output.close(); - +#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT + output.open("data/sneaky_degenerate_polygon_smoothed.off"); + output << mesh; + output.close(); +#endif /// filename = "data/joint_refined.off"; input.open(filename); +#ifdef CGAL_TEST_COMP_REMESHING_DEBUG +std::cout<<"case: "<< filename << std::endl; +#endif if (!input || !(input >> mesh) || mesh.is_empty()) { std::cerr << "Not a valid .off file." << std::endl; @@ -130,15 +187,19 @@ int main(int argc, char* argv[]){ input.close(); - //output.open("data/smoothed_joint_refined.off"); - //output << mesh; - //output.close(); - +#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT + output.open("data/joint_refined_smoothed.off"); + output << mesh; + output.close(); +#endif /// filename = "data/mannequin-devil.off"; input.open(filename); +#ifdef CGAL_TEST_COMP_REMESHING_DEBUG +std::cout<<"case: "<< filename << std::endl; +#endif if (!input || !(input >> mesh) || mesh.is_empty()) { std::cerr << "Not a valid .off file." << std::endl; @@ -148,16 +209,19 @@ int main(int argc, char* argv[]){ CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); input.close(); - - //output.open("data/smoothed_mannequin-devil.off"); - //output << mesh; - //output.close(); - +#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT + output.open("data/mannequin-devil_smoothed.off"); + output << mesh; + output.close(); +#endif /// filename = "data/mech-holes-shark.off"; input.open(filename); +#ifdef CGAL_TEST_COMP_REMESHING_DEBUG +std::cout<<"case: "<< filename << std::endl; +#endif if (!input || !(input >> mesh) || mesh.is_empty()) { std::cerr << "Not a valid .off file." << std::endl; @@ -168,15 +232,19 @@ int main(int argc, char* argv[]){ input.close(); - //output.open("data/smoothed_mech-holes-shark.off"); - //output << mesh; - //output.close(); - +#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT + output.open("data/mech-holes-shark_smoothed.off"); + output << mesh; + output.close(); +#endif /// filename = "data/non_manifold_vertex.off"; input.open(filename); +#ifdef CGAL_TEST_COMP_REMESHING_DEBUG +std::cout<<"case: "<< filename << std::endl; +#endif if (!input || !(input >> mesh) || mesh.is_empty()) { std::cerr << "Not a valid .off file." << std::endl; @@ -186,15 +254,19 @@ int main(int argc, char* argv[]){ input.close(); - //output.open("data/smoothed_non_manifold_vertex.off"); - //output << mesh; - //output.close(); - +#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT + output.open("data/non_manifold_vertex_smoothed.off"); + output << mesh; + output.close(); +#endif /// filename = "data/overlapping_triangles.off"; input.open(filename); +#ifdef CGAL_TEST_COMP_REMESHING_DEBUG +std::cout<<"case: "<< filename << std::endl; +#endif if (!input || !(input >> mesh) || mesh.is_empty()) { std::cerr << "Not a valid .off file." << std::endl; @@ -205,15 +277,19 @@ int main(int argc, char* argv[]){ input.close(); - //output.open("data/smoothed_overlapping_triangles.off"); - //output << mesh; - //output.close(); - +#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT + output.open("data/overlapping_triangles_smoothed.off"); + output << mesh; + output.close(); +#endif /// filename = "data/tetra1.off"; input.open(filename); +#ifdef CGAL_TEST_COMP_REMESHING_DEBUG +std::cout<<"case: "<< filename << std::endl; +#endif if (!input || !(input >> mesh) || mesh.is_empty()) { std::cerr << "Not a valid .off file." << std::endl; @@ -224,15 +300,19 @@ int main(int argc, char* argv[]){ input.close(); - //output.open("data/smoothed_tetra1.off"); - //output << mesh; - //output.close(); - +#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT + output.open("data/tetra1_smoothed.off"); + output << mesh; + output.close(); +#endif /// filename = "data/tetra2.off"; input.open(filename); +#ifdef CGAL_TEST_COMP_REMESHING_DEBUG +std::cout<<"case: "<< filename << std::endl; +#endif if (!input || !(input >> mesh) || mesh.is_empty()) { std::cerr << "Not a valid .off file." << std::endl; @@ -243,15 +323,19 @@ int main(int argc, char* argv[]){ input.close(); - //output.open("data/smoothed_tetra2.off"); - //output << mesh; - //output.close(); - +#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT + output.open("data/tetra2_smoothed.off"); + output << mesh; + output.close(); +#endif /// filename = "data/tetra3.off"; input.open(filename); +#ifdef CGAL_TEST_COMP_REMESHING_DEBUG +std::cout<<"case: "<< filename << std::endl; +#endif if (!input || !(input >> mesh) || mesh.is_empty()) { std::cerr << "Not a valid .off file." << std::endl; @@ -262,15 +346,19 @@ int main(int argc, char* argv[]){ input.close(); - //output.open("data/smoothed_tetra3.off"); - //output << mesh; - //output.close(); - +#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT + output.open("data/tetra3_smoothed.off"); + output << mesh; + output.close(); +#endif /// filename = "data/tetra4.off"; input.open(filename); +#ifdef CGAL_TEST_COMP_REMESHING_DEBUG +std::cout<<"case: "<< filename << std::endl; +#endif if (!input || !(input >> mesh) || mesh.is_empty()) { std::cerr << "Not a valid .off file." << std::endl; @@ -281,15 +369,19 @@ int main(int argc, char* argv[]){ input.close(); - //output.open("data/smoothed_tetra4.off"); - //output << mesh; - //output.close(); - +#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT + output.open("data/tetra4_smoothed.off"); + output << mesh; + output.close(); +#endif /// filename = "data/two_tris_collinear.off"; input.open(filename); +#ifdef CGAL_TEST_COMP_REMESHING_DEBUG +std::cout<<"case: "<< filename << std::endl; +#endif if (!input || !(input >> mesh) || mesh.is_empty()) { std::cerr << "Not a valid .off file." << std::endl; @@ -300,15 +392,42 @@ int main(int argc, char* argv[]){ input.close(); - //output.open("data/smoothed_two_tris_collinear.off"); - //output << mesh; - //output.close(); +#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT + output.open("data/two_tris_collinear_smoothed.off"); + output << mesh; + output.close(); +#endif + /// + filename = "data/degtri_nullface.off"; + input.open(filename); + +#ifdef CGAL_TEST_COMP_REMESHING_DEBUG +std::cout<<"case: "<< filename << std::endl; +#endif + + if (!input || !(input >> mesh) || mesh.is_empty()) { + std::cerr << "Not a valid .off file." << std::endl; + return 1; + } + + CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + + input.close(); + +#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT + output.open("data/degtri_nullface_smoothed.off"); + output << mesh; + output.close(); +#endif /// filename = "data/U.off"; input.open(filename); +#ifdef CGAL_TEST_COMP_REMESHING_DEBUG +std::cout<<"case: "<< filename << std::endl; +#endif if (!input || !(input >> mesh) || mesh.is_empty()) { std::cerr << "Not a valid .off file." << std::endl; @@ -319,11 +438,11 @@ int main(int argc, char* argv[]){ input.close(); - //output.open("data/smoothed_U.off"); - //output << mesh; - //output.close(); - - +#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT + output.open("data/U_smoothed.off"); + output << mesh; + output.close(); +#endif return 0; From 03292af820900ad8bc826c4d9f66311e184071fa Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Sat, 17 Jun 2017 16:25:28 +0300 Subject: [PATCH 018/102] area smoothing tests --- .../test_comp_remeshing.cpp | 100 ++++++++++-------- 1 file changed, 58 insertions(+), 42 deletions(-) diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_comp_remeshing.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_comp_remeshing.cpp index 6d51ff6dec5..8f4c263bded 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_comp_remeshing.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_comp_remeshing.cpp @@ -27,6 +27,7 @@ int main(int argc, char* argv[]){ std::ofstream output; #endif + /// filename = "data/polygon3D.off"; input.open(filename); @@ -40,8 +41,8 @@ std::cout<<"case: "<< filename << std::endl; return 1; } - CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); - //CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); + //CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); input.close(); @@ -66,8 +67,8 @@ std::cout<<"case: "<< filename << std::endl; return 1; } - CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); - //CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); + //CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); input.close(); @@ -78,6 +79,7 @@ std::cout<<"case: "<< filename << std::endl; output.close(); #endif + /// filename = "data/cube_quad.off"; input.open(filename); @@ -91,8 +93,8 @@ std::cout<<"case: "<< filename << std::endl; return 1; } - CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); - //CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); + //CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); input.close(); @@ -103,6 +105,7 @@ std::cout<<"case: "<< filename << std::endl; output.close(); #endif + /// filename = "data/elephant.off"; input.open(filename); @@ -116,7 +119,9 @@ std::cout<<"case: "<< filename << std::endl; return 1; } - CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + //CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); + input.close(); @@ -138,7 +143,9 @@ std::cout<<"case: "<< filename << std::endl; return 1; } - CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + //CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); + input.close(); @@ -160,7 +167,8 @@ std::cout<<"case: "<< filename << std::endl; return 1; } - CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + //CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); input.close(); @@ -170,6 +178,7 @@ std::cout<<"case: "<< filename << std::endl; output.close(); #endif + /// filename = "data/joint_refined.off"; input.open(filename); @@ -183,7 +192,9 @@ std::cout<<"case: "<< filename << std::endl; return 1; } - CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + //CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); + input.close(); @@ -193,6 +204,7 @@ std::cout<<"case: "<< filename << std::endl; output.close(); #endif + /// filename = "data/mannequin-devil.off"; input.open(filename); @@ -206,7 +218,9 @@ std::cout<<"case: "<< filename << std::endl; return 1; } - CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + //CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); + input.close(); #ifdef CGAL_TEST_COMP_REMESHING_OUTPUT @@ -215,6 +229,7 @@ std::cout<<"case: "<< filename << std::endl; output.close(); #endif + /// filename = "data/mech-holes-shark.off"; input.open(filename); @@ -228,7 +243,8 @@ std::cout<<"case: "<< filename << std::endl; return 1; } - CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + //CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); input.close(); @@ -238,6 +254,7 @@ std::cout<<"case: "<< filename << std::endl; output.close(); #endif + /// filename = "data/non_manifold_vertex.off"; input.open(filename); @@ -250,7 +267,10 @@ std::cout<<"case: "<< filename << std::endl; std::cerr << "Not a valid .off file." << std::endl; return 1; } - CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + + // CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); + input.close(); @@ -260,6 +280,7 @@ std::cout<<"case: "<< filename << std::endl; output.close(); #endif + /// filename = "data/overlapping_triangles.off"; input.open(filename); @@ -273,7 +294,8 @@ std::cout<<"case: "<< filename << std::endl; return 1; } - CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + //CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); input.close(); @@ -283,6 +305,7 @@ std::cout<<"case: "<< filename << std::endl; output.close(); #endif + /// filename = "data/tetra1.off"; input.open(filename); @@ -296,7 +319,9 @@ std::cout<<"case: "<< filename << std::endl; return 1; } - CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + //CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); + input.close(); @@ -306,6 +331,7 @@ std::cout<<"case: "<< filename << std::endl; output.close(); #endif + /// filename = "data/tetra2.off"; input.open(filename); @@ -319,7 +345,9 @@ std::cout<<"case: "<< filename << std::endl; return 1; } - CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + //CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); + input.close(); @@ -329,6 +357,7 @@ std::cout<<"case: "<< filename << std::endl; output.close(); #endif + /// filename = "data/tetra3.off"; input.open(filename); @@ -342,7 +371,9 @@ std::cout<<"case: "<< filename << std::endl; return 1; } - CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + //CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); + input.close(); @@ -352,6 +383,7 @@ std::cout<<"case: "<< filename << std::endl; output.close(); #endif + /// filename = "data/tetra4.off"; input.open(filename); @@ -365,7 +397,9 @@ std::cout<<"case: "<< filename << std::endl; return 1; } - CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + //CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); + input.close(); @@ -388,7 +422,9 @@ std::cout<<"case: "<< filename << std::endl; return 1; } - CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + //CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); + input.close(); @@ -398,28 +434,6 @@ std::cout<<"case: "<< filename << std::endl; output.close(); #endif - /// - filename = "data/degtri_nullface.off"; - input.open(filename); - -#ifdef CGAL_TEST_COMP_REMESHING_DEBUG -std::cout<<"case: "<< filename << std::endl; -#endif - - if (!input || !(input >> mesh) || mesh.is_empty()) { - std::cerr << "Not a valid .off file." << std::endl; - return 1; - } - - CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); - - input.close(); - -#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT - output.open("data/degtri_nullface_smoothed.off"); - output << mesh; - output.close(); -#endif /// filename = "data/U.off"; @@ -434,7 +448,9 @@ std::cout<<"case: "<< filename << std::endl; return 1; } - CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + //CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); + input.close(); From 291a6dc32f390e9e3b062349176a57b0fc35bcf5 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Sat, 17 Jun 2017 19:57:45 +0300 Subject: [PATCH 019/102] area - bugs and optimizations in gradient descent --- .../Polygon_mesh_processing/area_smoothing.h | 185 ++++++++++++------ 1 file changed, 126 insertions(+), 59 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/area_smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/area_smoothing.h index a9104bd9101..873362921fb 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/area_smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/area_smoothing.h @@ -15,7 +15,6 @@ - namespace CGAL { namespace Polygon_mesh_processing { @@ -23,10 +22,6 @@ namespace Polygon_mesh_processing { - - - - template class Area_remesher { @@ -34,6 +29,7 @@ class Area_remesher typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::face_descriptor face_descriptor; typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename boost::graph_traits::edge_descriptor edge_descriptor; typedef typename GeomTraits::Point_3 Point; typedef typename GeomTraits::Vector_3 Vector; @@ -78,31 +74,42 @@ public: void area_relaxation() { + count_non_convex_energy_ = 0; //temp; + unsigned int moved_points = 0; + for(vertex_descriptor v : vertices(mesh_)) { if(!is_border(v, mesh_)) { - std::cout<<"processing vertex: "<< v << std::endl; - std::cout<<"point moved from: "<closest_point(p_query); +#ifdef CGAL_AREA_BASED_REMESHING_DEBUG +std::cout<<"point moved from: "<closest_point(p_query); - //do the projection - put(vpmap_, v, projected); + //do the projection + put(vpmap_, v, projected); - std::cout<<" after projection: "< precision || previous_step_size_y > precision || previous_step_size_z > precision) + //std::ofstream out("data/energy.txt"); + //std::ofstream out("data/areas.txt"); + + double criterion = to_double( (energy - energy_new) / energy ); + + while( criterion > 0.001 ) // make it a named parameter { dFdx=0, dFdy=0, dFdz=0; compute_derivatives(dFdx, dFdy, dFdz, v, S_av); + /* + std::vector areas = calc_areas(v); + for(unsigned int i=0; i Date: Sun, 18 Jun 2017 12:58:43 +0300 Subject: [PATCH 020/102] get rid of boilerplate in test cpp --- .../test_comp_remeshing.cpp | 459 ++---------------- 1 file changed, 42 insertions(+), 417 deletions(-) diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_comp_remeshing.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_comp_remeshing.cpp index 8f4c263bded..e7c7ba6d43b 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_comp_remeshing.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_comp_remeshing.cpp @@ -1,5 +1,7 @@ #include #include +#include +#include #include #include @@ -11,6 +13,7 @@ #define CGAL_TEST_COMP_REMESHING_DEBUG //#define CGAL_TEST_COMP_REMESHING_OUTPUT + typedef CGAL::Exact_predicates_inexact_constructions_kernel K; typedef CGAL::Surface_mesh Mesh; @@ -20,7 +23,7 @@ int main(int argc, char* argv[]){ - const char* filename; + std::string filename; std::ifstream input; Mesh mesh; #ifdef CGAL_TEST_COMP_REMESHING_OUTPUT @@ -28,437 +31,59 @@ int main(int argc, char* argv[]){ #endif - /// - filename = "data/polygon3D.off"; - input.open(filename); + + std::vector filenames = { + "data/polygon3D", + "data/blobby_3cc", + "data/cube_quad", + "data/elephant", + "data/degenerate_polygon", + "data/sneaky_degenerate_polygon", + "data/joint_refined", + "data/mannequin-devil", + "data/mech-holes-shark", + "data/non_manifold_vertex", + "data/overlapping_triangles", + "data/tetra1", + "data/tetra2", + "data/tetra3", + "data/tetra4", + "data/two_tris_collinear", + "data/U" + }; + + + + for(auto i=0; i!= filenames.size(); ++i) + { + filename = filenames[i]+".off"; + input.open(filename); + #ifdef CGAL_TEST_COMP_REMESHING_DEBUG std::cout<<"case: "<< filename << std::endl; #endif - if (!input || !(input >> mesh) || mesh.is_empty()) { - std::cerr << "Not a valid .off file." << std::endl; - return 1; - } - - //CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); - CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); + if (!input || !(input >> mesh) || mesh.is_empty()) { + std::cerr << "Not a valid .off file." << std::endl; + return 1; + } + input.close(); + + + //CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); + CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); - input.close(); #ifdef CGAL_TEST_COMP_REMESHING_OUTPUT - output.open("data/polygon3D_smoothed.off"); + output.open(filenames[i]+"_smoothed"+".off"); output << mesh; output.close(); #endif - - /// - filename = "data/blobby_3cc.off"; - input.open(filename); - -#ifdef CGAL_TEST_COMP_REMESHING_DEBUG -std::cout<<"case: "<< filename << std::endl; -#endif - - if (!input || !(input >> mesh) || mesh.is_empty()) { - std::cerr << "Not a valid .off file." << std::endl; - return 1; } - //CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); - CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); - - - input.close(); - -#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT - output.open("data/blobby_3cc_smoothed.off"); - output << mesh; - output.close(); -#endif - - - /// - filename = "data/cube_quad.off"; - input.open(filename); - -#ifdef CGAL_TEST_COMP_REMESHING_DEBUG -std::cout<<"case: "<< filename << std::endl; -#endif - - if (!input || !(input >> mesh) || mesh.is_empty()) { - std::cerr << "Not a valid .off file." << std::endl; - return 1; - } - - //CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); - CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); - - - input.close(); - -#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT - output.open("data/cube_quad_smoothed.off"); - output << mesh; - output.close(); -#endif - - - /// - filename = "data/elephant.off"; - input.open(filename); - -#ifdef CGAL_TEST_COMP_REMESHING_DEBUG -std::cout<<"case: "<< filename << std::endl; -#endif - - if (!input || !(input >> mesh) || mesh.is_empty()) { - std::cerr << "Not a valid .off file." << std::endl; - return 1; - } - - //CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); - CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); - - - input.close(); - -#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT - output.open("data/elephant_smoothed.off"); - output << mesh; - output.close(); -#endif - - filename = "data/degenerate_polygon.off"; - input.open(filename); - -#ifdef CGAL_TEST_COMP_REMESHING_DEBUG -std::cout<<"case: "<< filename << std::endl; -#endif - - if (!input || !(input >> mesh) || mesh.is_empty()) { - std::cerr << "Not a valid .off file." << std::endl; - return 1; - } - - //CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); - CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); - - - input.close(); - -#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT - output.open("data/degenerate_polygon_smoothed.off"); - output << mesh; - output.close(); -#endif - - filename = "data/sneaky_degenerate_polygon.off"; - input.open(filename); - -#ifdef CGAL_TEST_COMP_REMESHING_DEBUG -std::cout<<"case: "<< filename << std::endl; -#endif - - if (!input || !(input >> mesh) || mesh.is_empty()) { - std::cerr << "Not a valid .off file." << std::endl; - return 1; - } - - //CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); - CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); - - input.close(); - -#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT - output.open("data/sneaky_degenerate_polygon_smoothed.off"); - output << mesh; - output.close(); -#endif - - - /// - filename = "data/joint_refined.off"; - input.open(filename); - -#ifdef CGAL_TEST_COMP_REMESHING_DEBUG -std::cout<<"case: "<< filename << std::endl; -#endif - - if (!input || !(input >> mesh) || mesh.is_empty()) { - std::cerr << "Not a valid .off file." << std::endl; - return 1; - } - - //CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); - CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); - - - input.close(); - -#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT - output.open("data/joint_refined_smoothed.off"); - output << mesh; - output.close(); -#endif - - - /// - filename = "data/mannequin-devil.off"; - input.open(filename); - -#ifdef CGAL_TEST_COMP_REMESHING_DEBUG -std::cout<<"case: "<< filename << std::endl; -#endif - - if (!input || !(input >> mesh) || mesh.is_empty()) { - std::cerr << "Not a valid .off file." << std::endl; - return 1; - } - - //CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); - CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); - - - input.close(); -#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT - output.open("data/mannequin-devil_smoothed.off"); - output << mesh; - output.close(); -#endif - - - /// - filename = "data/mech-holes-shark.off"; - input.open(filename); - -#ifdef CGAL_TEST_COMP_REMESHING_DEBUG -std::cout<<"case: "<< filename << std::endl; -#endif - - if (!input || !(input >> mesh) || mesh.is_empty()) { - std::cerr << "Not a valid .off file." << std::endl; - return 1; - } - - //CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); - CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); - - input.close(); - -#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT - output.open("data/mech-holes-shark_smoothed.off"); - output << mesh; - output.close(); -#endif - - - /// - filename = "data/non_manifold_vertex.off"; - input.open(filename); - -#ifdef CGAL_TEST_COMP_REMESHING_DEBUG -std::cout<<"case: "<< filename << std::endl; -#endif - - if (!input || !(input >> mesh) || mesh.is_empty()) { - std::cerr << "Not a valid .off file." << std::endl; - return 1; - } - - // CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); - CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); - - - input.close(); - -#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT - output.open("data/non_manifold_vertex_smoothed.off"); - output << mesh; - output.close(); -#endif - - - /// - filename = "data/overlapping_triangles.off"; - input.open(filename); - -#ifdef CGAL_TEST_COMP_REMESHING_DEBUG -std::cout<<"case: "<< filename << std::endl; -#endif - - if (!input || !(input >> mesh) || mesh.is_empty()) { - std::cerr << "Not a valid .off file." << std::endl; - return 1; - } - - //CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); - CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); - - input.close(); - -#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT - output.open("data/overlapping_triangles_smoothed.off"); - output << mesh; - output.close(); -#endif - - - /// - filename = "data/tetra1.off"; - input.open(filename); - -#ifdef CGAL_TEST_COMP_REMESHING_DEBUG -std::cout<<"case: "<< filename << std::endl; -#endif - - if (!input || !(input >> mesh) || mesh.is_empty()) { - std::cerr << "Not a valid .off file." << std::endl; - return 1; - } - - //CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); - CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); - - - input.close(); - -#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT - output.open("data/tetra1_smoothed.off"); - output << mesh; - output.close(); -#endif - - - /// - filename = "data/tetra2.off"; - input.open(filename); - -#ifdef CGAL_TEST_COMP_REMESHING_DEBUG -std::cout<<"case: "<< filename << std::endl; -#endif - - if (!input || !(input >> mesh) || mesh.is_empty()) { - std::cerr << "Not a valid .off file." << std::endl; - return 1; - } - - //CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); - CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); - - - input.close(); - -#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT - output.open("data/tetra2_smoothed.off"); - output << mesh; - output.close(); -#endif - - - /// - filename = "data/tetra3.off"; - input.open(filename); - -#ifdef CGAL_TEST_COMP_REMESHING_DEBUG -std::cout<<"case: "<< filename << std::endl; -#endif - - if (!input || !(input >> mesh) || mesh.is_empty()) { - std::cerr << "Not a valid .off file." << std::endl; - return 1; - } - - //CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); - CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); - - - input.close(); - -#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT - output.open("data/tetra3_smoothed.off"); - output << mesh; - output.close(); -#endif - - - /// - filename = "data/tetra4.off"; - input.open(filename); - -#ifdef CGAL_TEST_COMP_REMESHING_DEBUG -std::cout<<"case: "<< filename << std::endl; -#endif - - if (!input || !(input >> mesh) || mesh.is_empty()) { - std::cerr << "Not a valid .off file." << std::endl; - return 1; - } - - //CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); - CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); - - - input.close(); - -#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT - output.open("data/tetra4_smoothed.off"); - output << mesh; - output.close(); -#endif - - /// - filename = "data/two_tris_collinear.off"; - input.open(filename); - -#ifdef CGAL_TEST_COMP_REMESHING_DEBUG -std::cout<<"case: "<< filename << std::endl; -#endif - - if (!input || !(input >> mesh) || mesh.is_empty()) { - std::cerr << "Not a valid .off file." << std::endl; - return 1; - } - - //CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); - CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); - - - input.close(); - -#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT - output.open("data/two_tris_collinear_smoothed.off"); - output << mesh; - output.close(); -#endif - - - /// - filename = "data/U.off"; - input.open(filename); - -#ifdef CGAL_TEST_COMP_REMESHING_DEBUG -std::cout<<"case: "<< filename << std::endl; -#endif - - if (!input || !(input >> mesh) || mesh.is_empty()) { - std::cerr << "Not a valid .off file." << std::endl; - return 1; - } - - //CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); - CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); - - - input.close(); - -#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT - output.open("data/U_smoothed.off"); - output << mesh; - output.close(); -#endif return 0; From 20238d5abac08683d3a2e660492daf3afb4da519 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Sun, 18 Jun 2017 18:03:37 +0300 Subject: [PATCH 021/102] projection in angle smoothing --- .../Polygon_mesh_processing/angle_smoothing.h | 126 ++++++++++++------ .../Polygon_mesh_processing/area_smoothing.h | 24 +--- .../test_comp_remeshing.cpp | 7 +- 3 files changed, 94 insertions(+), 63 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h index ede27dacf69..e92568fccf0 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h @@ -1,12 +1,15 @@ #ifndef ANGLE_SMOOTHING_H #define ANGLE_SMOOTHING_H -//#define CGAL_ANGLE_BASE_SMOOTHING_DEBUG +//#define CGAL_ANGLE_BASED_SMOOTHING_DEBUG #include #include #include +#include +#include +#include namespace CGAL { @@ -20,17 +23,19 @@ template class Angle_remesher { - typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - typedef CGAL::Halfedge_around_source_iterator halfedge_around_source_iterator; - + typedef typename boost::graph_traits::face_descriptor face_descriptor; typedef typename GeomTraits::Point_3 Point; typedef typename GeomTraits::Vector_3 Vector; typedef typename GeomTraits::Segment_3 Segment; + typedef typename GeomTraits::Triangle_3 Triangle; + typedef std::vector Triangle_list; - + typedef CGAL::AABB_triangle_primitive AABB_Primitive; + typedef CGAL::AABB_traits AABB_Traits; + typedef CGAL::AABB_tree Tree; // gather incident lines to a map // @@ -42,8 +47,23 @@ public: Angle_remesher(PolygonMesh& pmesh, VertexPointMap& vpmap) : mesh_(pmesh), vpmap_(vpmap) {} + ~Angle_remesher() + { + delete tree_ptr_; + } + template + void init_remeshing(const FaceRange& face_range) + { + for (face_descriptor f : face_range) + { + input_triangles_.push_back(triangle(f)); + } + + tree_ptr_ = new Tree(input_triangles_.begin(), input_triangles_.end()); + tree_ptr_->accelerate_distance_queries(); + } void angle_relaxation() { @@ -56,10 +76,10 @@ public: if(!is_border(v, mesh_)) { - #ifdef CGAL_ANGLE_BASE_SMOOTHING_DEBUG - std::cout<<"processing vertex: "<< v << std::endl; - #endif +#ifdef CGAL_ANGLE_BASED_SMOOTHING_DEBUG +std::cout<<"processing vertex: "<< v << std::endl; +#endif // compute normal to v Vector vn = compute_vertex_normal(v, mesh_, @@ -77,19 +97,19 @@ public: - #ifdef CGAL_ANGLE_BASE_SMOOTHING_DEBUG - for(it = he_map.begin(); it!=he_map.end(); ++it) - { - halfedge_descriptor main_he = it->first; - He_pair he_pair = it->second; - std::cout<< "main: " << main_he; - std::cout<<" ("<"<< target(main_he, mesh_)<<")"; - std::cout<< " - incident: "<< he_pair.first; - std::cout<<" ("<"<< target(he_pair.first, mesh_)<<")"; - std::cout<<" and " << he_pair.second; - std::cout<<" ("<"<< target(he_pair.second, mesh_)<<")"<first; + He_pair he_pair = it->second; + std::cout<< "main: " << main_he; + std::cout<<" ("<"<< target(main_he, mesh_)<<")"; + std::cout<< " - incident: "<< he_pair.first; + std::cout<<" ("<"<< target(he_pair.first, mesh_)<<")"; + std::cout<<" and " << he_pair.second; + std::cout<<" ("<"<< target(he_pair.second, mesh_)<<")"<closest_point(p_query); + put(vpmap_, v, projected); + + } + + } } - - - private: - PolygonMesh& mesh_; - VertexPointMap& vpmap_; - - + Triangle triangle(face_descriptor f) const + { + halfedge_descriptor h = halfedge(f, mesh_); + vertex_descriptor v1 = target(h, mesh_); + vertex_descriptor v2 = target(next(h, mesh_), mesh_); + vertex_descriptor v3 = target(next(next(h, mesh_), mesh_), mesh_); + return Triangle(get(vpmap_, v1), get(vpmap_, v2), get(vpmap_, v3)); + } double sqlength(const vertex_descriptor& v1, const vertex_descriptor& v2) const { @@ -210,7 +248,7 @@ private: // under 2 degrees deviation consider it flat - if( bisector.squared_length() < 0.001 ) // sin(theta) = 0.0316 => theta = 1.83 + if( bisector.squared_length() < 0.001 ) // sin(theta) = 0.0316 => theta = 1.83 CHANGE THIS { // angle is (almost) 180 degrees, take the perpendicular @@ -295,6 +333,12 @@ private: +private: + PolygonMesh& mesh_; + VertexPointMap& vpmap_; + Triangle_list input_triangles_; + Tree* tree_ptr_; + }; @@ -306,15 +350,10 @@ private: -template -void angle_remeshing(PolygonMesh& pmesh, const NamedParameters& np) +template +void angle_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const NamedParameters& np) { - - - //CGAL_PMP_NP_CLASS np; - //np = CGAL::Polygon_mesh_processing::parameters::all_default(); - using boost::choose_param; using boost::get_param; @@ -327,8 +366,9 @@ void angle_remeshing(PolygonMesh& pmesh, const NamedParameters& np) CGAL::Polygon_mesh_processing::Angle_remesher remesher(pmesh, vpmap); + remesher.init_remeshing(faces); remesher.angle_relaxation(); - + remesher.project_to_surface(); diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/area_smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/area_smoothing.h index 873362921fb..cd6cf9545ef 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/area_smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/area_smoothing.h @@ -34,19 +34,13 @@ class Area_remesher typedef typename GeomTraits::Point_3 Point; typedef typename GeomTraits::Vector_3 Vector; typedef typename GeomTraits::Triangle_3 Triangle; - typedef std::vector Triangle_list; - - typedef CGAL::AABB_triangle_primitive Primitive; - typedef CGAL::AABB_traits AABB_Traits; + typedef CGAL::AABB_triangle_primitive AABB_Primitive; + typedef CGAL::AABB_traits AABB_Traits; typedef CGAL::AABB_tree Tree; - - - - public: Area_remesher(PolygonMesh& pmesh, VertexPointMap& vpmap) : mesh_(pmesh), vpmap_(vpmap) {} @@ -142,9 +136,9 @@ private: get(vpmap_, p3)))); } - double element_area_on_the_fly(const Point& P, - const vertex_descriptor& p2, - const vertex_descriptor& p3) const + double element_area(const Point& P, + const vertex_descriptor& p2, + const vertex_descriptor& p3) const { return to_double(CGAL::approximate_sqrt( GeomTraits().compute_squared_area_3_object()( @@ -174,7 +168,6 @@ private: } - double measure_energy(const vertex_descriptor& v, const double& S_av) { double energy = 0; @@ -194,7 +187,6 @@ private: return to_double( energy / number_of_edges ); } - double measure_energy(const vertex_descriptor& v, const double& S_av, const Point& new_P) { double energy = 0; @@ -204,7 +196,7 @@ private: { vertex_descriptor pi = source(next(h, mesh_), mesh_); vertex_descriptor pi1 = target(next(h, mesh_), mesh_); - double S = element_area_on_the_fly(new_P, pi, pi1); + double S = element_area(new_P, pi, pi1); energy += (S - S_av)*(S - S_av); number_of_edges++; @@ -381,10 +373,9 @@ private: template -void area_remeshing(PolygonMesh& pmesh, const NamedParameters& np, const FaceRange& faces) +void area_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const NamedParameters& np) { - using boost::choose_param; using boost::get_param; @@ -407,7 +398,6 @@ void area_remeshing(PolygonMesh& pmesh, const NamedParameters& np, const FaceRan - } diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_comp_remeshing.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_comp_remeshing.cpp index e7c7ba6d43b..d573003ae08 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_comp_remeshing.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_comp_remeshing.cpp @@ -11,7 +11,7 @@ #define CGAL_TEST_COMP_REMESHING_DEBUG -//#define CGAL_TEST_COMP_REMESHING_OUTPUT +#define CGAL_TEST_COMP_REMESHING_OUTPUT typedef CGAL::Exact_predicates_inexact_constructions_kernel K; @@ -33,6 +33,7 @@ int main(int argc, char* argv[]){ std::vector filenames = { + "data/polygon", "data/polygon3D", "data/blobby_3cc", "data/cube_quad", @@ -71,8 +72,8 @@ std::cout<<"case: "<< filename << std::endl; input.close(); - //CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); - CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); + CGAL::Polygon_mesh_processing::angle_remeshing(mesh, faces(mesh), CGAL::Polygon_mesh_processing::parameters::all_default()); + //CGAL::Polygon_mesh_processing::area_remeshing(mesh, faces(mesh), CGAL::Polygon_mesh_processing::parameters::all_default()); From f8019da79d257d78578427a18bdf6ecdc8ed7ed3 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Sun, 18 Jun 2017 22:51:15 +0300 Subject: [PATCH 022/102] new design: smoothing.h - internal/Isotropic_remeshing/smoothing_impl.h --- .../Polygon_mesh_processing/CMakeLists.txt | 3 +- .../angle_smoothing_example.cpp | 42 -- ...hing_example.cpp => smoothing_example.cpp} | 10 +- .../Polygon_mesh_processing/area_smoothing.h | 424 ------------------ .../Isotropic_remeshing/smoothing_impl.h} | 358 ++++++++++++++- .../CGAL/Polygon_mesh_processing/smoothing.h | 93 ++++ .../Polygon_mesh_processing/CMakeLists.txt | 2 +- ...hing.cpp => test_compatible_remeshing.cpp} | 3 +- 8 files changed, 438 insertions(+), 497 deletions(-) delete mode 100644 Polygon_mesh_processing/examples/Polygon_mesh_processing/angle_smoothing_example.cpp rename Polygon_mesh_processing/examples/Polygon_mesh_processing/{area_smoothing_example.cpp => smoothing_example.cpp} (61%) delete mode 100644 Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/area_smoothing.h rename Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/{angle_smoothing.h => internal/Isotropic_remeshing/smoothing_impl.h} (51%) create mode 100644 Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h rename Polygon_mesh_processing/test/Polygon_mesh_processing/{test_comp_remeshing.cpp => test_compatible_remeshing.cpp} (94%) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt index 86737fcf46f..926cedbf8b9 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt @@ -101,7 +101,8 @@ create_single_source_cgal_program( "corefinement_consecutive_bool_op.cpp" ) create_single_source_cgal_program( "corefinement_difference_remeshed.cpp" ) create_single_source_cgal_program( "corefinement_mesh_union.cpp" ) create_single_source_cgal_program( "corefinement_polyhedron_union.cpp" ) -create_single_source_cgal_program( "angle_smoothing_example.cpp") +create_single_source_cgal_program( "smoothing_example.cpp") + if(OpenMesh_FOUND) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/angle_smoothing_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/angle_smoothing_example.cpp deleted file mode 100644 index 3c47c4c97b1..00000000000 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/angle_smoothing_example.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include -#include - -#include -#include - -#include - - -typedef CGAL::Exact_predicates_inexact_constructions_kernel K; -typedef CGAL::Surface_mesh Mesh; - - - -int main(int argc, char* argv[]){ - - - std::cout<<"hello\n"; - - const char* filename = "data/polygon.off"; - std::ifstream input(filename); - - Mesh mesh; - if (!input || !(input >> mesh) || mesh.is_empty()) { - std::cerr << "Not a valid .off file." << std::endl; - return 1; - } - - - - CGAL::Polygon_mesh_processing::angle_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default()); - - - - std::ofstream output("data/smoothed_polygon.off"); - output << mesh; - output.close(); - - - - return 0; -} diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/area_smoothing_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/smoothing_example.cpp similarity index 61% rename from Polygon_mesh_processing/examples/Polygon_mesh_processing/area_smoothing_example.cpp rename to Polygon_mesh_processing/examples/Polygon_mesh_processing/smoothing_example.cpp index f4465d7d2f4..40ed003a867 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/area_smoothing_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/smoothing_example.cpp @@ -4,7 +4,8 @@ #include #include -#include +#include + typedef CGAL::Exact_predicates_inexact_constructions_kernel K; @@ -15,8 +16,6 @@ typedef CGAL::Surface_mesh Mesh; int main(int argc, char* argv[]){ - std::cout<<"hello\n"; - const char* filename = "data/polygon3D.off"; std::ifstream input(filename); @@ -28,11 +27,12 @@ int main(int argc, char* argv[]){ - CGAL::Polygon_mesh_processing::area_remeshing(mesh, CGAL::Polygon_mesh_processing::parameters::all_default(), faces(mesh)); + CGAL::Polygon_mesh_processing::angle_remeshing(mesh, faces(mesh), CGAL::Polygon_mesh_processing::parameters::all_default()); + CGAL::Polygon_mesh_processing::area_remeshing(mesh, faces(mesh), CGAL::Polygon_mesh_processing::parameters::all_default()); - std::ofstream output("data/area_smoothed_polygon3D.off"); + std::ofstream output("data/polygon3D_smoothed.off"); output << mesh; output.close(); diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/area_smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/area_smoothing.h deleted file mode 100644 index cd6cf9545ef..00000000000 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/area_smoothing.h +++ /dev/null @@ -1,424 +0,0 @@ -#ifndef AREA_SMOOTHING_H -#define AREA_SMOOTHING_H - -#include - -#include -#include - - -#include -#include -#include -//#include - - - - -namespace CGAL { - -namespace Polygon_mesh_processing { - - - - -template -class Area_remesher -{ - - typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - typedef typename boost::graph_traits::face_descriptor face_descriptor; - typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; - typedef typename boost::graph_traits::edge_descriptor edge_descriptor; - - typedef typename GeomTraits::Point_3 Point; - typedef typename GeomTraits::Vector_3 Vector; - typedef typename GeomTraits::Triangle_3 Triangle; - typedef std::vector Triangle_list; - - typedef CGAL::AABB_triangle_primitive AABB_Primitive; - typedef CGAL::AABB_traits AABB_Traits; - typedef CGAL::AABB_tree Tree; - - -public: - Area_remesher(PolygonMesh& pmesh, VertexPointMap& vpmap) : mesh_(pmesh), vpmap_(vpmap) - {} - - ~Area_remesher() - { - delete tree_ptr_; - } - - - template - void init_remeshing(const FaceRange& face_range) - { - for(face_descriptor f : face_range) - input_triangles_.push_back(triangle(f)); - - - tree_ptr_ = new Tree(input_triangles_.begin(), input_triangles_.end()); - tree_ptr_->accelerate_distance_queries(); - - } - - - - void area_relaxation() - { - - count_non_convex_energy_ = 0; //temp; - unsigned int moved_points = 0; - - for(vertex_descriptor v : vertices(mesh_)) - { - - if(!is_border(v, mesh_)) - { - - - if (gradient_descent(v)) - { - -#ifdef CGAL_AREA_BASED_REMESHING_DEBUG -std::cout<<"point moved from: "<closest_point(p_query); - - //do the projection - put(vpmap_, v, projected); - -#ifdef CGAL_AREA_BASED_REMESHING_DEBUG -std::cout<<" to after projection: "< calc_areas(const vertex_descriptor& v) - { - std::vector areas; - for(halfedge_descriptor h : halfedges_around_source(v, mesh_)) - { - - vertex_descriptor pi = source(next(h, mesh_), mesh_); - vertex_descriptor pi1 = target(next(h, mesh_), mesh_); - double S = element_area(v, pi, pi1); - - areas.push_back(S); - - - } - - return areas; - } - - - void compute_derivatives(double& dFdx, double& dFdy, double& dFdz, const vertex_descriptor& v, const double& S_av) - { - - for(halfedge_descriptor h : halfedges_around_source(v, mesh_)) - { - - vertex_descriptor pi = source(next(h, mesh_), mesh_); - vertex_descriptor pi1 = target(next(h, mesh_), mesh_); - double S = element_area(v, pi, pi1); - - Vector vec(get(vpmap_, pi), get(vpmap_, pi1)); - - dFdx += (S - S_av) * 0.5 * (vec.z() - vec.y()); - dFdy += (S - S_av) * 0.5 * (vec.x() - vec.z()); - dFdz += (S - S_av) * 0.5 * (vec.y() - vec.x()); - - } - - dFdx *= 2; - dFdy *= 2; - dFdz *= 2; - - } - - double sqlength(const vertex_descriptor& v1, - const vertex_descriptor& v2) const - { - return to_double(CGAL::squared_distance(get(vpmap_, v1), get(vpmap_, v2))); - } - - double sqlength(const halfedge_descriptor& h) const - { - vertex_descriptor v1 = target(h, mesh_); - vertex_descriptor v2 = source(h, mesh_); - return sqlength(v1, v2); - } - - double sqlength(const edge_descriptor& e) const - { - return sqlength(halfedge(e, mesh_)); - } - - bool gradient_descent(const vertex_descriptor& v) - { - - double eta = 0.01; //learning rate - bool move_flag; - double x, y, z, x_new, y_new, z_new, dFdx, dFdy, dFdz; - x = get(vpmap_, v).x(); - y = get(vpmap_, v).y(); - z = get(vpmap_, v).z(); - - double S_av = compute_average_area_around(v); - double energy = measure_energy(v, S_av); - - // if the adjacent areas are absolutely equal - if(energy == 0) - return false; - double energy_new = 0; - - //std::ofstream out("data/energy.txt"); - //std::ofstream out("data/areas.txt"); - - double criterion = to_double( (energy - energy_new) / energy ); - - while( criterion > 0.001 ) // make it a named parameter - { - - dFdx=0, dFdy=0, dFdz=0; - compute_derivatives(dFdx, dFdy, dFdz, v, S_av); - - /* - std::vector areas = calc_areas(v); - for(unsigned int i=0; i -void area_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const NamedParameters& np) -{ - - using boost::choose_param; - using boost::get_param; - - typedef typename GetVertexPointMap::const_type VertexPointMap; - VertexPointMap vpmap = choose_param(get_param(np, internal_np::vertex_point), - get_const_property_map(CGAL::vertex_point, pmesh)); - - - typedef typename GetGeomTraits::type GeomTraits; - - - //bool do_project = choose_param(get_param(np, internal_np::do_project), true); - - - CGAL::Polygon_mesh_processing::Area_remesher remesher(pmesh, vpmap); - remesher.init_remeshing(faces); - remesher.area_relaxation(); - - - - - -} - - - - - - - - - - -} // namespace Polygon_mesh_processing -} //namespace CGAL - - - - - - - - -#endif // AREA_SMOOTHING_H - - diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h similarity index 51% rename from Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h rename to Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h index e92568fccf0..4d16f8be6a6 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/angle_smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h @@ -1,20 +1,24 @@ -#ifndef ANGLE_SMOOTHING_H -#define ANGLE_SMOOTHING_H -//#define CGAL_ANGLE_BASED_SMOOTHING_DEBUG +#ifndef CGAL_POLYGON_MESH_PROCESSING_SMOOTHING_IMPL_H +#define CGAL_POLYGON_MESH_PROCESSING_SMOOTHING_IMPL_H + + +#include #include -#include -#include - #include #include #include + namespace CGAL { namespace Polygon_mesh_processing { +namespace internal { + + + @@ -350,29 +354,339 @@ private: -template -void angle_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const NamedParameters& np) + + +template +class Area_remesher { - using boost::choose_param; - using boost::get_param; + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::face_descriptor face_descriptor; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename boost::graph_traits::edge_descriptor edge_descriptor; - typedef typename GetVertexPointMap::const_type VertexPointMap; - VertexPointMap vpmap = choose_param(get_param(np, internal_np::vertex_point), - get_const_property_map(CGAL::vertex_point, pmesh)); + typedef typename GeomTraits::Point_3 Point; + typedef typename GeomTraits::Vector_3 Vector; + typedef typename GeomTraits::Triangle_3 Triangle; + typedef std::vector Triangle_list; + + typedef CGAL::AABB_triangle_primitive AABB_Primitive; + typedef CGAL::AABB_traits AABB_Traits; + typedef CGAL::AABB_tree Tree; - typedef typename GetGeomTraits::type Traits; +public: + Area_remesher(PolygonMesh& pmesh, VertexPointMap& vpmap) : mesh_(pmesh), vpmap_(vpmap) + {} + + ~Area_remesher() + { + delete tree_ptr_; + } - CGAL::Polygon_mesh_processing::Angle_remesher remesher(pmesh, vpmap); - remesher.init_remeshing(faces); - remesher.angle_relaxation(); - remesher.project_to_surface(); + template + void init_remeshing(const FaceRange& face_range) + { + for(face_descriptor f : face_range) + input_triangles_.push_back(triangle(f)); + + + tree_ptr_ = new Tree(input_triangles_.begin(), input_triangles_.end()); + tree_ptr_->accelerate_distance_queries(); + + } -} + void area_relaxation() + { + + count_non_convex_energy_ = 0; //temp; + unsigned int moved_points = 0; + + for(vertex_descriptor v : vertices(mesh_)) + { + + if(!is_border(v, mesh_)) + { + + + if (gradient_descent(v)) + { + +#ifdef CGAL_AREA_BASED_REMESHING_DEBUG +std::cout<<"point moved from: "<closest_point(p_query); + + //do the projection + put(vpmap_, v, projected); + +#ifdef CGAL_AREA_BASED_REMESHING_DEBUG +std::cout<<" to after projection: "< calc_areas(const vertex_descriptor& v) + { + std::vector areas; + for(halfedge_descriptor h : halfedges_around_source(v, mesh_)) + { + + vertex_descriptor pi = source(next(h, mesh_), mesh_); + vertex_descriptor pi1 = target(next(h, mesh_), mesh_); + double S = element_area(v, pi, pi1); + + areas.push_back(S); + + + } + + return areas; + } + + + void compute_derivatives(double& dFdx, double& dFdy, double& dFdz, const vertex_descriptor& v, const double& S_av) + { + + for(halfedge_descriptor h : halfedges_around_source(v, mesh_)) + { + + vertex_descriptor pi = source(next(h, mesh_), mesh_); + vertex_descriptor pi1 = target(next(h, mesh_), mesh_); + double S = element_area(v, pi, pi1); + + Vector vec(get(vpmap_, pi), get(vpmap_, pi1)); + + dFdx += (S - S_av) * 0.5 * (vec.z() - vec.y()); + dFdy += (S - S_av) * 0.5 * (vec.x() - vec.z()); + dFdz += (S - S_av) * 0.5 * (vec.y() - vec.x()); + + } + + dFdx *= 2; + dFdy *= 2; + dFdz *= 2; + + } + + double sqlength(const vertex_descriptor& v1, + const vertex_descriptor& v2) const + { + return to_double(CGAL::squared_distance(get(vpmap_, v1), get(vpmap_, v2))); + } + + double sqlength(const halfedge_descriptor& h) const + { + vertex_descriptor v1 = target(h, mesh_); + vertex_descriptor v2 = source(h, mesh_); + return sqlength(v1, v2); + } + + double sqlength(const edge_descriptor& e) const + { + return sqlength(halfedge(e, mesh_)); + } + + bool gradient_descent(const vertex_descriptor& v) + { + + double eta = 0.01; //learning rate + bool move_flag; + double x, y, z, x_new, y_new, z_new, dFdx, dFdy, dFdz; + x = get(vpmap_, v).x(); + y = get(vpmap_, v).y(); + z = get(vpmap_, v).z(); + + double S_av = compute_average_area_around(v); + double energy = measure_energy(v, S_av); + + // if the adjacent areas are absolutely equal + if(energy == 0) + return false; + double energy_new = 0; + + //std::ofstream out("data/energy.txt"); + //std::ofstream out("data/areas.txt"); + + double criterion = to_double( (energy - energy_new) / energy ); + + while( criterion > 0.001 ) // make it a named parameter + { + + dFdx=0, dFdy=0, dFdz=0; + compute_derivatives(dFdx, dFdy, dFdz, v, S_av); + + /* + std::vector areas = calc_areas(v); + for(unsigned int i=0; i + +#include +#include + + + + +namespace CGAL { + +namespace Polygon_mesh_processing { + + + + + +template +void angle_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const NamedParameters& np) +{ + + using boost::choose_param; + using boost::get_param; + + typedef typename GetVertexPointMap::const_type VertexPointMap; + VertexPointMap vpmap = choose_param(get_param(np, internal_np::vertex_point), + get_const_property_map(CGAL::vertex_point, pmesh)); + + + typedef typename GetGeomTraits::type Traits; + + + CGAL::Polygon_mesh_processing::internal::Angle_remesher remesher(pmesh, vpmap); + remesher.init_remeshing(faces); + remesher.angle_relaxation(); + remesher.project_to_surface(); + + +} + + + +template +void area_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const NamedParameters& np) +{ + + using boost::choose_param; + using boost::get_param; + + typedef typename GetVertexPointMap::const_type VertexPointMap; + VertexPointMap vpmap = choose_param(get_param(np, internal_np::vertex_point), + get_const_property_map(CGAL::vertex_point, pmesh)); + + + typedef typename GetGeomTraits::type GeomTraits; + + + //bool do_project = choose_param(get_param(np, internal_np::do_project), true); + + + CGAL::Polygon_mesh_processing::internal::Area_remesher remesher(pmesh, vpmap); + remesher.init_remeshing(faces); + remesher.area_relaxation(); + + +} + + + + + + + + + + +} // namespace Polygon_mesh_processing +} // namespace CGAL + + + + + + + + + + + +#endif // CGAL_POLYGON_MESH_PROCESSING_SMOOTHING_H diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt index dc947f78233..e997d969478 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt @@ -95,4 +95,4 @@ endif(EIGEN3_FOUND) create_single_source_cgal_program("test_does_bound_a_volume.cpp") create_single_source_cgal_program("test_pmp_clip.cpp") create_single_source_cgal_program("triangulate_hole_polyline_test.cpp") - create_single_source_cgal_program("test_comp_remeshing.cpp") + create_single_source_cgal_program("test_compatible_remeshing.cpp") diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_comp_remeshing.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_compatible_remeshing.cpp similarity index 94% rename from Polygon_mesh_processing/test/Polygon_mesh_processing/test_comp_remeshing.cpp rename to Polygon_mesh_processing/test/Polygon_mesh_processing/test_compatible_remeshing.cpp index d573003ae08..da1d424f446 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_comp_remeshing.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_compatible_remeshing.cpp @@ -6,8 +6,7 @@ #include #include -#include -#include +#include #define CGAL_TEST_COMP_REMESHING_DEBUG From 4ff97d4b8e9886daebb5bc304d5f33649354a3ae Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Sun, 18 Jun 2017 23:31:21 +0300 Subject: [PATCH 023/102] merge area and angle classes --- .../Isotropic_remeshing/smoothing_impl.h | 441 +++++++----------- .../CGAL/Polygon_mesh_processing/smoothing.h | 4 +- 2 files changed, 171 insertions(+), 274 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h index 4d16f8be6a6..c1bd2506912 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h @@ -22,14 +22,14 @@ namespace internal { - template -class Angle_remesher +class Compatible_remesher { typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::face_descriptor face_descriptor; + typedef typename boost::graph_traits::edge_descriptor edge_descriptor; typedef typename GeomTraits::Point_3 Point; typedef typename GeomTraits::Vector_3 Vector; @@ -41,17 +41,16 @@ class Angle_remesher typedef CGAL::AABB_traits AABB_Traits; typedef CGAL::AABB_tree Tree; - // gather incident lines to a map // typedef std::pair He_pair; typedef std::map Edges_around_map; public: - Angle_remesher(PolygonMesh& pmesh, VertexPointMap& vpmap) : mesh_(pmesh), vpmap_(vpmap) + Compatible_remesher(PolygonMesh& pmesh, VertexPointMap& vpmap) : mesh_(pmesh), vpmap_(vpmap) {} - ~Angle_remesher() + ~Compatible_remesher() { delete tree_ptr_; } @@ -165,6 +164,46 @@ std::cout<<" moved at: "<< vp.second << std::endl; #endif } + } + + void area_relaxation() + { + + count_non_convex_energy_ = 0; //temp; + unsigned int moved_points = 0; + + for(vertex_descriptor v : vertices(mesh_)) + { + + if(!is_border(v, mesh_)) + { + + if (gradient_descent(v)) + { + +#ifdef CGAL_AREA_BASED_REMESHING_DEBUG +std::cout<<"point moved from: "<closest_point(p_query); + + //do the projection + put(vpmap_, v, projected); + +#ifdef CGAL_AREA_BASED_REMESHING_DEBUG +std::cout<<" to after projection: "< tolerance); - - // get bisector - Vector bisector = CGAL::NULL_VECTOR; - internal::normalize(edge1, GeomTraits()); - internal::normalize(edge2, GeomTraits()); - bisector = edge1 + edge2; - - - // under 2 degrees deviation consider it flat - if( bisector.squared_length() < 0.001 ) // sin(theta) = 0.0316 => theta = 1.83 CHANGE THIS - { - - // angle is (almost) 180 degrees, take the perpendicular - Vector normal_vec = find_perpendicular(edge1, s, pv); // normal to edge and found on (s-pv)'s plane - - CGAL_assertion(normal_vec != CGAL::NULL_VECTOR); - CGAL_assertion(CGAL::scalar_product(edge1, normal_vec) < tolerance); - - Segment b_segment(s, s + normal_vec); - Point b_segment_end = b_segment.target(); - - if(CGAL::angle(b_segment_end, s, pv) == CGAL::OBTUSE) - { - b_segment = b_segment.opposite(); - } - - bisector = Vector(b_segment); - - } - - - correct_bisector(bisector, main_he); - - - double target_length = CGAL::sqrt(sqlength(main_he)); - double bisector_length = CGAL::sqrt(bisector.squared_length()); - - - - CGAL_assertion( ( target_length - tolerance < bisector_length ) && - ( bisector_length < target_length + tolerance ) ); - - - return bisector; - - - } - - - Vector find_perpendicular(const Vector& input_vec, const Point& s, const Point& pv) - { - Vector s_pv(s, pv); - Vector aux_normal = CGAL::cross_product(input_vec, s_pv); - - return CGAL::cross_product(aux_normal, input_vec); - - } - - Vector max_vector(const Vector& vec1, const Vector& vec2) - { - if (vec1.squared_length() > vec2.squared_length()) - return vec1; - else - return vec2; - } - - void correct_bisector(Vector& bisector_vec, const halfedge_descriptor& main_he) - { - - // get common vertex around which the edge is rotated - Point s = get(vpmap_, target(main_he, mesh_)); - - // create a segment to be able to translate - Segment bisector(s, s + bisector_vec); - - // scale - double scale_factor = CGAL::sqrt( sqlength(main_he) / bisector.squared_length() ); - typename GeomTraits::Aff_transformation_3 t_scale(CGAL::SCALING, scale_factor); - bisector = bisector.transform(t_scale); - - // translate - Vector vec(bisector.source(), s); - typename GeomTraits::Aff_transformation_3 t_translate(CGAL::TRANSLATION, vec); - bisector = bisector.transform(t_translate); - - // take the opposite so that their sum is the overall displacement - bisector_vec = -Vector(bisector); - - } - - - - - -private: - PolygonMesh& mesh_; - VertexPointMap& vpmap_; - Triangle_list input_triangles_; - Tree* tree_ptr_; - - -}; - - - - - - - - - - - -template -class Area_remesher -{ - - typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - typedef typename boost::graph_traits::face_descriptor face_descriptor; - typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; - typedef typename boost::graph_traits::edge_descriptor edge_descriptor; - - typedef typename GeomTraits::Point_3 Point; - typedef typename GeomTraits::Vector_3 Vector; - typedef typename GeomTraits::Triangle_3 Triangle; - typedef std::vector Triangle_list; - - typedef CGAL::AABB_triangle_primitive AABB_Primitive; - typedef CGAL::AABB_traits AABB_Traits; - typedef CGAL::AABB_tree Tree; - - -public: - Area_remesher(PolygonMesh& pmesh, VertexPointMap& vpmap) : mesh_(pmesh), vpmap_(vpmap) - {} - - ~Area_remesher() - { - delete tree_ptr_; - } - - - template - void init_remeshing(const FaceRange& face_range) - { - for(face_descriptor f : face_range) - input_triangles_.push_back(triangle(f)); - - - tree_ptr_ = new Tree(input_triangles_.begin(), input_triangles_.end()); - tree_ptr_->accelerate_distance_queries(); - - } - - - - void area_relaxation() - { - - count_non_convex_energy_ = 0; //temp; - unsigned int moved_points = 0; - - for(vertex_descriptor v : vertices(mesh_)) - { - - if(!is_border(v, mesh_)) - { - - - if (gradient_descent(v)) - { - -#ifdef CGAL_AREA_BASED_REMESHING_DEBUG -std::cout<<"point moved from: "<closest_point(p_query); - - //do the projection - put(vpmap_, v, projected); - -#ifdef CGAL_AREA_BASED_REMESHING_DEBUG -std::cout<<" to after projection: "< tolerance); + + // get bisector + Vector bisector = CGAL::NULL_VECTOR; + internal::normalize(edge1, GeomTraits()); + internal::normalize(edge2, GeomTraits()); + bisector = edge1 + edge2; + + + // under about 0.5 degrees deviation consider it flat + if( bisector.squared_length() < 0.001 ) // -> length = 0.01 -> sin(theta) = 0.01 -> theta = 0.57 degrees + { + + // angle is (almost) 180 degrees, take the perpendicular + Vector normal_vec = find_perpendicular(edge1, s, pv); // normal to edge and found on (s-pv)'s plane + + CGAL_assertion(normal_vec != CGAL::NULL_VECTOR); + CGAL_assertion(CGAL::scalar_product(edge1, normal_vec) < tolerance); + + Segment b_segment(s, s + normal_vec); + Point b_segment_end = b_segment.target(); + + if(CGAL::angle(b_segment_end, s, pv) == CGAL::OBTUSE) + { + b_segment = b_segment.opposite(); + } + + bisector = Vector(b_segment); + + } + + + correct_bisector(bisector, main_he); + + + double target_length = CGAL::sqrt(sqlength(main_he)); + double bisector_length = CGAL::sqrt(bisector.squared_length()); + + + + CGAL_assertion( ( target_length - tolerance < bisector_length ) && + ( bisector_length < target_length + tolerance ) ); + + + return bisector; + + + } + + Vector find_perpendicular(const Vector& input_vec, const Point& s, const Point& pv) + { + Vector s_pv(s, pv); + Vector aux_normal = CGAL::cross_product(input_vec, s_pv); + + return CGAL::cross_product(aux_normal, input_vec); + + } + + Vector max_vector(const Vector& vec1, const Vector& vec2) + { + if (vec1.squared_length() > vec2.squared_length()) + return vec1; + else + return vec2; + } + + void correct_bisector(Vector& bisector_vec, const halfedge_descriptor& main_he) + { + + // get common vertex around which the edge is rotated + Point s = get(vpmap_, target(main_he, mesh_)); + + // create a segment to be able to translate + Segment bisector(s, s + bisector_vec); + + // scale + double scale_factor = CGAL::sqrt( sqlength(main_he) / bisector.squared_length() ); + typename GeomTraits::Aff_transformation_3 t_scale(CGAL::SCALING, scale_factor); + bisector = bisector.transform(t_scale); + + // translate + Vector vec(bisector.source(), s); + typename GeomTraits::Aff_transformation_3 t_translate(CGAL::TRANSLATION, vec); + bisector = bisector.transform(t_translate); + + // take the opposite so that their sum is the overall displacement + bisector_vec = -Vector(bisector); + + } @@ -679,13 +576,12 @@ private: private: PolygonMesh& mesh_; VertexPointMap& vpmap_; - const Tree* tree_ptr_; Triangle_list input_triangles_; + Tree* tree_ptr_; unsigned int count_non_convex_energy_; - }; @@ -698,6 +594,7 @@ private: + } //namespace internal } // namespace Polygon_mesh_processing } // namespace CGAL diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h index ed7c85044e6..1cd3e7d8830 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h @@ -33,7 +33,7 @@ void angle_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const NamedPara typedef typename GetGeomTraits::type Traits; - CGAL::Polygon_mesh_processing::internal::Angle_remesher remesher(pmesh, vpmap); + CGAL::Polygon_mesh_processing::internal::Compatible_remesher remesher(pmesh, vpmap); remesher.init_remeshing(faces); remesher.angle_relaxation(); remesher.project_to_surface(); @@ -61,7 +61,7 @@ void area_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const NamedPara //bool do_project = choose_param(get_param(np, internal_np::do_project), true); - CGAL::Polygon_mesh_processing::internal::Area_remesher remesher(pmesh, vpmap); + CGAL::Polygon_mesh_processing::internal::Compatible_remesher remesher(pmesh, vpmap); remesher.init_remeshing(faces); remesher.area_relaxation(); From d93e18b1b32cc35bb8311f2da1f2972c58de8ccc Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Mon, 19 Jun 2017 14:51:26 +0300 Subject: [PATCH 024/102] add constrained edges map --- .../smoothing_example.cpp | 10 +- .../Isotropic_remeshing/smoothing_impl.h | 97 ++++++++++++++++++- .../CGAL/Polygon_mesh_processing/smoothing.h | 85 ++++++++++++++-- .../test_compatible_remeshing.cpp | 5 +- 4 files changed, 180 insertions(+), 17 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/smoothing_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/smoothing_example.cpp index 40ed003a867..4c1ed73afbf 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/smoothing_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/smoothing_example.cpp @@ -27,8 +27,14 @@ int main(int argc, char* argv[]){ - CGAL::Polygon_mesh_processing::angle_remeshing(mesh, faces(mesh), CGAL::Polygon_mesh_processing::parameters::all_default()); - CGAL::Polygon_mesh_processing::area_remeshing(mesh, faces(mesh), CGAL::Polygon_mesh_processing::parameters::all_default()); + CGAL::Polygon_mesh_processing::angle_remeshing(mesh, + faces(mesh), + edges(mesh), + CGAL::Polygon_mesh_processing::parameters::all_default()); + CGAL::Polygon_mesh_processing::area_remeshing(mesh, + faces(mesh), + edges(mesh), + CGAL::Polygon_mesh_processing::parameters::all_default()); diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h index c1bd2506912..f412bc059a7 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h @@ -19,10 +19,70 @@ namespace internal { +template +struct No_constraint_pmap +{ +public: + typedef Descriptor key_type; + typedef bool value_type; + typedef value_type& reference; + typedef boost::read_write_property_map_tag category; + + friend bool get(const No_constraint_pmap& , const key_type& ) { + return false; + } + friend void put(No_constraint_pmap& , const key_type& , const bool ) {} +}; + + +template +struct Edge_constraint_map +{ + + typedef typename boost::graph_traits::edge_descriptor edge_descriptor; + + //boost::shared_ptr> constrained_edges_ptr; + std::shared_ptr> constrained_edges_ptr; + +public: + typedef edge_descriptor key_type; + typedef bool value_type; + typedef value_type& reference; + typedef boost::read_write_property_map_tag category; + + Edge_constraint_map() : constrained_edges_ptr(new std::set() ) + {} + + Edge_constraint_map(const EdgeRange& edges) : constrained_edges_ptr(new std::set() ) + { + for (edge_descriptor e : edges) + { + constrained_edges_ptr->insert(e); + } + } + + friend bool exists(const Edge_constraint_map& map, const edge_descriptor& e) + { + // assertion on pmesh + //return map.constrained_edges_ptr->count(e)!=0; + return map.constrained_edges_ptr->find(e) != map.constrained_edges_ptr->end(); + + } + friend void put(const Edge_constraint_map& map, const edge_descriptor& e) + { + map.constrained_edges_ptr->insert(e); + } + friend void remove(const Edge_constraint_map& map, const edge_descriptor& e) + { + map.constrained_edges_ptr->erase(e); + } + + +}; -template +template class Compatible_remesher { @@ -47,7 +107,8 @@ class Compatible_remesher public: - Compatible_remesher(PolygonMesh& pmesh, VertexPointMap& vpmap) : mesh_(pmesh), vpmap_(vpmap) + Compatible_remesher(PolygonMesh& pmesh, VertexPointMap& vpmap, VertexConstraitMap& vcmap, EdgeConstraintMap& ecmap) : + mesh_(pmesh), vpmap_(vpmap), vcmap_(vcmap), ecmap_(ecmap) {} ~Compatible_remesher() @@ -60,12 +121,14 @@ public: { for (face_descriptor f : face_range) { - input_triangles_.push_back(triangle(f)); } tree_ptr_ = new Tree(input_triangles_.begin(), input_triangles_.end()); tree_ptr_->accelerate_distance_queries(); + + //update constrained edges + check_constrained_edges(); } void angle_relaxation() @@ -77,7 +140,7 @@ public: for(vertex_descriptor v : vertices(mesh_)) { - if(!is_border(v, mesh_)) + if(!is_border(v, mesh_) && !is_constrained(v)) { #ifdef CGAL_ANGLE_BASED_SMOOTHING_DEBUG @@ -214,7 +277,7 @@ std::cout<<" to after projection: "<closest_point(p_query); @@ -569,13 +632,37 @@ private: } + bool is_constrained(const edge_descriptor& e) + { + exists(ecmap_, e); + } + bool is_constrained(const vertex_descriptor& v) + { + get(vcmap_, v); + } + + void check_constrained_edges() + { + for(edge_descriptor e : edges(mesh_)) + { + if (is_constrained(e)) + { + vertex_descriptor vs = source(e, mesh_); + vertex_descriptor vt = target(e, mesh_); + put(vcmap_, vs, true); + put(vcmap_, vt, true); + } + } + } private: PolygonMesh& mesh_; VertexPointMap& vpmap_; + VertexConstraitMap vcmap_; + EdgeConstraintMap ecmap_; Triangle_list input_triangles_; Tree* tree_ptr_; unsigned int count_non_convex_energy_; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h index 1cd3e7d8830..48a3833d637 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h @@ -18,8 +18,8 @@ namespace Polygon_mesh_processing { -template -void angle_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const NamedParameters& np) +template +void angle_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const EdgeRange& edges, const NamedParameters& np) { using boost::choose_param; @@ -30,10 +30,53 @@ void angle_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const NamedPara get_const_property_map(CGAL::vertex_point, pmesh)); - typedef typename GetGeomTraits::type Traits; + typedef typename GetGeomTraits::type GeomTraits; - CGAL::Polygon_mesh_processing::internal::Compatible_remesher remesher(pmesh, vpmap); + + // extract some edges + /* + typedef typename boost::graph_traits::edge_iterator edge_iterator; + typedef std::pair p_edges; + + typename boost::graph_traits::edge_iterator ei, ei_end; + + + for(boost::tie(ei, ei_end) = edges; ei != ei_end; ++ei) + { + //std::cout<<"p: "<"<::vertex_descriptor vertex_descriptor; + + typedef typename boost::lookup_named_param_def < + internal_np::vertex_is_constrained_t, + NamedParameters, + internal::No_constraint_pmap//default + > ::type VCMap; + VCMap vcmap = choose_param(get_param(np, internal_np::vertex_is_constrained), + internal::No_constraint_pmap()); + + + + //create ecmap with Edge_constraint_map struct + typedef typename boost::graph_traits::edge_descriptor edge_descriptor; + + //ecmap + typedef typename boost::lookup_named_param_def < + internal_np::edge_is_constrained_t, + NamedParameters, + internal::Edge_constraint_map + > ::type ECMap; + ECMap ecmap = choose_param(get_param(np, internal_np::edge_is_constrained), + internal::Edge_constraint_map()); // pass constrained edges range in this constructor + + + CGAL::Polygon_mesh_processing::internal::Compatible_remesher remesher(pmesh, vpmap, vcmap, ecmap); remesher.init_remeshing(faces); remesher.angle_relaxation(); remesher.project_to_surface(); @@ -43,8 +86,8 @@ void angle_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const NamedPara -template -void area_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const NamedParameters& np) +template +void area_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const EdgeRange& edges, const NamedParameters& np) { using boost::choose_param; @@ -61,7 +104,35 @@ void area_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const NamedPara //bool do_project = choose_param(get_param(np, internal_np::do_project), true); - CGAL::Polygon_mesh_processing::internal::Compatible_remesher remesher(pmesh, vpmap); + + //vcmap - not sure yet + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + + typedef typename boost::lookup_named_param_def < + internal_np::vertex_is_constrained_t, + NamedParameters, + internal::No_constraint_pmap//default + > ::type VCMap; + VCMap vcmap = choose_param(get_param(np, internal_np::vertex_is_constrained), + internal::No_constraint_pmap()); + + + + //create ecmap with Edge_constraint_map struct + typedef typename boost::graph_traits::edge_descriptor edge_descriptor; + + //ecmap + typedef typename boost::lookup_named_param_def < + internal_np::edge_is_constrained_t, + NamedParameters, + internal::Edge_constraint_map + > ::type ECMap; + ECMap ecmap = choose_param(get_param(np, internal_np::edge_is_constrained), + internal::Edge_constraint_map()); + + + + CGAL::Polygon_mesh_processing::internal::Compatible_remesher remesher(pmesh, vpmap, vcmap, ecmap); remesher.init_remeshing(faces); remesher.area_relaxation(); diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_compatible_remeshing.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_compatible_remeshing.cpp index da1d424f446..68ca9d1cc18 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_compatible_remeshing.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_compatible_remeshing.cpp @@ -53,7 +53,6 @@ int main(int argc, char* argv[]){ }; - for(auto i=0; i!= filenames.size(); ++i) { filename = filenames[i]+".off"; @@ -71,8 +70,8 @@ std::cout<<"case: "<< filename << std::endl; input.close(); - CGAL::Polygon_mesh_processing::angle_remeshing(mesh, faces(mesh), CGAL::Polygon_mesh_processing::parameters::all_default()); - //CGAL::Polygon_mesh_processing::area_remeshing(mesh, faces(mesh), CGAL::Polygon_mesh_processing::parameters::all_default()); + CGAL::Polygon_mesh_processing::angle_remeshing(mesh, faces(mesh), edges(mesh), CGAL::Polygon_mesh_processing::parameters::all_default()); + CGAL::Polygon_mesh_processing::area_remeshing(mesh, faces(mesh), edges(mesh), CGAL::Polygon_mesh_processing::parameters::all_default()); From 5a38cdf185ebfdb40b763c29d72f62bab105eed4 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Sat, 24 Jun 2017 18:46:05 +0300 Subject: [PATCH 025/102] area: remove projection on the fly, projection at the end only --- .../Isotropic_remeshing/smoothing_impl.h | 24 ++++--------------- .../internal/parameters_interface.h | 2 +- .../CGAL/Polygon_mesh_processing/smoothing.h | 10 ++++---- 3 files changed, 10 insertions(+), 26 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h index f412bc059a7..d3c925186c3 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h @@ -41,8 +41,7 @@ struct Edge_constraint_map typedef typename boost::graph_traits::edge_descriptor edge_descriptor; - //boost::shared_ptr> constrained_edges_ptr; - std::shared_ptr> constrained_edges_ptr; + boost::shared_ptr> constrained_edges_ptr; public: typedef edge_descriptor key_type; @@ -61,17 +60,18 @@ public: } } - friend bool exists(const Edge_constraint_map& map, const edge_descriptor& e) + friend bool get(const Edge_constraint_map& map, const edge_descriptor& e) { // assertion on pmesh //return map.constrained_edges_ptr->count(e)!=0; return map.constrained_edges_ptr->find(e) != map.constrained_edges_ptr->end(); - } + friend void put(const Edge_constraint_map& map, const edge_descriptor& e) { map.constrained_edges_ptr->insert(e); } + friend void remove(const Edge_constraint_map& map, const edge_descriptor& e) { map.constrained_edges_ptr->erase(e); @@ -243,21 +243,7 @@ std::cout<<" moved at: "<< vp.second << std::endl; if (gradient_descent(v)) { - -#ifdef CGAL_AREA_BASED_REMESHING_DEBUG -std::cout<<"point moved from: "<closest_point(p_query); - - //do the projection - put(vpmap_, v, projected); - -#ifdef CGAL_AREA_BASED_REMESHING_DEBUG -std::cout<<" to after projection: "<::vertex_descriptor vertex_descriptor; typedef typename boost::lookup_named_param_def < @@ -62,7 +62,6 @@ void angle_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const EdgeRange internal::No_constraint_pmap()); - //create ecmap with Edge_constraint_map struct typedef typename boost::graph_traits::edge_descriptor edge_descriptor; @@ -101,11 +100,10 @@ void area_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const EdgeRange typedef typename GetGeomTraits::type GeomTraits; - //bool do_project = choose_param(get_param(np, internal_np::do_project), true); + //bool do_project_on_the_fly = choose_param(get_param(np, internal_np::do_project_on_the_fly), true); - - //vcmap - not sure yet + //vcmap typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::lookup_named_param_def < @@ -117,7 +115,6 @@ void area_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const EdgeRange internal::No_constraint_pmap()); - //create ecmap with Edge_constraint_map struct typedef typename boost::graph_traits::edge_descriptor edge_descriptor; @@ -135,6 +132,7 @@ void area_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const EdgeRange CGAL::Polygon_mesh_processing::internal::Compatible_remesher remesher(pmesh, vpmap, vcmap, ecmap); remesher.init_remeshing(faces); remesher.area_relaxation(); + remesher.project_to_surface(); } From 137031d77e40c4d6316d6c33c89c1124526da344 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Sat, 24 Jun 2017 21:09:21 +0300 Subject: [PATCH 026/102] iterations and combination of area and angle remeshing --- .../CGAL/Polygon_mesh_processing/smoothing.h | 178 ++++++++---------- 1 file changed, 78 insertions(+), 100 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h index 0114a8db9ed..7022da70c25 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h @@ -1,12 +1,19 @@ #ifndef CGAL_POLYGON_MESH_PROCESSING_SMOOTHING_H #define CGAL_POLYGON_MESH_PROCESSING_SMOOTHING_H +#define CGAL_PMP_REMESHING_VERBOSE + #include #include #include +#ifdef CGAL_PMP_REMESHING_VERBOSE +#include +#endif + + @@ -19,130 +26,101 @@ namespace Polygon_mesh_processing { template -void angle_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const EdgeRange& edges, const NamedParameters& np) +void compatible_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const EdgeRange& edges, const NamedParameters& np) { - using boost::choose_param; using boost::get_param; +#ifdef CGAL_PMP_REMESHING_VERBOSE + CGAL::Timer t; + std::cout << "Remeshing parameters..."; + std::cout.flush(); + t.start(); +#endif + + //geom traits + typedef typename GetGeomTraits::type GeomTraits; + + //vpmap typedef typename GetVertexPointMap::const_type VertexPointMap; VertexPointMap vpmap = choose_param(get_param(np, internal_np::vertex_point), get_const_property_map(CGAL::vertex_point, pmesh)); + //vcmap + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::lookup_named_param_def < + internal_np::vertex_is_constrained_t, + NamedParameters, + internal::No_constraint_pmap//default + > ::type VCMap; + VCMap vcmap = choose_param(get_param(np, internal_np::vertex_is_constrained), + internal::No_constraint_pmap()); - typedef typename GetGeomTraits::type GeomTraits; + //ecmap + typedef typename boost::lookup_named_param_def < + internal_np::edge_is_constrained_t, + NamedParameters, + internal::Edge_constraint_map + > ::type ECMap; + // either fill map with given constrined edges or use default constructor for an NULL map + ECMap ecmap = (boost::is_same >::value) + ? choose_param(get_param(np, internal_np::edge_is_constrained), + internal::Edge_constraint_map(edges)) + : choose_param(get_param(np, internal_np::edge_is_constrained), + internal::Edge_constraint_map()); + + //nb_iterations + unsigned int nb_iterations = choose_param(get_param(np, internal_np::number_of_iterations), 1); +#ifdef CGAL_PMP_REMESHING_VERBOSE + t.stop(); + std::cout << "\rRemeshing parameters done ("<< t.time() <<" sec)" << std::endl; + std::cout << "Remesher construction..."; + std::cout.flush(); + t.reset(); t.start(); +#endif - // extract some edges - /* - typedef typename boost::graph_traits::edge_iterator edge_iterator; - typedef std::pair p_edges; + CGAL::Polygon_mesh_processing::internal::Compatible_remesher + remesher(pmesh, vpmap, vcmap, ecmap); + remesher.init_remeshing(faces); - typename boost::graph_traits::edge_iterator ei, ei_end; +#ifdef CGAL_PMP_REMESHING_VERBOSE + t.stop(); + std::cout << " done ("<< t.time() <<" sec)." << std::endl; +#endif - for(boost::tie(ei, ei_end) = edges; ei != ei_end; ++ei) +#ifdef CGAL_PMP_REMESHING_VERBOSE + std::cout << std::endl; + std::cout << "#iter = " << nb_iterations << std::endl; + std::cout << "Remeshing ..." << std::endl; + t.reset(); t.start(); +#endif + + for(unsigned int i=0; i"<::vertex_descriptor vertex_descriptor; - - typedef typename boost::lookup_named_param_def < - internal_np::vertex_is_constrained_t, - NamedParameters, - internal::No_constraint_pmap//default - > ::type VCMap; - VCMap vcmap = choose_param(get_param(np, internal_np::vertex_is_constrained), - internal::No_constraint_pmap()); - - - //create ecmap with Edge_constraint_map struct - typedef typename boost::graph_traits::edge_descriptor edge_descriptor; - - //ecmap - typedef typename boost::lookup_named_param_def < - internal_np::edge_is_constrained_t, - NamedParameters, - internal::Edge_constraint_map - > ::type ECMap; - ECMap ecmap = choose_param(get_param(np, internal_np::edge_is_constrained), - internal::Edge_constraint_map()); // pass constrained edges range in this constructor - - - CGAL::Polygon_mesh_processing::internal::Compatible_remesher remesher(pmesh, vpmap, vcmap, ecmap); - remesher.init_remeshing(faces); - remesher.angle_relaxation(); - remesher.project_to_surface(); - +#ifdef CGAL_PMP_REMESHING_VERBOSE + t.stop(); + std::cout << "Remeshing done in "; + std::cout << t.time() << " sec." << std::endl; + std::cout< -void area_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const EdgeRange& edges, const NamedParameters& np) -{ - - using boost::choose_param; - using boost::get_param; - - typedef typename GetVertexPointMap::const_type VertexPointMap; - VertexPointMap vpmap = choose_param(get_param(np, internal_np::vertex_point), - get_const_property_map(CGAL::vertex_point, pmesh)); - - - typedef typename GetGeomTraits::type GeomTraits; - - - //bool do_project_on_the_fly = choose_param(get_param(np, internal_np::do_project_on_the_fly), true); - - - //vcmap - typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - - typedef typename boost::lookup_named_param_def < - internal_np::vertex_is_constrained_t, - NamedParameters, - internal::No_constraint_pmap//default - > ::type VCMap; - VCMap vcmap = choose_param(get_param(np, internal_np::vertex_is_constrained), - internal::No_constraint_pmap()); - - - //create ecmap with Edge_constraint_map struct - typedef typename boost::graph_traits::edge_descriptor edge_descriptor; - - //ecmap - typedef typename boost::lookup_named_param_def < - internal_np::edge_is_constrained_t, - NamedParameters, - internal::Edge_constraint_map - > ::type ECMap; - ECMap ecmap = choose_param(get_param(np, internal_np::edge_is_constrained), - internal::Edge_constraint_map()); - - - - CGAL::Polygon_mesh_processing::internal::Compatible_remesher remesher(pmesh, vpmap, vcmap, ecmap); - remesher.init_remeshing(faces); - remesher.area_relaxation(); - remesher.project_to_surface(); - - -} - - - - - - - From 89bcf82b8ff311ebaa4d1f953bedb4d1b21c552b Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Sun, 25 Jun 2017 17:05:11 +0300 Subject: [PATCH 027/102] add gradient descent precision as named parameter --- .../internal/Isotropic_remeshing/smoothing_impl.h | 8 ++++---- .../internal/parameters_interface.h | 2 +- .../include/CGAL/Polygon_mesh_processing/smoothing.h | 6 ++++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h index d3c925186c3..2babf232458 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h @@ -229,7 +229,7 @@ std::cout<<" moved at: "<< vp.second << std::endl; } - void area_relaxation() + void area_relaxation(const double& precision) { count_non_convex_energy_ = 0; //temp; @@ -241,7 +241,7 @@ std::cout<<" moved at: "<< vp.second << std::endl; if(!is_border(v, mesh_)) { - if (gradient_descent(v)) + if (gradient_descent(v, precision)) { moved_points++; } @@ -427,7 +427,7 @@ private: } - bool gradient_descent(const vertex_descriptor& v) + bool gradient_descent(const vertex_descriptor& v, const double& precision) { double eta = 0.01; //learning rate @@ -450,7 +450,7 @@ private: double criterion = to_double( (energy - energy_new) / energy ); - while( criterion > 0.001 ) // make it a named parameter + while( criterion > precision ) { dFdx=0, dFdy=0, dFdz=0; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/parameters_interface.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/parameters_interface.h index 02d96a99604..bea7d67bc61 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/parameters_interface.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/parameters_interface.h @@ -46,7 +46,7 @@ CGAL_add_named_parameter(nb_points_per_area_unit_t, nb_points_per_area_unit, num CGAL_add_named_parameter(nb_points_per_distance_unit_t, nb_points_per_distance_unit, number_of_points_per_distance_unit) //to be documented CGAL_add_named_parameter(face_normal_t, face_normal, face_normal_map) -//CGAL_add_named_parameter(do_project_t, do_project, do_project) +CGAL_add_named_parameter(gradient_descent_precision_t, gradient_descent_precision, gradient_descent_precision) //internal CGAL_add_named_parameter(weight_calculator_t, weight_calculator, weight_calculator) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h index 7022da70c25..0594d5e02f5 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h @@ -72,6 +72,9 @@ void compatible_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const Edg //nb_iterations unsigned int nb_iterations = choose_param(get_param(np, internal_np::number_of_iterations), 1); + //gradient descente precision + double gd_precision = choose_param(get_param(np, internal_np::gradient_descent_precision), 0.001); + #ifdef CGAL_PMP_REMESHING_VERBOSE t.stop(); @@ -92,7 +95,6 @@ void compatible_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const Edg #ifdef CGAL_PMP_REMESHING_VERBOSE - std::cout << std::endl; std::cout << "#iter = " << nb_iterations << std::endl; std::cout << "Remeshing ..." << std::endl; t.reset(); t.start(); @@ -104,7 +106,7 @@ void compatible_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const Edg std::cout << " * Iteration " << (i + 1) << " *" << std::endl; #endif remesher.angle_relaxation(); - remesher.area_relaxation(); + remesher.area_relaxation(gd_precision); remesher.angle_relaxation(); remesher.project_to_surface(); } From 517e35d8940a67c552bb329cafb7831e967e0902 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Sun, 25 Jun 2017 20:12:54 +0300 Subject: [PATCH 028/102] use (optionally) weighted angles on calculating the barycenter --- .../smoothing_example.cpp | 14 ++--- .../Isotropic_remeshing/smoothing_impl.h | 54 +++++++++++++++---- .../internal/parameters_interface.h | 1 + .../CGAL/Polygon_mesh_processing/smoothing.h | 7 ++- .../test_compatible_remeshing.cpp | 11 ++-- 5 files changed, 63 insertions(+), 24 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/smoothing_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/smoothing_example.cpp index 4c1ed73afbf..6fc5f282ad3 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/smoothing_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/smoothing_example.cpp @@ -7,7 +7,6 @@ #include - typedef CGAL::Exact_predicates_inexact_constructions_kernel K; typedef CGAL::Surface_mesh Mesh; @@ -27,14 +26,11 @@ int main(int argc, char* argv[]){ - CGAL::Polygon_mesh_processing::angle_remeshing(mesh, - faces(mesh), - edges(mesh), - CGAL::Polygon_mesh_processing::parameters::all_default()); - CGAL::Polygon_mesh_processing::area_remeshing(mesh, - faces(mesh), - edges(mesh), - CGAL::Polygon_mesh_processing::parameters::all_default()); + CGAL::Polygon_mesh_processing::compatible_remeshing( + mesh, + faces(mesh), + edges(mesh), + CGAL::Polygon_mesh_processing::parameters::number_of_iterations(3)); diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h index 2babf232458..582f956ea93 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h @@ -3,6 +3,7 @@ #include +#include #include @@ -11,6 +12,7 @@ #include + namespace CGAL { namespace Polygon_mesh_processing { @@ -131,7 +133,7 @@ public: check_constrained_edges(); } - void angle_relaxation() + void angle_relaxation(bool use_weights) { std::map barycenters; @@ -153,15 +155,11 @@ std::cout<<"processing vertex: "<< v << std::endl; .geom_traits(GeomTraits())); n_map[v] = vn; - - Edges_around_map he_map; typename Edges_around_map::iterator it; for(halfedge_descriptor hi : halfedges_around_source(v, mesh_)) // or make it around target - he_map[hi] = He_pair(next(hi, mesh_), prev(opposite(hi, mesh_) ,mesh_)); - - + he_map[hi] = He_pair( next(hi, mesh_), prev(opposite(hi, mesh_), mesh_) ); #ifdef CGAL_ANGLE_BASED_SMOOTHING_DEBUG for(it = he_map.begin(); it!=he_map.end(); ++it) @@ -177,9 +175,9 @@ for(it = he_map.begin(); it!=he_map.end(); ++it) } #endif - // calculate movement Vector move = CGAL::NULL_VECTOR; + double opposite_weight_factor = 0; for(it = he_map.begin(); it != he_map.end(); ++it) { @@ -188,11 +186,26 @@ for(it = he_map.begin(); it!=he_map.end(); ++it) Vector rotated_edge = rotate_edge(main_he, incident_pair); - move += rotated_edge; + // calculate angle + double angle = get_angle(incident_pair, vn); + //small angles to have more weight + double weight = 1.0 / (angle*angle); + opposite_weight_factor += weight; + + if(use_weights) + move += weight * rotated_edge; + else + move += rotated_edge; } - barycenters[v] = get(vpmap_, v) + (move / (double)he_map.size()); + if(use_weights) + move /= opposite_weight_factor; + else + move /= CGAL::to_double(he_map.size()); + + + barycenters[v] = (get(vpmap_, v) + move) ; } // not on border @@ -510,6 +523,7 @@ private: // get "equidistant" points - in fact they are at equal angles Point equidistant_p1 = get(vpmap_, target(incd_edges.first, mesh_)); Point equidistant_p2 = get(vpmap_, source(incd_edges.second, mesh_)); + CGAL_assertion(target(incd_edges.second, mesh_) == source(incd_edges.first, mesh_)); Vector edge1(s, equidistant_p1); Vector edge2(s, equidistant_p2); @@ -577,6 +591,28 @@ private: } + double get_angle(const He_pair& incd_edges, const Vector& vn) + { + + Point s = get(vpmap_, source(incd_edges.first, mesh_)); + Point p1 = get(vpmap_, target(incd_edges.first, mesh_)); + Point p2 = get(vpmap_, source(incd_edges.second, mesh_)); + CGAL_assertion(target(incd_edges.second, mesh_) == source(incd_edges.first, mesh_)); + + Vector v1(s, p1); + Vector v2(s, p2); + + Vector cp = CGAL::cross_product(v1, v2); + double det = CGAL::scalar_product(vn, cp); + double dot = CGAL::scalar_product(v1, v2); + + // transform to range [0, 2pi] + double res = atan2(-det, -dot) + M_PI; + + return res; + } + + Vector find_perpendicular(const Vector& input_vec, const Point& s, const Point& pv) { Vector s_pv(s, pv); diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/parameters_interface.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/parameters_interface.h index bea7d67bc61..03bdc7a777c 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/parameters_interface.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/parameters_interface.h @@ -47,6 +47,7 @@ CGAL_add_named_parameter(nb_points_per_distance_unit_t, nb_points_per_distance_u //to be documented CGAL_add_named_parameter(face_normal_t, face_normal, face_normal_map) CGAL_add_named_parameter(gradient_descent_precision_t, gradient_descent_precision, gradient_descent_precision) +CGAL_add_named_parameter(use_weights_t, use_weights, use_weights) //internal CGAL_add_named_parameter(weight_calculator_t, weight_calculator, weight_calculator) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h index 0594d5e02f5..cd6f298d880 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h @@ -75,6 +75,9 @@ void compatible_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const Edg //gradient descente precision double gd_precision = choose_param(get_param(np, internal_np::gradient_descent_precision), 0.001); + //use weighted angles + bool use_weights = choose_param(get_param(np, internal_np::use_weights), true); + #ifdef CGAL_PMP_REMESHING_VERBOSE t.stop(); @@ -105,9 +108,9 @@ void compatible_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const Edg #ifdef CGAL_PMP_REMESHING_VERBOSE std::cout << " * Iteration " << (i + 1) << " *" << std::endl; #endif - remesher.angle_relaxation(); + remesher.angle_relaxation(use_weights); remesher.area_relaxation(gd_precision); - remesher.angle_relaxation(); + remesher.angle_relaxation(use_weights); remesher.project_to_surface(); } diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_compatible_remeshing.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_compatible_remeshing.cpp index 68ca9d1cc18..18555f6aded 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_compatible_remeshing.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_compatible_remeshing.cpp @@ -9,7 +9,7 @@ #include -#define CGAL_TEST_COMP_REMESHING_DEBUG +#define CGAL_PMP_REMESHING_VERBOSE #define CGAL_TEST_COMP_REMESHING_OUTPUT @@ -59,7 +59,7 @@ int main(int argc, char* argv[]){ input.open(filename); -#ifdef CGAL_TEST_COMP_REMESHING_DEBUG +#ifdef CGAL_PMP_REMESHING_VERBOSE std::cout<<"case: "<< filename << std::endl; #endif @@ -70,8 +70,11 @@ std::cout<<"case: "<< filename << std::endl; input.close(); - CGAL::Polygon_mesh_processing::angle_remeshing(mesh, faces(mesh), edges(mesh), CGAL::Polygon_mesh_processing::parameters::all_default()); - CGAL::Polygon_mesh_processing::area_remeshing(mesh, faces(mesh), edges(mesh), CGAL::Polygon_mesh_processing::parameters::all_default()); + CGAL::Polygon_mesh_processing::compatible_remeshing( + mesh, + faces(mesh), + edges(mesh), + CGAL::Polygon_mesh_processing::parameters::number_of_iterations(1)); From 87df9821122ddb862c1dd376da0d1907bc6b7cb0 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Sun, 25 Jun 2017 20:33:07 +0300 Subject: [PATCH 029/102] take No_constraint_map from remesh_impl --- .../internal/Isotropic_remeshing/smoothing_impl.h | 15 --------------- .../CGAL/Polygon_mesh_processing/smoothing.h | 1 + 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h index 582f956ea93..10d8d0cb384 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h @@ -21,21 +21,6 @@ namespace internal { -template -struct No_constraint_pmap -{ -public: - typedef Descriptor key_type; - typedef bool value_type; - typedef value_type& reference; - typedef boost::read_write_property_map_tag category; - - friend bool get(const No_constraint_pmap& , const key_type& ) { - return false; - } - friend void put(No_constraint_pmap& , const key_type& , const bool ) {} -}; - template struct Edge_constraint_map diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h index cd6f298d880..7d3940808dc 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h @@ -5,6 +5,7 @@ #include +#include #include #include From bb13cf0d3d43d5c8d3e77341aef6677f9c806ac4 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Tue, 27 Jun 2017 12:48:30 +0300 Subject: [PATCH 030/102] anneal learning rate in gradient descent with a power law to avoid local minima --- .../Isotropic_remeshing/smoothing_impl.h | 60 +++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h index 10d8d0cb384..483c8d374cd 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h @@ -50,7 +50,6 @@ public: friend bool get(const Edge_constraint_map& map, const edge_descriptor& e) { // assertion on pmesh - //return map.constrained_edges_ptr->count(e)!=0; return map.constrained_edges_ptr->find(e) != map.constrained_edges_ptr->end(); } @@ -130,7 +129,7 @@ public: if(!is_border(v, mesh_) && !is_constrained(v)) { -#ifdef CGAL_ANGLE_BASED_SMOOTHING_DEBUG +#ifdef CGAL_PMP_COMPATIBLE_REMESHING_DEBUG std::cout<<"processing vertex: "<< v << std::endl; #endif @@ -146,7 +145,7 @@ std::cout<<"processing vertex: "<< v << std::endl; for(halfedge_descriptor hi : halfedges_around_source(v, mesh_)) // or make it around target he_map[hi] = He_pair( next(hi, mesh_), prev(opposite(hi, mesh_), mesh_) ); -#ifdef CGAL_ANGLE_BASED_SMOOTHING_DEBUG +#ifdef CGAL_PMP_COMPATIBLE_REMESHING_DEBUG for(it = he_map.begin(); it!=he_map.end(); ++it) { halfedge_descriptor main_he = it->first; @@ -215,12 +214,12 @@ for(it = he_map.begin(); it!=he_map.end(); ++it) for(const VP& vp : new_locations) { -#ifdef CGAL_ANGLE_BASED_SMOOTHING_DEBUG +#ifdef CGAL_PMP_COMPATIBLE_REMESHING_DEBUG std::cout << "from: "<< get(vpmap_, vp.first); #endif put(vpmap_, vp.first, vp.second); -#ifdef CGAL_ANGLE_BASED_SMOOTHING_DEBUG +#ifdef CGAL_PMP_COMPATIBLE_REMESHING_DEBUG std::cout<<" moved at: "<< vp.second << std::endl; #endif } @@ -236,7 +235,7 @@ std::cout<<" moved at: "<< vp.second << std::endl; for(vertex_descriptor v : vertices(mesh_)) { - if(!is_border(v, mesh_)) + if(!is_border(v, mesh_) && !is_constrained(v)) { if (gradient_descent(v, precision)) @@ -249,8 +248,10 @@ std::cout<<" moved at: "<< vp.second << std::endl; } - //std::cout<<"moved points: "< areas; for(halfedge_descriptor h : halfedges_around_source(v, mesh_)) { - vertex_descriptor pi = source(next(h, mesh_), mesh_); vertex_descriptor pi1 = target(next(h, mesh_), mesh_); double S = element_area(v, pi, pi1); - areas.push_back(S); - - } return areas; @@ -403,10 +400,8 @@ private: void compute_derivatives(double& dFdx, double& dFdy, double& dFdz, const vertex_descriptor& v, const double& S_av) { - for(halfedge_descriptor h : halfedges_around_source(v, mesh_)) { - vertex_descriptor pi = source(next(h, mesh_), mesh_); vertex_descriptor pi1 = target(next(h, mesh_), mesh_); double S = element_area(v, pi, pi1); @@ -416,19 +411,16 @@ private: dFdx += (S - S_av) * 0.5 * (vec.z() - vec.y()); dFdy += (S - S_av) * 0.5 * (vec.x() - vec.z()); dFdz += (S - S_av) * 0.5 * (vec.y() - vec.x()); - } dFdx *= 2; dFdy *= 2; dFdz *= 2; - } bool gradient_descent(const vertex_descriptor& v, const double& precision) { - double eta = 0.01; //learning rate bool move_flag; double x, y, z, x_new, y_new, z_new, dFdx, dFdy, dFdz; x = get(vpmap_, v).x(); @@ -441,28 +433,34 @@ private: // if the adjacent areas are absolutely equal if(energy == 0) return false; + +#ifdef CGAL_PMP_COMPATIBLE_REMESHING_DEBUG + std::ofstream out("data/energy.txt"); + std::ofstream out("data/coords.txt"); + std::ofstream out("data/areas.txt"); +#endif double energy_new = 0; + double relative_energy = precision + 1; + unsigned int t = 1; + double eta0 = 0.01; + double power_t = 0.25; + double eta = eta0 / pow(t, power_t); - //std::ofstream out("data/energy.txt"); - //std::ofstream out("data/areas.txt"); - - double criterion = to_double( (energy - energy_new) / energy ); - - while( criterion > precision ) + while(relative_energy > precision) { - + t++; dFdx=0, dFdy=0, dFdz=0; compute_derivatives(dFdx, dFdy, dFdz, v, S_av); - /* +#ifdef CGAL_PMP_COMPATIBLE_REMESHING_DEBUG std::vector areas = calc_areas(v); + std::cout<<"v= "< Date: Tue, 27 Jun 2017 14:38:58 +0300 Subject: [PATCH 031/102] anneal learning rate asymptotically --- .../Isotropic_remeshing/smoothing_impl.h | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h index 483c8d374cd..0604983606a 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h @@ -408,6 +408,12 @@ private: Vector vec(get(vpmap_, pi), get(vpmap_, pi1)); + // minimize r: + // r = Σ(S-S_av)^2 + // dr/dx = 2 Σ(S - S_av) dS/dx + // area of triangle with respect to (x_a, y_a, z_a) = + // (v_z - v_y)x_a + (v_x - v_z)y_a + (y_y - v_x)z_a + constants + // vector v is (x_c - x_b, y_c - y_b, z_c - z_b) dFdx += (S - S_av) * 0.5 * (vec.z() - vec.y()); dFdy += (S - S_av) * 0.5 * (vec.x() - vec.z()); dFdz += (S - S_av) * 0.5 * (vec.y() - vec.x()); @@ -443,12 +449,12 @@ private: double relative_energy = precision + 1; unsigned int t = 1; double eta0 = 0.01; - double power_t = 0.25; - double eta = eta0 / pow(t, power_t); + //double power_t = 0.25; + double t0 = 0.001; + double eta = eta0 / (1 + t0*t); while(relative_energy > precision) { - t++; dFdx=0, dFdy=0, dFdz=0; compute_derivatives(dFdx, dFdy, dFdz, v, S_av); @@ -487,8 +493,10 @@ private: y = y_new; z = z_new; energy = energy_new; + t++; - eta = eta0 / pow(t, power_t); + //eta = eta0 / pow(t, power_t); + eta = eta0 / (1 + t0*t); } From b4b3ace780f50f87a17dbb30da1b6e4645b46d3a Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Thu, 29 Jun 2017 08:30:47 +0300 Subject: [PATCH 032/102] small fix for collapsed degenerate cases after first iteration when using angle weights and some typos --- .../Isotropic_remeshing/smoothing_impl.h | 35 ++++++++++--------- .../test_compatible_remeshing.cpp | 2 +- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h index 0604983606a..b7bb99d20fe 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h @@ -172,8 +172,10 @@ for(it = he_map.begin(); it!=he_map.end(); ++it) // calculate angle double angle = get_angle(incident_pair, vn); + if(angle < 1e-5) // temp + continue; - //small angles to have more weight + //small angles have more weight double weight = 1.0 / (angle*angle); opposite_weight_factor += weight; @@ -183,7 +185,8 @@ for(it = he_map.begin(); it!=he_map.end(); ++it) move += rotated_edge; } - if(use_weights) + // if at least 1 angle was summed + if(use_weights && opposite_weight_factor != 0) move /= opposite_weight_factor; else move /= CGAL::to_double(he_map.size()); @@ -398,7 +401,7 @@ private: return areas; } - void compute_derivatives(double& dFdx, double& dFdy, double& dFdz, const vertex_descriptor& v, const double& S_av) + void compute_derivatives(double& drdx, double& drdy, double& drdz, const vertex_descriptor& v, const double& S_av) { for(halfedge_descriptor h : halfedges_around_source(v, mesh_)) { @@ -412,23 +415,23 @@ private: // r = Σ(S-S_av)^2 // dr/dx = 2 Σ(S - S_av) dS/dx // area of triangle with respect to (x_a, y_a, z_a) = - // (v_z - v_y)x_a + (v_x - v_z)y_a + (y_y - v_x)z_a + constants + // (1/2) [(v_z - v_y)x_a + (v_x - v_z)y_a + (y_y - v_x)z_a + constants] // vector v is (x_c - x_b, y_c - y_b, z_c - z_b) - dFdx += (S - S_av) * 0.5 * (vec.z() - vec.y()); - dFdy += (S - S_av) * 0.5 * (vec.x() - vec.z()); - dFdz += (S - S_av) * 0.5 * (vec.y() - vec.x()); + drdx += (S - S_av) * 0.5 * (vec.z() - vec.y()); + drdy += (S - S_av) * 0.5 * (vec.x() - vec.z()); + drdz += (S - S_av) * 0.5 * (vec.y() - vec.x()); } - dFdx *= 2; - dFdy *= 2; - dFdz *= 2; + drdx *= 2; + drdy *= 2; + drdz *= 2; } bool gradient_descent(const vertex_descriptor& v, const double& precision) { bool move_flag; - double x, y, z, x_new, y_new, z_new, dFdx, dFdy, dFdz; + double x, y, z, x_new, y_new, z_new, drdx, drdy, drdz; x = get(vpmap_, v).x(); y = get(vpmap_, v).y(); z = get(vpmap_, v).z(); @@ -455,8 +458,8 @@ private: while(relative_energy > precision) { - dFdx=0, dFdy=0, dFdz=0; - compute_derivatives(dFdx, dFdy, dFdz, v, S_av); + drdx=0, drdy=0, drdz=0; + compute_derivatives(drdx, drdy, drdz, v, S_av); #ifdef CGAL_PMP_COMPATIBLE_REMESHING_DEBUG std::vector areas = calc_areas(v); @@ -468,9 +471,9 @@ private: std::cout< Date: Thu, 29 Jun 2017 08:49:41 +0300 Subject: [PATCH 033/102] switch default angle weighting off temporarily --- .../include/CGAL/Polygon_mesh_processing/smoothing.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h index 7d3940808dc..ec9c72a2815 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h @@ -77,7 +77,7 @@ void compatible_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const Edg double gd_precision = choose_param(get_param(np, internal_np::gradient_descent_precision), 0.001); //use weighted angles - bool use_weights = choose_param(get_param(np, internal_np::use_weights), true); + bool use_weights = choose_param(get_param(np, internal_np::use_weights), false); #ifdef CGAL_PMP_REMESHING_VERBOSE From 3c5ca4d88d6255485e52a8f85ebfb2caf2eb6fdc Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Wed, 5 Jul 2017 12:20:24 +0300 Subject: [PATCH 034/102] setup for curvature flow class --- .../curvature_flow_example.cpp | 40 +++++++++ .../Isotropic_remeshing/curvature_flow_impl.h | 60 +++++++++++++ .../CGAL/Polygon_mesh_processing/smoothing.h | 22 +++++ .../test_curvature_flow.cpp | 89 +++++++++++++++++++ 4 files changed, 211 insertions(+) create mode 100644 Polygon_mesh_processing/examples/Polygon_mesh_processing/curvature_flow_example.cpp create mode 100644 Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h create mode 100644 Polygon_mesh_processing/test/Polygon_mesh_processing/test_curvature_flow.cpp diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/curvature_flow_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/curvature_flow_example.cpp new file mode 100644 index 00000000000..5caf2c80a17 --- /dev/null +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/curvature_flow_example.cpp @@ -0,0 +1,40 @@ +#include +#include + +#include +#include + +#include + + +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; +typedef CGAL::Surface_mesh Mesh; + + + +int main(int argc, char* argv[]){ + + + const char* filename = "data/curved_polygon.off"; + std::ifstream input(filename); + + Mesh mesh; + if (!input || !(input >> mesh) || mesh.is_empty()) { + std::cerr << "Not a valid .off file." << std::endl; + return 1; + } + + + + CGAL::Polygon_mesh_processing::curvature_flow(mesh); + + + + std::ofstream output("data/curved_polygon_smoothed.off"); + output << mesh; + output.close(); + + + + return 0; +} diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h new file mode 100644 index 00000000000..7298ccff075 --- /dev/null +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h @@ -0,0 +1,60 @@ +#ifndef CURVATURE_FLOW_IMPL_H +#define CURVATURE_FLOW_IMPL_H + + + +namespace CGAL { + +namespace Polygon_mesh_processing { + +namespace internal { + + + + +template +class Curvature_flow +{ + + + + + +public: + + + Curvature_flow(PolygonMesh& pmesh, VertexPointMap& vpmap) : mesh_(pmesh), vpmap_(vpmap) + {} + + + + + // k = div n + + + // cot a = v1 * v2 / v1 x v2 + + + + +private: + PolygonMesh& mesh_; + VertexPointMap& vpmap_; + +}; + + + + + + + +} // internal +} // Polygon_mesh_processing +} // CGAL + + + + + +#endif // CURVATURE_FLOW_IMPL_H diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h index ec9c72a2815..5b977a76fc8 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h @@ -5,6 +5,7 @@ #include +#include #include #include @@ -128,6 +129,27 @@ void compatible_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const Edg +template +void curvature_flow(PolygonMesh& pmesh, NamedParameters& np) +{ + using boost::choose_param; + using boost::get_param; + + //vpmap + typedef typename GetVertexPointMap::const_type VertexPointMap; + VertexPointMap vpmap = choose_param(get_param(np, internal_np::vertex_point), + get_const_property_map(CGAL::vertex_point, pmesh)); + + internal::Curvature_flow curvature_remesher(pmesh, vpmap); + +} + +void curvature_flow(PolygonMesh& pmesh) +{ + curvature_flow(pmesh, parameters::all_default()); +} + + } // namespace Polygon_mesh_processing diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_curvature_flow.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_curvature_flow.cpp new file mode 100644 index 00000000000..45bd2268dc3 --- /dev/null +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_curvature_flow.cpp @@ -0,0 +1,89 @@ +#include +#include +#include +#include + +#include +#include + +#include + + +#define CGAL_PMP_REMESHING_VERBOSE +#define CGAL_TEST_COMP_REMESHING_OUTPUT + + +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; +typedef CGAL::Surface_mesh Mesh; + + + +int main(int argc, char* argv[]){ + + + + std::string filename; + std::ifstream input; + Mesh mesh; +#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT + std::ofstream output; +#endif + + + + std::vector filenames = { + "data/curved_polygon", + /*"data/polygon", + "data/polygon3D", + "data/blobby_3cc", + "data/cube_quad", + "data/elephant", + "data/degenerate_polygon", + "data/sneaky_degenerate_polygon", + "data/joint_refined", + "data/mannequin-devil", + "data/mech-holes-shark", + "data/non_manifold_vertex", + "data/overlapping_triangles", + "data/tetra1", + "data/tetra2", + "data/tetra3", + "data/tetra4", + "data/two_tris_collinear", + "data/U"*/ + }; + + + for(auto i=0; i!= filenames.size(); ++i) + { + filename = filenames[i]+".off"; + input.open(filename); + + +#ifdef CGAL_PMP_REMESHING_VERBOSE +std::cout<<"case: "<< filename << std::endl; +#endif + + if (!input || !(input >> mesh) || mesh.is_empty()) { + std::cerr << "Not a valid .off file." << std::endl; + return 1; + } + input.close(); + + + CGAL::Polygon_mesh_processing::curvature_flow(mesh); + + + +#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT + output.open(filenames[i]+"_smoothed"+".off"); + output << mesh; + output.close(); +#endif + + } + + + + return 0; +} From b145af2f33de786bc299c51c13fc08589a62c9ee Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Sun, 9 Jul 2017 11:34:54 +0300 Subject: [PATCH 035/102] mean curvature function overload fix --- .../include/CGAL/Polygon_mesh_processing/smoothing.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h index 5b977a76fc8..9b5a1ce6ae2 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h @@ -74,7 +74,7 @@ void compatible_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const Edg //nb_iterations unsigned int nb_iterations = choose_param(get_param(np, internal_np::number_of_iterations), 1); - //gradient descente precision + //gradient descent precision double gd_precision = choose_param(get_param(np, internal_np::gradient_descent_precision), 0.001); //use weighted angles @@ -130,7 +130,7 @@ void compatible_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const Edg template -void curvature_flow(PolygonMesh& pmesh, NamedParameters& np) +void curvature_flow(PolygonMesh& pmesh, const NamedParameters& np) { using boost::choose_param; using boost::get_param; @@ -144,6 +144,7 @@ void curvature_flow(PolygonMesh& pmesh, NamedParameters& np) } +template void curvature_flow(PolygonMesh& pmesh) { curvature_flow(pmesh, parameters::all_default()); From dd134890d6ef1e4142f89f02260fd5c805028f34 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Sun, 9 Jul 2017 11:48:20 +0300 Subject: [PATCH 036/102] basic setup for demo plugin - boost::vector_property_map to be fixed --- .../Polyhedron/Plugins/PMP/CMakeLists.txt | 4 + .../Plugins/PMP/Smoothing_plugin.cpp | 190 ++++++++++++++++++ .../Plugins/PMP/Smoothing_plugin.ui | 78 +++++++ 3 files changed, 272 insertions(+) create mode 100644 Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.cpp create mode 100644 Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.ui diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/CMakeLists.txt b/Polyhedron/demo/Polyhedron/Plugins/PMP/CMakeLists.txt index fbe2d6ba293..7dd96cb39e0 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/CMakeLists.txt @@ -84,3 +84,7 @@ target_link_libraries(isotropic_remeshing_plugin scene_polyhedron_item scene_po polyhedron_demo_plugin(distance_plugin Distance_plugin) target_link_libraries(distance_plugin scene_polyhedron_item scene_color_ramp) + +qt5_wrap_ui( smoothingUI_FILES Smoothing_plugin.ui) +polyhedron_demo_plugin(smoothing_plugin Smoothing_plugin ${smoothingUI_FILES}) +target_link_libraries(smoothing_plugin scene_polyhedron_item scene_polyhedron_selection_item) diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.cpp new file mode 100644 index 00000000000..01b0c89c6ef --- /dev/null +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.cpp @@ -0,0 +1,190 @@ + +#include + +#include + +#include "Scene_polyhedron_item.h" +#include "Scene_polyhedron_selection_item.h" +#include "Polyhedron_type.h" + +#include +#include +#include +#include + +#include +#include +#include + + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ui_Smoothing_plugin.h" + + +using namespace CGAL::Three; +class Polyhedron_demo_smothing_plugin : + public QObject, + public Polyhedron_demo_plugin_interface +{ + Q_OBJECT + Q_INTERFACES(CGAL::Three::Polyhedron_demo_plugin_interface) + Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.PluginInterface/1.0") + + +public: + void init(QMainWindow* mainWindow, + Scene_interface* scene_interface, + Messages_interface*) + { + this->scene = scene_interface; + this->mw = mainWindow; + + actionSmoothing_ = new QAction("Smoothing", mw); + actionSmoothing_->setProperty("subMenuName", "Polygon Mesh Processing"); + if (actionSmoothing_) { + connect(actionSmoothing_, SIGNAL(triggered()), + this, SLOT(smooth())); + } + } + + QList actions() const { + return QList() << actionSmoothing_; + } + + bool applicable(QAction*) const + { + const Scene_interface::Item_id index = scene->mainSelectionIndex(); + if (qobject_cast(scene->item(index))) + return true; + else if (qobject_cast(scene->item(index))) + return true; + else + return false; + } + + + +public Q_SLOTS: + void smooth() + { + const Scene_interface::Item_id index = scene->mainSelectionIndex(); + Scene_polyhedron_item* poly_item = + qobject_cast(scene->item(index)); + Scene_polyhedron_selection_item* selection_item = + qobject_cast(scene->item(index)); + + //Create dialog box + QDialog dialog(mw); + Ui::Smoothing_dialog ui + = smooth_dialog(&dialog, poly_item, selection_item); + + //Get values + int i = dialog.exec(); + if (i == QDialog::Rejected) + { + std::cout << "Smoothing aborted" << std::endl; + return; + } + + // wait cursor + QApplication::setOverrideCursor(Qt::WaitCursor); + QTime time; + time.start(); + + std::cout << "Smoothing..." << std::endl; + + if(poly_item || selection_item) + { + Polyhedron& pmesh = *poly_item->polyhedron(); + CGAL::Polygon_mesh_processing::compatible_remeshing(pmesh, faces(pmesh), edges(pmesh), + CGAL::Polygon_mesh_processing::parameters::all_default()); + + } + else + { + std::cerr << "No smooth!" << std::endl; + } + + std::cout << " ok (" << time.elapsed() << " ms)" << std::endl; + + // default cursor + QApplication::restoreOverrideCursor(); + } + + + + + Ui::Smoothing_dialog smooth_dialog(QDialog* dialog, Scene_polyhedron_item* poly_item, Scene_polyhedron_selection_item* selection_item) + { + + Ui::Smoothing_dialog ui; + ui.setupUi(dialog); + connect(ui.buttonBox, SIGNAL(accepted()), dialog, SLOT(accept())); + connect(ui.buttonBox, SIGNAL(rejected()), dialog, SLOT(reject())); + + //Set default parameters + Scene_interface::Bbox bbox = poly_item != NULL ? poly_item->bbox() + : (selection_item != NULL ? selection_item->bbox() + : scene->bbox()); + ui.objectName->setText(poly_item != NULL ? poly_item->name() + : (selection_item != NULL ? selection_item->name() + : QString("Remeshing parameters"))); + + ui.objectNameSize->setText( + tr("Object bbox size (w,h,d): %1, %2, %3") + .arg(bbox.xmax() - bbox.xmin(), 0, 'g', 3) + .arg(bbox.ymax() - bbox.ymin(), 0, 'g', 3) + .arg(bbox.zmax() - bbox.zmin(), 0, 'g', 3)); + + double diago_length = CGAL::sqrt((bbox.xmax() - bbox.xmin())*(bbox.xmax() - bbox.xmin()) + + (bbox.ymax() - bbox.ymin())*(bbox.ymax() - bbox.ymin()) + + (bbox.zmax() - bbox.zmin())*(bbox.zmax() - bbox.zmin())); + double log = std::log10(diago_length); + unsigned int nb_decimals = (log > 0) ? 5 : (std::ceil(-log) + 3); + + + return ui; + } + + +private: + Scene_interface *scene; + QMainWindow* mw; + QAction* actionSmoothing_; + + + +}; + + + +#include "Smoothing_plugin.moc" + + + + + + + + + + + + + + + + + + diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.ui b/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.ui new file mode 100644 index 00000000000..88022b133c4 --- /dev/null +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.ui @@ -0,0 +1,78 @@ + + + Smoothing_dialog + + + + 0 + 0 + 413 + 331 + + + + Dialog + + + + + + NO OBJECT + + + + + + + No size + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + Smoothing_dialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + Smoothing_dialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + From ee051f18e932561becd175175b346cf7ad817cd7 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Sun, 9 Jul 2017 13:13:17 +0300 Subject: [PATCH 037/102] fix vector_property_map and vertex_point map --- .../internal/Isotropic_remeshing/smoothing_impl.h | 4 ++-- .../include/CGAL/Polygon_mesh_processing/smoothing.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h index b7bb99d20fe..25f6bc40b60 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h @@ -12,7 +12,6 @@ #include - namespace CGAL { namespace Polygon_mesh_processing { @@ -121,7 +120,8 @@ public: { std::map barycenters; - boost::vector_property_map n_map; + //boost::vector_property_map n_map; + std::map n_map; for(vertex_descriptor v : vertices(mesh_)) { diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h index 9b5a1ce6ae2..9d533b63a9f 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h @@ -44,9 +44,9 @@ void compatible_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const Edg typedef typename GetGeomTraits::type GeomTraits; //vpmap - typedef typename GetVertexPointMap::const_type VertexPointMap; + typedef typename GetVertexPointMap::type VertexPointMap; VertexPointMap vpmap = choose_param(get_param(np, internal_np::vertex_point), - get_const_property_map(CGAL::vertex_point, pmesh)); + get_property_map(CGAL::vertex_point, pmesh)); //vcmap typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; From cf2dd45c4cc09478d59a619448e1882975703a6e Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Sun, 9 Jul 2017 17:16:31 +0300 Subject: [PATCH 038/102] compatible remeshing works via demo plugin --- .../Plugins/PMP/Smoothing_plugin.cpp | 70 ++++++--- .../Plugins/PMP/Smoothing_plugin.ui | 145 ++++++++++++++---- 2 files changed, 161 insertions(+), 54 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.cpp index 01b0c89c6ef..8aacac6a6ef 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.cpp @@ -1,5 +1,13 @@ #include +#include +#include +#include +#include +#include +#include +#include +#include #include @@ -11,24 +19,13 @@ #include #include #include +#include +#include #include #include #include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - #include "ui_Smoothing_plugin.h" @@ -97,6 +94,10 @@ public Q_SLOTS: return; } + bool weights_flag = ui.angle_weights_checkBox->isChecked(); + double gd_precision = ui.gradient_descent_doubleSpinBox->value(); + unsigned int nb_iterations = ui.iterations_spinBox->value(); + // wait cursor QApplication::setOverrideCursor(Qt::WaitCursor); QTime time; @@ -107,13 +108,29 @@ public Q_SLOTS: if(poly_item || selection_item) { Polyhedron& pmesh = *poly_item->polyhedron(); - CGAL::Polygon_mesh_processing::compatible_remeshing(pmesh, faces(pmesh), edges(pmesh), - CGAL::Polygon_mesh_processing::parameters::all_default()); + CGAL::Polygon_mesh_processing::compatible_remeshing(pmesh, + faces(pmesh), + edges(pmesh), + CGAL::Polygon_mesh_processing::parameters::use_weights(weights_flag) + .number_of_iterations(nb_iterations) + .gradient_descent_precision(gd_precision)); + + // to fix + if(poly_item) + { + poly_item->invalidateOpenGLBuffers(); + Q_EMIT poly_item->itemChanged(); + } + else + { + std::cerr<<"selection_item!"<bbox() - : (selection_item != NULL ? selection_item->bbox() - : scene->bbox()); + : (selection_item != NULL ? selection_item->bbox() : scene->bbox()); ui.objectName->setText(poly_item != NULL ? poly_item->name() - : (selection_item != NULL ? selection_item->name() - : QString("Remeshing parameters"))); + : (selection_item != NULL ? selection_item->name() : QString("Smoothing parameters"))); ui.objectNameSize->setText( tr("Object bbox size (w,h,d): %1, %2, %3") @@ -151,8 +162,17 @@ public Q_SLOTS: + (bbox.ymax() - bbox.ymin())*(bbox.ymax() - bbox.ymin()) + (bbox.zmax() - bbox.zmin())*(bbox.zmax() - bbox.zmin())); double log = std::log10(diago_length); - unsigned int nb_decimals = (log > 0) ? 5 : (std::ceil(-log) + 3); + unsigned int nb_decimals = (log > 0) ? 3 : (std::ceil(-log) + 3); + // default values + ui.angle_weights_checkBox->setChecked(false); + + ui.gradient_descent_doubleSpinBox->setDecimals(nb_decimals); + ui.gradient_descent_doubleSpinBox->setSingleStep(1e-3); + ui.gradient_descent_doubleSpinBox->setValue(0.001); + + ui.iterations_spinBox->setValue(1); + ui.iterations_spinBox->setMinimum(1); return ui; } diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.ui b/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.ui index 88022b133c4..0434bed4cdb 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.ui +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.ui @@ -6,39 +6,126 @@ 0 0 - 413 - 331 + 411 + 312 - Dialog + Smoothing parameters - - - - - NO OBJECT - - - - - - - No size - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - + + + + 9 + 9 + 391 + 26 + + + + + 15 + 75 + true + + + + NO OBJECT + + + + + + 10 + 40 + 391 + 20 + + + + No size + + + + + + 240 + 270 + 166 + 28 + + + + Qt::LeftToRight + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + 10 + 110 + 391 + 145 + + + + Options + + + + 10 + + + + + Use angle weights + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + + Number of iterations + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Gradient descent precision + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + From 250c6522419a78e46e0becfbecc574f5e099f558 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Mon, 10 Jul 2017 14:31:26 +0300 Subject: [PATCH 039/102] typo --- Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.cpp index 8aacac6a6ef..664d7d5d373 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.cpp @@ -23,8 +23,6 @@ #include #include -#include -#include #include "ui_Smoothing_plugin.h" From 929364619350338cf0b240ff0f7cd2e906e0a93a Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Mon, 10 Jul 2017 21:54:10 +0300 Subject: [PATCH 040/102] add tests for invalid meshes and adjust tolerance a bit to comply with some extreme cases --- .../internal/Isotropic_remeshing/smoothing_impl.h | 2 +- .../Polygon_mesh_processing/test_compatible_remeshing.cpp | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h index 25f6bc40b60..c277139d3ba 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h @@ -527,7 +527,7 @@ private: // check degenerate cases - double tolerance = 1e-5; // to think about it + double tolerance = 1e-3; // to think about it if ( edge1.squared_length() < tolerance || edge2.squared_length() < tolerance || diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_compatible_remeshing.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_compatible_remeshing.cpp index 1c7f173e122..78d32787567 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_compatible_remeshing.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_compatible_remeshing.cpp @@ -49,7 +49,9 @@ int main(int argc, char* argv[]){ "data/tetra3", "data/tetra4", "data/two_tris_collinear", - "data/U" + "data/U", + "data/elephant-invalid", + "data/mech-holes-shark-invalid" }; From 9d1f09921c32f6dd6438ead498b50a008202f308 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Fri, 14 Jul 2017 13:03:21 +0300 Subject: [PATCH 041/102] cotangent weights calculation --- .../Isotropic_remeshing/curvature_flow_impl.h | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h index 7298ccff075..e5b15719585 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h @@ -1,7 +1,7 @@ #ifndef CURVATURE_FLOW_IMPL_H #define CURVATURE_FLOW_IMPL_H - +#include namespace CGAL { @@ -11,7 +11,6 @@ namespace internal { - template class Curvature_flow { @@ -20,27 +19,38 @@ class Curvature_flow + + + + + public: - Curvature_flow(PolygonMesh& pmesh, VertexPointMap& vpmap) : mesh_(pmesh), vpmap_(vpmap) + Curvature_flow(PolygonMesh& pmesh, VertexPointMap& vpmap) : mesh_(pmesh), vpmap_(vpmap), + cot_calculator_(pmesh_, vpmap_) {} + // k = div n - // cot a = v1 * v2 / v1 x v2 private: - PolygonMesh& mesh_; + PolygonMesh& pmesh_; VertexPointMap& vpmap_; + // Cotagent calculator class + CGAL::internal::Cotangent_value_Meyer< + PolygonMesh, + typename boost::property_map::type > cot_calculator_; + }; From f1d2339d1a612862528fe7892b18001b23911dac Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Sun, 16 Jul 2017 20:43:26 +0300 Subject: [PATCH 042/102] calculate mean curvature flow with Monge jet fitting --- .../Isotropic_remeshing/curvature_flow_impl.h | 113 ++++++++++++++++-- .../Isotropic_remeshing/smoothing_impl.h | 1 + .../CGAL/Polygon_mesh_processing/smoothing.h | 7 +- 3 files changed, 111 insertions(+), 10 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h index e5b15719585..17c6e0210a8 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h @@ -2,6 +2,7 @@ #define CURVATURE_FLOW_IMPL_H #include +#include namespace CGAL { @@ -11,16 +12,20 @@ namespace internal { -template +template class Curvature_flow { + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename CGAL::Monge_via_jet_fitting Monge_via_jet_fitting; + typedef typename Monge_via_jet_fitting::Monge_form Monge_form; - - - + typedef typename GeomTraits::Point_3 Point; + typedef typename GeomTraits::Vector_3 Vector; + typedef typename GeomTraits::FT FT; @@ -28,14 +33,46 @@ public: Curvature_flow(PolygonMesh& pmesh, VertexPointMap& vpmap) : mesh_(pmesh), vpmap_(vpmap), - cot_calculator_(pmesh_, vpmap_) - {} + cot_calculator_(mesh_, vpmap_) + { + + //std::vector points + std::size_t num_points = vertices(mesh_).size(); + std::size_t min_num_of_points = 6; // (d+1)(d+2)/2, for d=2 + if(num_points < min_num_of_points) + { + CGAL_error_msg("Not enough points in the mesh."); + } + + } + void curvature_smoothing() + { + for(vertex_descriptor v : vertices(mesh_)) + { - // k = div n + if(!is_border(v, mesh_)) // add && !is_constrained + { + + + double k_mean = compute_mean_curvature(); + std::cout<<"ok"< incident_points = gather_all_points(); + + Monge_form monge_form; + Monge_via_jet_fitting monge_fit; + + std::size_t d_fit = 2; // d_fit >= d_monge + std::size_t d_monge = 2; // need 2 principal coeeficients + std::size_t Nd = (d_fit + 1)*(d_fit + 1) / 2.0; + CGAL_assertion(incident_points.size() >= Nd); + + monge_form = monge_fit(incident_points.begin(), incident_points.end(), d_fit, d_monge); + const FT k1 = monge_form.principal_curvatures(0); + const FT k2 = monge_form.principal_curvatures(1); + + return (k1 + k2) / 2.0; + } + + + std::vector points_around_vertex(vertex_descriptor v) + { + std::vector incident_vertices; + for(halfedge_descriptor h : halfedges_around_target(v, mesh_)) + { + vertex_descriptor vs = source(h, mesh_); + incident_vertices.push_back(get(vpmap_, vs)); + } + + // temp assertion + std::vector incident_vertices2; + for(vertex_descriptor vi : vertices_around_target(v, mesh_)) + { + incident_vertices2.push_back(get(vpmap_, vi)); + } + CGAL_assertion(incident_vertices.size() == incident_vertices2.size()); + + return incident_vertices; + } + + + std::vector gather_all_points() + { + std::vector points; // todo: preallocate it and fill it with pointing + for(vertex_descriptor v : vertices(mesh_)) + { + points.push_back(get(vpmap_, v)); + } + + return points; + } + + + + // data members + // ------------ + PolygonMesh& mesh_; + VertexPointMap& vpmap_; // Cotagent calculator class CGAL::internal::Cotangent_value_Meyer< PolygonMesh, diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h index c277139d3ba..d78982b25c2 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h @@ -5,6 +5,7 @@ #include #include +#include #include #include diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h index 9d533b63a9f..d0d52abcb77 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h @@ -140,7 +140,12 @@ void curvature_flow(PolygonMesh& pmesh, const NamedParameters& np) VertexPointMap vpmap = choose_param(get_param(np, internal_np::vertex_point), get_const_property_map(CGAL::vertex_point, pmesh)); - internal::Curvature_flow curvature_remesher(pmesh, vpmap); + // GeomTraits + typedef typename GetGeomTraits::type GeomTraits; + + internal::Curvature_flow curvature_remesher(pmesh, vpmap); + curvature_remesher.curvature_smoothing(); + } From 1b28c2d0323ece493a90f80c41399ecedb2b9689 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Mon, 17 Jul 2017 23:38:40 +0300 Subject: [PATCH 043/102] mean curvature smoothing - testing with and without cot angles in simple cases --- .../Isotropic_remeshing/curvature_flow_impl.h | 85 ++++++++++++++++++- .../Isotropic_remeshing/smoothing_impl.h | 1 + 2 files changed, 83 insertions(+), 3 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h index 17c6e0210a8..6715dd45640 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h @@ -4,6 +4,8 @@ #include #include +#include + namespace CGAL { namespace Polygon_mesh_processing { @@ -28,6 +30,10 @@ class Curvature_flow typedef typename GeomTraits::FT FT; + // + typedef std::pair He_pair; + typedef std::map Edges_around_map; + public: @@ -51,6 +57,10 @@ public: void curvature_smoothing() { + + std::map barycenters; + std::map n_map; + for(vertex_descriptor v : vertices(mesh_)) { @@ -58,16 +68,69 @@ public: { + // mean curvature double k_mean = compute_mean_curvature(); - std::cout<<"ok"<first; + He_pair inc_pair = it->second; + + std::pair a1a2 = cot_angles(main_he, inc_pair); + double weight = a1a2.first + a1a2.second; + sum_c += weight; + + displacement += Vector(get(vpmap_, source(main_he, mesh_)) - get(vpmap_, target(main_he, mesh_))); + displacement *= weight; + } + + displacement /= sum_c; + + barycenters[v] = get(vpmap_, v) + (displacement / halfedges_around_source(v, mesh_).size()) ; + Point new_location = barycenters[v] + k_mean * n_map[v]; // point + vector + + + // update location + put(vpmap_, v, new_location); - } + } // in not on border - } + } // all vertices @@ -102,6 +165,22 @@ private: return (k1 + k2) / 2.0; } + std::pair cot_angles(const halfedge_descriptor& main_he, const He_pair& incd_edges) + { + vertex_descriptor v0 = source(main_he, mesh_); + vertex_descriptor vs = target(main_he, mesh_); + vertex_descriptor v1 = target(incd_edges.first, mesh_); + vertex_descriptor v2 = source(incd_edges.second, mesh_); + CGAL_assertion(target(incd_edges.second, mesh_) == source(incd_edges.first, mesh_)); + + double a1 = cot_calculator_(v0, v1, vs); + double a2 = cot_calculator_(v0, v2, vs); + + // to check degeneracies + + return std::make_pair(a1, a2); + + } std::vector points_around_vertex(vertex_descriptor v) { diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h index d78982b25c2..e809c7b5a8b 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h @@ -4,6 +4,7 @@ #include #include +#include #include #include From f46a9b06ccf397dced5ef21b3c25c252e597d707 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Tue, 18 Jul 2017 15:06:47 +0300 Subject: [PATCH 044/102] add projection to initial surface on curvature smoothing --- .../Isotropic_remeshing/curvature_flow_impl.h | 61 ++++++++++++++++++- .../Isotropic_remeshing/smoothing_impl.h | 6 -- 2 files changed, 59 insertions(+), 8 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h index 6715dd45640..f59f9924736 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h @@ -4,6 +4,10 @@ #include #include +#include +#include +#include + #include namespace CGAL { @@ -20,6 +24,7 @@ class Curvature_flow typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename boost::graph_traits::face_descriptor face_descriptor; typedef typename CGAL::Monge_via_jet_fitting Monge_via_jet_fitting; @@ -28,6 +33,8 @@ class Curvature_flow typedef typename GeomTraits::Point_3 Point; typedef typename GeomTraits::Vector_3 Vector; typedef typename GeomTraits::FT FT; + typedef typename GeomTraits::Triangle_3 Triangle; + typedef std::vector Triangle_list; // @@ -35,6 +42,11 @@ class Curvature_flow typedef std::map Edges_around_map; + typedef CGAL::AABB_triangle_primitive AABB_Primitive; + typedef CGAL::AABB_traits AABB_Traits; + typedef CGAL::AABB_tree Tree; + + public: @@ -50,9 +62,25 @@ public: CGAL_error_msg("Not enough points in the mesh."); } + } + template + void init_remeshing(const FaceRange& face_range) + { + for (face_descriptor f : face_range) + { + input_triangles_.push_back(triangle(f)); + } + + tree_ptr_ = new Tree(input_triangles_.begin(), input_triangles_.end()); + tree_ptr_->accelerate_distance_queries(); + + //TODO: update constrained edges + //check_constrained_edges(); + } + void curvature_smoothing() @@ -79,6 +107,7 @@ public: n_map[v] = vn; + // find incident halfedges Edges_around_map he_map; typename Edges_around_map::iterator it; @@ -86,6 +115,7 @@ public: he_map[hi] = He_pair( next(hi, mesh_), prev(opposite(hi, mesh_), mesh_) ); + /* // find barycenter - without cot weights Vector displacement = CGAL::NULL_VECTOR; @@ -98,6 +128,8 @@ public: */ + + // with cotangent weights Vector displacement = CGAL::NULL_VECTOR; double sum_c = 0; @@ -121,6 +153,7 @@ public: Point new_location = barycenters[v] + k_mean * n_map[v]; // point + vector + // update location put(vpmap_, v, new_location); @@ -138,6 +171,19 @@ public: } + void project_to_surface() + { + for( vertex_descriptor v : vertices(mesh_)) + { + if(!is_border(v, mesh_) ) // todo: && !is_constrained(v) + { + Point p_query = get(vpmap_, v); + Point projected = tree_ptr_->closest_point(p_query); + put(vpmap_, v, projected); + } + } + } + @@ -205,7 +251,7 @@ private: std::vector gather_all_points() { - std::vector points; // todo: preallocate it and fill it with pointing + std::vector points; // todo: preallocate it and fill it by pointing for(vertex_descriptor v : vertices(mesh_)) { points.push_back(get(vpmap_, v)); @@ -214,6 +260,14 @@ private: return points; } + Triangle triangle(face_descriptor f) const + { + halfedge_descriptor h = halfedge(f, mesh_); + vertex_descriptor v1 = target(h, mesh_); + vertex_descriptor v2 = target(next(h, mesh_), mesh_); + vertex_descriptor v3 = target(next(next(h, mesh_), mesh_), mesh_); + return Triangle(get(vpmap_, v1), get(vpmap_, v2), get(vpmap_, v3)); + } // data members @@ -223,7 +277,10 @@ private: // Cotagent calculator class CGAL::internal::Cotangent_value_Meyer< PolygonMesh, - typename boost::property_map::type > cot_calculator_; + typename boost::property_map::type > cot_calculator_; + Triangle_list input_triangles_; + Tree* tree_ptr_; + }; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h index e809c7b5a8b..44b6bed37f5 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h @@ -264,19 +264,13 @@ std::cout<<" moved at: "<< vp.second << std::endl; { for( vertex_descriptor v : vertices(mesh_)) { - - // to check if is constrained - if(!is_border(v, mesh_) && !is_constrained(v)) { Point p_query = get(vpmap_, v); Point projected = tree_ptr_->closest_point(p_query); put(vpmap_, v, projected); - } - } - } From 7fbe5e156d88d25844609e098aeefc721f263ef1 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Tue, 18 Jul 2017 18:17:01 +0300 Subject: [PATCH 045/102] verbose info in smoothing.h and an overload --- .../CGAL/Polygon_mesh_processing/smoothing.h | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h index d0d52abcb77..5e353ff9f9d 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h @@ -126,6 +126,12 @@ void compatible_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const Edg } +template +void compatible_remeshing(PolygonMesh& pmesh) +{ + compatible_remeshing(pmesh, faces(pmesh), edges(pmesh), parameters::all_default()); +} + @@ -135,6 +141,13 @@ void curvature_flow(PolygonMesh& pmesh, const NamedParameters& np) using boost::choose_param; using boost::get_param; +#ifdef CGAL_PMP_REMESHING_VERBOSE + CGAL::Timer t; + std::cout << "Remeshing parameters..."; + std::cout.flush(); + t.start(); +#endif + //vpmap typedef typename GetVertexPointMap::const_type VertexPointMap; VertexPointMap vpmap = choose_param(get_param(np, internal_np::vertex_point), @@ -143,8 +156,36 @@ void curvature_flow(PolygonMesh& pmesh, const NamedParameters& np) // GeomTraits typedef typename GetGeomTraits::type GeomTraits; + +#ifdef CGAL_PMP_REMESHING_VERBOSE + t.stop(); + std::cout << "\rRemeshing parameters done ("<< t.time() <<" sec)" << std::endl; + std::cout << "Remesher construction..."; + std::cout.flush(); + t.reset(); t.start(); +#endif + + internal::Curvature_flow curvature_remesher(pmesh, vpmap); + curvature_remesher.init_remeshing(faces(pmesh)); + +#ifdef CGAL_PMP_REMESHING_VERBOSE + t.stop(); + std::cout << " done ("<< t.time() <<" sec)." << std::endl; + std::cout << "Remeshing ..." << std::endl; + t.reset(); t.start(); +#endif + curvature_remesher.curvature_smoothing(); + curvature_remesher.project_to_surface(); + + +#ifdef CGAL_PMP_REMESHING_VERBOSE + t.stop(); + std::cout << "Remeshing done in "; + std::cout << t.time() << " sec." << std::endl; + std::cout< Date: Tue, 18 Jul 2017 23:27:56 +0300 Subject: [PATCH 046/102] setup plugin for curvature flow --- .../Isotropic_remeshing/curvature_flow_impl.h | 9 +- .../CGAL/Polygon_mesh_processing/smoothing.h | 4 +- .../PMP/Curvature_smoothing_plugin.cpp | 131 ++++++++++++++++++ 3 files changed, 137 insertions(+), 7 deletions(-) create mode 100644 Polyhedron/demo/Polyhedron/Plugins/PMP/Curvature_smoothing_plugin.cpp diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h index f59f9924736..48a04c82b8b 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h @@ -17,7 +17,6 @@ namespace Polygon_mesh_processing { namespace internal { - template class Curvature_flow { @@ -47,11 +46,12 @@ class Curvature_flow typedef CGAL::AABB_tree Tree; + + public: - Curvature_flow(PolygonMesh& pmesh, VertexPointMap& vpmap) : mesh_(pmesh), vpmap_(vpmap), - cot_calculator_(mesh_, vpmap_) + Curvature_flow(PolygonMesh& pmesh, VertexPointMap& vpmap) : mesh_(pmesh), vpmap_(vpmap), cot_calculator_(pmesh, vpmap) { //std::vector points @@ -276,8 +276,7 @@ private: VertexPointMap& vpmap_; // Cotagent calculator class CGAL::internal::Cotangent_value_Meyer< - PolygonMesh, - typename boost::property_map::type > cot_calculator_; + PolygonMesh, VertexPointMap> cot_calculator_; Triangle_list input_triangles_; Tree* tree_ptr_; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h index 5e353ff9f9d..f2553415ff0 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h @@ -149,9 +149,9 @@ void curvature_flow(PolygonMesh& pmesh, const NamedParameters& np) #endif //vpmap - typedef typename GetVertexPointMap::const_type VertexPointMap; + typedef typename GetVertexPointMap::type VertexPointMap; VertexPointMap vpmap = choose_param(get_param(np, internal_np::vertex_point), - get_const_property_map(CGAL::vertex_point, pmesh)); + get_property_map(CGAL::vertex_point, pmesh)); // GeomTraits typedef typename GetGeomTraits::type GeomTraits; diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Curvature_smoothing_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Curvature_smoothing_plugin.cpp new file mode 100644 index 00000000000..80749b79e39 --- /dev/null +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Curvature_smoothing_plugin.cpp @@ -0,0 +1,131 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "Scene_polyhedron_item.h" +#include "Scene_polyhedron_selection_item.h" +#include "Polyhedron_type.h" + +#include +#include +#include +#include +#include +#include + +#include + + + +using namespace CGAL::Three; +class Polyhedron_demo_smothing_plugin : + public QObject, + public Polyhedron_demo_plugin_interface +{ + Q_OBJECT + Q_INTERFACES(CGAL::Three::Polyhedron_demo_plugin_interface) + Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.PluginInterface/1.0") + + +public: + void init(QMainWindow* mainWindow, + Scene_interface* scene_interface, + Messages_interface*) + { + this->scene = scene_interface; + this->mw = mainWindow; + + actionCurvatureSmoothing_ = new QAction("Mean curvature flow smoothing", mw); + actionCurvatureSmoothing_->setProperty("subMenuName", "Polygon Mesh Processing"); + if (actionCurvatureSmoothing_) { + connect(actionCurvatureSmoothing_, SIGNAL(triggered()), + this, SLOT(smooth())); + } + } + + QList actions() const { + return QList() << actionCurvatureSmoothing_; + } + + bool applicable(QAction*) const + { + const Scene_interface::Item_id index = scene->mainSelectionIndex(); + if (qobject_cast(scene->item(index))) + return true; + else + return false; + } + + + +public Q_SLOTS: + void smooth() + { + const Scene_interface::Item_id index = scene->mainSelectionIndex(); + Scene_polyhedron_item* poly_item = + qobject_cast(scene->item(index)); + + // wait cursor + QApplication::setOverrideCursor(Qt::WaitCursor); + QTime time; + time.start(); + + std::cout << "Smoothing..." << std::endl; + + if(poly_item) + { + Polyhedron& pmesh = *poly_item->polyhedron(); + CGAL::Polygon_mesh_processing::curvature_flow(pmesh); + + // to fix + if(poly_item) + { + poly_item->invalidateOpenGLBuffers(); + Q_EMIT poly_item->itemChanged(); + } + else + { + std::cerr<<"selection_item!"< Date: Thu, 20 Jul 2017 14:35:53 +0300 Subject: [PATCH 047/102] normalize kn --- .../Isotropic_remeshing/curvature_flow_impl.h | 34 ++++++------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h index 48a04c82b8b..3a535ce5b2f 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h @@ -2,6 +2,8 @@ #define CURVATURE_FLOW_IMPL_H #include +#include + #include #include @@ -104,7 +106,13 @@ public: Vector vn = compute_vertex_normal(v, mesh_, Polygon_mesh_processing::parameters::vertex_point_map(vpmap_) .geom_traits(GeomTraits())); - n_map[v] = vn; + + + // normalize (kn) + Vector kn = k_mean * vn; + normalize(kn, GeomTraits()); + + n_map[v] = kn; @@ -116,7 +124,7 @@ public: - /* + // find barycenter - without cot weights Vector displacement = CGAL::NULL_VECTOR; for(halfedge_descriptor hi : halfedges_around_source(v, mesh_)) @@ -124,33 +132,13 @@ public: displacement += Vector(get(vpmap_, target(hi, mesh_)) - get(vpmap_, source(hi, mesh_))); } barycenters[v] = get(vpmap_, v) + (displacement / halfedges_around_source(v, mesh_).size()) ; - Point new_location = barycenters[v] + k_mean * n_map[v]; // point + vector - */ + Point new_location = barycenters[v] + n_map[v]; // point + vector - // with cotangent weights - Vector displacement = CGAL::NULL_VECTOR; - double sum_c = 0; - for(it = he_map.begin(); it != he_map.end(); ++it) - { - halfedge_descriptor main_he = it->first; - He_pair inc_pair = it->second; - std::pair a1a2 = cot_angles(main_he, inc_pair); - double weight = a1a2.first + a1a2.second; - sum_c += weight; - - displacement += Vector(get(vpmap_, source(main_he, mesh_)) - get(vpmap_, target(main_he, mesh_))); - displacement *= weight; - } - - displacement /= sum_c; - - barycenters[v] = get(vpmap_, v) + (displacement / halfedges_around_source(v, mesh_).size()) ; - Point new_location = barycenters[v] + k_mean * n_map[v]; // point + vector From 29dc7c968a9b24fbea82658711c172dd65454604 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Thu, 20 Jul 2017 17:49:41 +0300 Subject: [PATCH 048/102] find new location using cot weigths --- .../Isotropic_remeshing/curvature_flow_impl.h | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h index 3a535ce5b2f..9279a7b79d5 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h @@ -124,7 +124,7 @@ public: - + /* // find barycenter - without cot weights Vector displacement = CGAL::NULL_VECTOR; for(halfedge_descriptor hi : halfedges_around_source(v, mesh_)) @@ -133,9 +133,38 @@ public: } barycenters[v] = get(vpmap_, v) + (displacement / halfedges_around_source(v, mesh_).size()) ; Point new_location = barycenters[v] + n_map[v]; // point + vector + */ + // with cot weights + Vector weighted_barycenter = CGAL::NULL_VECTOR; + double sum_c = 0; + for(it = he_map.begin(); it!= he_map.end(); ++it) + { + halfedge_descriptor hi = it->first; + + //weight + std::pair a1a2 = cot_angles(hi, it->second); //check if correct + double weight = a1a2.first + a1a2.second; + sum_c += weight; + + // displacement vector + Vector vec(get(vpmap_, target(hi, mesh_)) - get(vpmap_, source(hi, mesh_))); + // add weight + vec *= weight; + // sum vecs + weighted_barycenter += vec; + + } + + // divide with total weight + weighted_barycenter /= sum_c; + + + + + Point new_location = get(vpmap_, v) + weighted_barycenter; // + kn ? From 22562eec110816bafa3ca3145fd008815f13ad75 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Fri, 21 Jul 2017 12:13:16 +0300 Subject: [PATCH 049/102] plugin: dock widget design & support both compatible and curvature --- .../PMP/Curvature_smoothing_plugin.cpp | 131 ------------- .../Plugins/PMP/Smoothing_plugin.cpp | 163 +++++----------- .../Plugins/PMP/Smoothing_plugin.ui | 182 +++--------------- 3 files changed, 84 insertions(+), 392 deletions(-) delete mode 100644 Polyhedron/demo/Polyhedron/Plugins/PMP/Curvature_smoothing_plugin.cpp diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Curvature_smoothing_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Curvature_smoothing_plugin.cpp deleted file mode 100644 index 80749b79e39..00000000000 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Curvature_smoothing_plugin.cpp +++ /dev/null @@ -1,131 +0,0 @@ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "Scene_polyhedron_item.h" -#include "Scene_polyhedron_selection_item.h" -#include "Polyhedron_type.h" - -#include -#include -#include -#include -#include -#include - -#include - - - -using namespace CGAL::Three; -class Polyhedron_demo_smothing_plugin : - public QObject, - public Polyhedron_demo_plugin_interface -{ - Q_OBJECT - Q_INTERFACES(CGAL::Three::Polyhedron_demo_plugin_interface) - Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.PluginInterface/1.0") - - -public: - void init(QMainWindow* mainWindow, - Scene_interface* scene_interface, - Messages_interface*) - { - this->scene = scene_interface; - this->mw = mainWindow; - - actionCurvatureSmoothing_ = new QAction("Mean curvature flow smoothing", mw); - actionCurvatureSmoothing_->setProperty("subMenuName", "Polygon Mesh Processing"); - if (actionCurvatureSmoothing_) { - connect(actionCurvatureSmoothing_, SIGNAL(triggered()), - this, SLOT(smooth())); - } - } - - QList actions() const { - return QList() << actionCurvatureSmoothing_; - } - - bool applicable(QAction*) const - { - const Scene_interface::Item_id index = scene->mainSelectionIndex(); - if (qobject_cast(scene->item(index))) - return true; - else - return false; - } - - - -public Q_SLOTS: - void smooth() - { - const Scene_interface::Item_id index = scene->mainSelectionIndex(); - Scene_polyhedron_item* poly_item = - qobject_cast(scene->item(index)); - - // wait cursor - QApplication::setOverrideCursor(Qt::WaitCursor); - QTime time; - time.start(); - - std::cout << "Smoothing..." << std::endl; - - if(poly_item) - { - Polyhedron& pmesh = *poly_item->polyhedron(); - CGAL::Polygon_mesh_processing::curvature_flow(pmesh); - - // to fix - if(poly_item) - { - poly_item->invalidateOpenGLBuffers(); - Q_EMIT poly_item->itemChanged(); - } - else - { - std::cerr<<"selection_item!"< #include #include +#include #include #include #include #include #include +#include #include "Scene_polyhedron_item.h" #include "Scene_polyhedron_selection_item.h" @@ -30,7 +32,7 @@ using namespace CGAL::Three; class Polyhedron_demo_smothing_plugin : public QObject, - public Polyhedron_demo_plugin_interface + public Polyhedron_demo_plugin_helper { Q_OBJECT Q_INTERFACES(CGAL::Three::Polyhedron_demo_plugin_interface) @@ -38,24 +40,32 @@ class Polyhedron_demo_smothing_plugin : public: - void init(QMainWindow* mainWindow, - Scene_interface* scene_interface, - Messages_interface*) + void init(QMainWindow* mainWindow, Scene_interface* scene_interface, Messages_interface*) { - this->scene = scene_interface; - this->mw = mainWindow; + scene = scene_interface; + mw = mainWindow; + + actionSmoothing_ = new QAction(tr("Smoothing"), mw); + actionSmoothing_->setProperty("subMenuName", "Polygon Mesh Processing"); + + + connect(actionSmoothing_, SIGNAL(triggered()), this, SLOT(smoothing_action())); + + dock_widget = new QDockWidget("Smoothing", mw); + dock_widget->setVisible(false); + + ui_widget.setupUi(dock_widget); + addDockWidget(dock_widget); + + connect(ui_widget.Compatible_button, SIGNAL(clicked()), this, SLOT(on_Compatible_button_clicked())); + connect(ui_widget.Curvature_button, SIGNAL(clicked()), this, SLOT(on_Curvature_button_clicked())); - actionSmoothing_ = new QAction("Smoothing", mw); - actionSmoothing_->setProperty("subMenuName", "Polygon Mesh Processing"); - if (actionSmoothing_) { - connect(actionSmoothing_, SIGNAL(triggered()), - this, SLOT(smooth())); - } } - QList actions() const { + QList actions() const + { return QList() << actionSmoothing_; - } + } bool applicable(QAction*) const { @@ -68,118 +78,49 @@ public: return false; } - - -public Q_SLOTS: - void smooth() + virtual void closure() { - const Scene_interface::Item_id index = scene->mainSelectionIndex(); - Scene_polyhedron_item* poly_item = - qobject_cast(scene->item(index)); - Scene_polyhedron_selection_item* selection_item = - qobject_cast(scene->item(index)); - - //Create dialog box - QDialog dialog(mw); - Ui::Smoothing_dialog ui - = smooth_dialog(&dialog, poly_item, selection_item); - - //Get values - int i = dialog.exec(); - if (i == QDialog::Rejected) - { - std::cout << "Smoothing aborted" << std::endl; - return; - } - - bool weights_flag = ui.angle_weights_checkBox->isChecked(); - double gd_precision = ui.gradient_descent_doubleSpinBox->value(); - unsigned int nb_iterations = ui.iterations_spinBox->value(); - - // wait cursor - QApplication::setOverrideCursor(Qt::WaitCursor); - QTime time; - time.start(); - - std::cout << "Smoothing..." << std::endl; - - if(poly_item || selection_item) - { - Polyhedron& pmesh = *poly_item->polyhedron(); - CGAL::Polygon_mesh_processing::compatible_remeshing(pmesh, - faces(pmesh), - edges(pmesh), - CGAL::Polygon_mesh_processing::parameters::use_weights(weights_flag) - .number_of_iterations(nb_iterations) - .gradient_descent_precision(gd_precision)); - - // to fix - if(poly_item) - { - poly_item->invalidateOpenGLBuffers(); - Q_EMIT poly_item->itemChanged(); - } - else - { - std::cerr<<"selection_item!"<hide(); } - Ui::Smoothing_dialog smooth_dialog(QDialog* dialog, Scene_polyhedron_item* poly_item, Scene_polyhedron_selection_item* selection_item) +public Q_SLOTS: + void smoothing_action() { - Ui::Smoothing_dialog ui; - ui.setupUi(dialog); - connect(ui.buttonBox, SIGNAL(accepted()), dialog, SLOT(accept())); - connect(ui.buttonBox, SIGNAL(rejected()), dialog, SLOT(reject())); + dock_widget->show(); + dock_widget->raise(); + } - //Set default parameters - Scene_interface::Bbox bbox = poly_item != NULL ? poly_item->bbox() - : (selection_item != NULL ? selection_item->bbox() : scene->bbox()); - ui.objectName->setText(poly_item != NULL ? poly_item->name() - : (selection_item != NULL ? selection_item->name() : QString("Smoothing parameters"))); + void on_Compatible_button_clicked() + { + const Scene_interface::Item_id index = scene->mainSelectionIndex(); + Scene_polyhedron_item* poly_item = qobject_cast(scene->item(index)); - ui.objectNameSize->setText( - tr("Object bbox size (w,h,d): %1, %2, %3") - .arg(bbox.xmax() - bbox.xmin(), 0, 'g', 3) - .arg(bbox.ymax() - bbox.ymin(), 0, 'g', 3) - .arg(bbox.zmax() - bbox.zmin(), 0, 'g', 3)); + Polyhedron& pmesh = *poly_item->polyhedron(); + CGAL::Polygon_mesh_processing::compatible_remeshing(pmesh); - double diago_length = CGAL::sqrt((bbox.xmax() - bbox.xmin())*(bbox.xmax() - bbox.xmin()) - + (bbox.ymax() - bbox.ymin())*(bbox.ymax() - bbox.ymin()) - + (bbox.zmax() - bbox.zmin())*(bbox.zmax() - bbox.zmin())); - double log = std::log10(diago_length); - unsigned int nb_decimals = (log > 0) ? 3 : (std::ceil(-log) + 3); + poly_item->invalidateOpenGLBuffers(); + Q_EMIT poly_item->itemChanged(); + QApplication::restoreOverrideCursor(); + } - // default values - ui.angle_weights_checkBox->setChecked(false); + void on_Curvature_button_clicked() + { + const Scene_interface::Item_id index = scene->mainSelectionIndex(); + Scene_polyhedron_item* poly_item = qobject_cast(scene->item(index)); - ui.gradient_descent_doubleSpinBox->setDecimals(nb_decimals); - ui.gradient_descent_doubleSpinBox->setSingleStep(1e-3); - ui.gradient_descent_doubleSpinBox->setValue(0.001); + Polyhedron& pmesh = *poly_item->polyhedron(); + CGAL::Polygon_mesh_processing::curvature_flow(pmesh); - ui.iterations_spinBox->setValue(1); - ui.iterations_spinBox->setMinimum(1); - - return ui; + poly_item->invalidateOpenGLBuffers(); + Q_EMIT poly_item->itemChanged(); + QApplication::restoreOverrideCursor(); } private: - Scene_interface *scene; - QMainWindow* mw; QAction* actionSmoothing_; + QDockWidget* dock_widget; + Ui::Smoothing ui_widget; diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.ui b/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.ui index 0434bed4cdb..17036176c6c 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.ui +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.ui @@ -1,165 +1,47 @@ - Smoothing_dialog - + Smoothing + 0 0 - 411 - 312 + 400 + 300 - Smoothing parameters + Smoothing options - - - - 9 - 9 - 391 - 26 - - - - - 15 - 75 - true - - - - NO OBJECT - - - - - - 10 - 40 - 391 - 20 - - - - No size - - - - - - 240 - 270 - 166 - 28 - - - - Qt::LeftToRight - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - 10 - 110 - 391 - 145 - - - - Options - - - - 10 + + + + + 90 + 60 + 221 + 51 + - - - - Use angle weights - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - - - - - Number of iterations - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Gradient descent precision - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - + + Compatible remeshing + + + + + + 90 + 120 + 221 + 51 + + + + Curvature flow + + - - - buttonBox - accepted() - Smoothing_dialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - Smoothing_dialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - + From 46c524ecaf48c7fa52735d513e89d603fc471c03 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Sat, 22 Jul 2017 14:26:07 +0300 Subject: [PATCH 050/102] curvature example in cmakelists --- .../examples/Polygon_mesh_processing/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt index 926cedbf8b9..dfe55191d3d 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt @@ -102,6 +102,7 @@ create_single_source_cgal_program( "corefinement_difference_remeshed.cpp" ) create_single_source_cgal_program( "corefinement_mesh_union.cpp" ) create_single_source_cgal_program( "corefinement_polyhedron_union.cpp" ) create_single_source_cgal_program( "smoothing_example.cpp") +create_single_source_cgal_program( "curvature_flow_example.cpp") From 493992978ccc9a94d9396653762019c013ebecef Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Mon, 24 Jul 2017 17:31:35 +0300 Subject: [PATCH 051/102] remove degenerate edges and faces --- .../Isotropic_remeshing/curvature_flow_impl.h | 199 ++++++++++++++++-- .../CGAL/Polygon_mesh_processing/smoothing.h | 11 + 2 files changed, 195 insertions(+), 15 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h index 9279a7b79d5..337ec567d8f 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h @@ -5,12 +5,17 @@ #include #include - #include #include #include +#include + +#include +#include + #include +#include namespace CGAL { @@ -26,6 +31,9 @@ class Curvature_flow typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::face_descriptor face_descriptor; + typedef typename boost::graph_traits::edge_descriptor edge_descriptor; + typedef typename boost::graph_traits::vertex_iterator vertex_iterator; + typedef typename CGAL::Monge_via_jet_fitting Monge_via_jet_fitting; @@ -57,13 +65,14 @@ public: { //std::vector points - std::size_t num_points = vertices(mesh_).size(); + /* std::size_t num_points = vertices(mesh_).size(); std::size_t min_num_of_points = 6; // (d+1)(d+2)/2, for d=2 if(num_points < min_num_of_points) { CGAL_error_msg("Not enough points in the mesh."); } + */ } @@ -79,11 +88,101 @@ public: tree_ptr_ = new Tree(input_triangles_.begin(), input_triangles_.end()); tree_ptr_->accelerate_distance_queries(); + + min_edge_len_ = init_min_edge_length(); + //TODO: update constrained edges //check_constrained_edges(); + } + // fixing degenerates + + std::size_t remove_degenerate_faces() + { + std::size_t nb_removed_faces = 0; + for(face_descriptor f : faces(mesh_)) + { + Triangle tr = triangle(f); + if(tr.is_degenerate()) + { + halfedge_descriptor he = halfedge(f, mesh_); + Euler::remove_face(he, mesh_); + nb_removed_faces++; + } + } + + return nb_removed_faces; + } + + + + + std::size_t collapse_short_edges() + { + std::size_t nb_collapsed_edges = 0; + + std::set edges_to_collapse, non_topologically_valid_collapses; + + + // collect short edges + for(edge_descriptor e : edges(mesh_)) + { + if(edge_should_collapse(e)) + { + edges_to_collapse.insert(e); + } + } + + + + // collapse + while(!edges_to_collapse.empty()) + { + edge_descriptor e = *edges_to_collapse.begin(); + edges_to_collapse.erase(edges_to_collapse.begin()); + + // link condition + if(!Euler::does_satisfy_link_condition(e, mesh_)) + { + non_topologically_valid_collapses.insert(e); + CGAL_assertion(non_topologically_valid_collapses.empty()); + continue; + } + + halfedge_descriptor he = halfedge(e, mesh_); + vertex_descriptor vs = source(he, mesh_); + vertex_descriptor vt = target(he, mesh_); + + vertex_descriptor v = Euler::collapse_edge(e, mesh_); + + + for (edge_descriptor out_e : out_edges(v, mesh_)) + { + if(edge_should_collapse(out_e)) + { + edges_to_collapse.insert(out_e); + } + } + + + nb_collapsed_edges++; + + + + } + + + std::cout<<"nb_collapsed_edges: "< a1a2 = cot_angles(hi, it->second); //check if correct double weight = a1a2.first + a1a2.second; + sum_c += weight; + CGAL_assertion(!isinf(sum_c)); // displacement vector Vector vec(get(vpmap_, target(hi, mesh_)) - get(vpmap_, source(hi, mesh_))); @@ -207,7 +312,78 @@ public: private: + // start degenerate fixing functions + bool edge_should_collapse(edge_descriptor e) + { + halfedge_descriptor he = halfedge(e, mesh_); + Point s = get(vpmap_, source(he, mesh_)); + Point t = get(vpmap_, target(he, mesh_)); + + double sq_length = traits_.compute_squared_distance_3_object()(s, t); + + if(sq_length < min_edge_len_) + return true; + else + return false; + } + + struct Vertex_to_point + { + Vertex_to_point(VertexPointMap vpmap) : vpmap(vpmap){} + + typedef typename boost::property_traits::reference output_type; + + output_type operator()(vertex_descriptor vd) const + { + return get(vpmap, vd); + } + + VertexPointMap vpmap; + }; + + + double init_min_edge_length() + { + vertex_iterator vi, ve; + std::pair vp; + + boost::tie(vi, ve) = vertices(mesh_); + + // to improve + Vertex_to_point v_to_p(vpmap_); + + Bbox_3 bbox= CGAL::bbox_3(boost::make_transform_iterator(vi, v_to_p), boost::make_transform_iterator(ve, v_to_p)); + + //try with .begin() + + return 0.01 * diagonal_length(bbox); + } + + double diagonal_length(const Bbox_3& bbox) + { + double dx = bbox.xmax() - bbox.xmin(); + double dy = bbox.ymax() - bbox.ymin(); + double dz = bbox.zmax() - bbox.zmin(); + + double diag = dx * dx + dy * dy + dz * dz; + return std::sqrt(diag); + } + + + // end degenerate functions + + + Triangle triangle(face_descriptor f) const + { + halfedge_descriptor h = halfedge(f, mesh_); + vertex_descriptor v1 = target(h, mesh_); + vertex_descriptor v2 = target(next(h, mesh_), mesh_); + vertex_descriptor v3 = target(next(next(h, mesh_), mesh_), mesh_); + return Triangle(get(vpmap_, v1), get(vpmap_, v2), get(vpmap_, v3)); + } + +/* double compute_mean_curvature() { // gather points around v @@ -227,7 +403,7 @@ private: return (k1 + k2) / 2.0; } - +*/ std::pair cot_angles(const halfedge_descriptor& main_he, const He_pair& incd_edges) { vertex_descriptor v0 = source(main_he, mesh_); @@ -277,15 +453,6 @@ private: return points; } - Triangle triangle(face_descriptor f) const - { - halfedge_descriptor h = halfedge(f, mesh_); - vertex_descriptor v1 = target(h, mesh_); - vertex_descriptor v2 = target(next(h, mesh_), mesh_); - vertex_descriptor v3 = target(next(next(h, mesh_), mesh_), mesh_); - return Triangle(get(vpmap_, v1), get(vpmap_, v2), get(vpmap_, v3)); - } - // data members // ------------ @@ -296,6 +463,8 @@ private: PolygonMesh, VertexPointMap> cot_calculator_; Triangle_list input_triangles_; Tree* tree_ptr_; + GeomTraits traits_; + double min_edge_len_; }; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h index f2553415ff0..3611f0df1ae 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h @@ -169,6 +169,17 @@ void curvature_flow(PolygonMesh& pmesh, const NamedParameters& np) internal::Curvature_flow curvature_remesher(pmesh, vpmap); curvature_remesher.init_remeshing(faces(pmesh)); + +#ifdef CGAL_PMP_REMESHING_VERBOSE + t.stop(); + std::cout << " done ("<< t.time() <<" sec)." << std::endl; + std::cout << "Removing degenerate edges..." << std::endl; + t.reset(); t.start(); +#endif + + curvature_remesher.collapse_short_edges(); + curvature_remesher.remove_degenerate_faces(); + #ifdef CGAL_PMP_REMESHING_VERBOSE t.stop(); std::cout << " done ("<< t.time() <<" sec)." << std::endl; From bc72d6715cb6fadfd0eb1cabd5c2f24d5f0bd31f Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Mon, 24 Jul 2017 18:15:57 +0300 Subject: [PATCH 052/102] recent pull in repair.h - minor changes --- .../include/CGAL/Polygon_mesh_processing/repair.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair.h index 1d3ccd50aed..b2ba4a50fbc 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair.h @@ -653,7 +653,7 @@ std::size_t remove_null_edges( /// @param np optional \ref namedparameters described below /// /// \cgalNamedParamsBegin -/// \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `pmesh`. The type of this map is model of `ReadWritePropertyMap`. +/// \cgalParamBegin{vertex_point_map} the property map with the points associated to the vertices of `pmesh`. The type of this map is model of `ReadWritePropertyMap`. /// If this parameter is omitted, an internal property map for /// `CGAL::vertex_point_t` should be available in `TriangleMesh` /// \cgalParamEnd @@ -1147,7 +1147,7 @@ bool remove_self_intersections(TriangleMesh& tm, const int max_steps = 7, bool v boundary_hedges.resize(boundary_hedges_initial_size); BOOST_FOREACH(face_descriptor fh, faces_to_remove) { - halfedge_descriptor h = fh->halfedge(); + halfedge_descriptor h = halfedge(fh,tm); for (int i=0;i<3; ++i) { if ( is_border( opposite(h, tm), tm) ){ @@ -1175,7 +1175,7 @@ bool remove_self_intersections(TriangleMesh& tm, const int max_steps = 7, bool v std::set border_vertices; BOOST_FOREACH(halfedge_descriptor h, boundary_hedges) { - if (!border_vertices.insert(h->vertex()).second){ + if (!border_vertices.insert(target(h,tm)).second){ BOOST_FOREACH(halfedge_descriptor hh, halfedges_around_target(h,tm)){ if (!is_border(hh, tm)) faces_to_remove.insert(face(hh, tm)); @@ -1197,7 +1197,7 @@ bool remove_self_intersections(TriangleMesh& tm, const int max_steps = 7, bool v std::set edges_to_remove; BOOST_FOREACH(face_descriptor fh, faces_to_remove) { - BOOST_FOREACH(halfedge_descriptor h, halfedges_around_face(fh->halfedge(),tm)) + BOOST_FOREACH(halfedge_descriptor h, halfedges_around_face(halfedge(fh,tm),tm)) { if (halfedge(target(h, tm), tm)==h) // limit the number of insertions vertices_to_remove.insert(target(h, tm)); From 54a8b80eac898e17dbf420a72e6790cad6f65f00 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Mon, 24 Jul 2017 22:48:35 +0300 Subject: [PATCH 053/102] more robust edge collapsing and use of repair.h for deg faces --- .../Isotropic_remeshing/curvature_flow_impl.h | 74 +++++++++++++------ 1 file changed, 50 insertions(+), 24 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h index 337ec567d8f..243c8fff5ab 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -101,7 +102,10 @@ public: std::size_t remove_degenerate_faces() { + std::size_t nb_removed_faces = 0; + + /* for(face_descriptor f : faces(mesh_)) { Triangle tr = triangle(f); @@ -112,6 +116,11 @@ public: nb_removed_faces++; } } + */ + + // repair.h + nb_removed_faces = CGAL::Polygon_mesh_processing::remove_degenerate_faces(mesh_); + return nb_removed_faces; } @@ -140,40 +149,57 @@ public: // collapse while(!edges_to_collapse.empty()) { - edge_descriptor e = *edges_to_collapse.begin(); - edges_to_collapse.erase(edges_to_collapse.begin()); - - // link condition - if(!Euler::does_satisfy_link_condition(e, mesh_)) + while(!edges_to_collapse.empty()) { - non_topologically_valid_collapses.insert(e); - CGAL_assertion(non_topologically_valid_collapses.empty()); - continue; - } + edge_descriptor e = *edges_to_collapse.begin(); + edges_to_collapse.erase(edges_to_collapse.begin()); - halfedge_descriptor he = halfedge(e, mesh_); - vertex_descriptor vs = source(he, mesh_); - vertex_descriptor vt = target(he, mesh_); - - vertex_descriptor v = Euler::collapse_edge(e, mesh_); - - - for (edge_descriptor out_e : out_edges(v, mesh_)) - { - if(edge_should_collapse(out_e)) + // link condition + if(!Euler::does_satisfy_link_condition(e, mesh_)) { - edges_to_collapse.insert(out_e); + non_topologically_valid_collapses.insert(e); + continue; } + + + // take out from short_edges prev and prev(opposite), which will be collapsed + halfedge_descriptor he = halfedge(e, mesh_); + + // + vertex_descriptor vs = source(he, mesh_); + vertex_descriptor vt = target(he, mesh_); + // + + edges_to_collapse.erase(edge(prev(he, mesh_), mesh_)); + edges_to_collapse.erase(edge(prev(opposite(he, mesh_), mesh_), mesh_)); + + // shoot out edge to be collapsed from topologically_non_valid + non_topologically_valid_collapses.erase(e); + non_topologically_valid_collapses.erase(edge(prev(he, mesh_), mesh_)); + non_topologically_valid_collapses.erase(edge(prev(opposite(he, mesh_), mesh_), mesh_)); + + + + vertex_descriptor v = Euler::collapse_edge(e, mesh_); + + + // check if an out_edge now is too short + for (edge_descriptor out_e : out_edges(v, mesh_)) + { + if(edge_should_collapse(out_e)) + edges_to_collapse.insert(out_e); + } + + + nb_collapsed_edges++; } - - nb_collapsed_edges++; - - + edges_to_collapse.swap(non_topologically_valid_collapses); } + std::cout<<"nb_collapsed_edges: "< Date: Tue, 25 Jul 2017 17:49:25 +0300 Subject: [PATCH 054/102] paste degenerate removal code in compatible remeshing class --- .../Isotropic_remeshing/smoothing_impl.h | 169 ++++++++++++++++-- 1 file changed, 151 insertions(+), 18 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h index 44b6bed37f5..c46ecca40a5 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -75,6 +76,7 @@ class Compatible_remesher typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::vertex_iterator vertex_iterator; typedef typename boost::graph_traits::face_descriptor face_descriptor; typedef typename boost::graph_traits::edge_descriptor edge_descriptor; @@ -118,9 +120,97 @@ public: check_constrained_edges(); } + std::size_t remove_degenerate_faces() + { + std::size_t nb_removed_faces = 0; + + /* + for(face_descriptor f : faces(mesh_)) + { + Triangle tr = triangle(f); + if(tr.is_degenerate()) + { + halfedge_descriptor he = halfedge(f, mesh_); + Euler::remove_face(he, mesh_); + nb_removed_faces++; + } + } + */ + + // from repair.h + nb_removed_faces = CGAL::Polygon_mesh_processing::remove_degenerate_faces(mesh_); + + std::cout<<"nb_collapsed_faces: "< edges_to_collapse, non_topologically_valid_collapses; + + // collect short edges + for(edge_descriptor e : edges(mesh_)) + { + if(edge_should_collapse(e)) + edges_to_collapse.insert(e); + } + + // collapse + while(!edges_to_collapse.empty()) + { + while(!edges_to_collapse.empty()) + { + edge_descriptor e = *edges_to_collapse.begin(); + edges_to_collapse.erase(edges_to_collapse.begin()); + + // link condition + if(!Euler::does_satisfy_link_condition(e, mesh_)) + { + non_topologically_valid_collapses.insert(e); + continue; + } + + // take out from short_edges prev and prev(opposite), which will be collapsed + halfedge_descriptor he = halfedge(e, mesh_); + + // verbose - todo + vertex_descriptor vs = source(he, mesh_); + vertex_descriptor vt = target(he, mesh_); + // + + edges_to_collapse.erase(edge(prev(he, mesh_), mesh_)); + edges_to_collapse.erase(edge(prev(opposite(he, mesh_), mesh_), mesh_)); + + // shoot out edge to be collapsed from topologically_non_valid + non_topologically_valid_collapses.erase(e); + non_topologically_valid_collapses.erase(edge(prev(he, mesh_), mesh_)); + non_topologically_valid_collapses.erase(edge(prev(opposite(he, mesh_), mesh_), mesh_)); + + vertex_descriptor v = Euler::collapse_edge(e, mesh_); + + // check if an out_edge now is too short + for (edge_descriptor out_e : out_edges(v, mesh_)) + { + if(edge_should_collapse(out_e)) + edges_to_collapse.insert(out_e); + } + + nb_collapsed_edges++; + } + + edges_to_collapse.swap(non_topologically_valid_collapses); + } + + // debug + std::cout<<"nb_collapsed_edges: "< barycenters; //boost::vector_property_map n_map; std::map n_map; @@ -138,7 +228,7 @@ std::cout<<"processing vertex: "<< v << std::endl; // compute normal to v Vector vn = compute_vertex_normal(v, mesh_, Polygon_mesh_processing::parameters::vertex_point_map(vpmap_) - .geom_traits(GeomTraits())); + .geom_traits(traits_)); n_map[v] = vn; Edges_around_map he_map; @@ -307,7 +397,7 @@ private: const vertex_descriptor& p3) const { return to_double(CGAL::approximate_sqrt( - GeomTraits().compute_squared_area_3_object()( + traits_.compute_squared_area_3_object()( get(vpmap_, p1), get(vpmap_, p2), get(vpmap_, p3)))); @@ -318,7 +408,7 @@ private: const vertex_descriptor& p3) const { return to_double(CGAL::approximate_sqrt( - GeomTraits().compute_squared_area_3_object()( + traits_.compute_squared_area_3_object()( P, get(vpmap_, p2), get(vpmap_, p3)))); @@ -326,7 +416,6 @@ private: double compute_average_area_around(const vertex_descriptor& v) { - double sum_areas = 0; unsigned int number_of_edges = 0; @@ -342,7 +431,6 @@ private: } return sum_areas / number_of_edges; - } double measure_energy(const vertex_descriptor& v, const double& S_av) @@ -358,7 +446,6 @@ private: energy += (S - S_av)*(S - S_av); number_of_edges++; - } return to_double( energy / number_of_edges ); @@ -377,7 +464,6 @@ private: energy += (S - S_av)*(S - S_av); number_of_edges++; - } return to_double( energy / (2 * number_of_edges) ); @@ -521,7 +607,6 @@ private: Vector edge2(s, equidistant_p2); Vector s_pv(s, pv); - // check degenerate cases double tolerance = 1e-3; // to think about it @@ -538,8 +623,8 @@ private: // get bisector Vector bisector = CGAL::NULL_VECTOR; - internal::normalize(edge1, GeomTraits()); - internal::normalize(edge2, GeomTraits()); + internal::normalize(edge1, traits_); + internal::normalize(edge2, traits_); bisector = edge1 + edge2; @@ -562,10 +647,8 @@ private: } bisector = Vector(b_segment); - } - correct_bisector(bisector, main_he); @@ -579,8 +662,6 @@ private: return bisector; - - } double get_angle(const He_pair& incd_edges, const Vector& vn) @@ -611,7 +692,6 @@ private: Vector aux_normal = CGAL::cross_product(input_vec, s_pv); return CGAL::cross_product(aux_normal, input_vec); - } Vector max_vector(const Vector& vec1, const Vector& vec2) @@ -624,7 +704,6 @@ private: void correct_bisector(Vector& bisector_vec, const halfedge_descriptor& main_he) { - // get common vertex around which the edge is rotated Point s = get(vpmap_, target(main_he, mesh_)); @@ -643,7 +722,6 @@ private: // take the opposite so that their sum is the overall displacement bisector_vec = -Vector(bisector); - } bool is_constrained(const edge_descriptor& e) @@ -670,6 +748,59 @@ private: } } + // degenerate fixing functions + + bool edge_should_collapse(edge_descriptor e) + { + halfedge_descriptor he = halfedge(e, mesh_); + Point s = get(vpmap_, source(he, mesh_)); + Point t = get(vpmap_, target(he, mesh_)); + + double sq_length = traits_.compute_squared_distance_3_object()(s, t); + + if(sq_length < min_edge_len_) + return true; + else + return false; + } + + struct Vertex_to_point + { + Vertex_to_point(VertexPointMap vpmap) : vpmap(vpmap){} + + typedef typename boost::property_traits::reference output_type; + + output_type operator()(vertex_descriptor vd) const + { + return get(vpmap, vd); + } + + VertexPointMap vpmap; + }; + + double init_min_edge_length() + { + vertex_iterator vi, ve; + boost::tie(vi, ve) = vertices(mesh_); + Vertex_to_point v_to_p(vpmap_); + + Bbox_3 bbox= CGAL::bbox_3( + boost::make_transform_iterator(vi, v_to_p), + boost::make_transform_iterator(ve, v_to_p)); + + return 0.01 * diagonal_length(bbox); + } + + double diagonal_length(const Bbox_3& bbox) + { + double dx = bbox.xmax() - bbox.xmin(); + double dy = bbox.ymax() - bbox.ymin(); + double dz = bbox.zmax() - bbox.zmin(); + + double diag = dx * dx + dy * dy + dz * dz; + return std::sqrt(diag); + } + private: @@ -680,6 +811,8 @@ private: Triangle_list input_triangles_; Tree* tree_ptr_; unsigned int count_non_convex_energy_; + GeomTraits traits_; + double min_edge_len_; From d5c6283b54095f324569fb7256cb6112da9fe937 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Wed, 26 Jul 2017 14:36:18 +0300 Subject: [PATCH 055/102] testing curvature flow, exploring robust degenerate handling, overloads and minor fixes --- .../smoothing_example.cpp | 6 - .../Isotropic_remeshing/curvature_flow_impl.h | 168 +++++++----------- .../Isotropic_remeshing/smoothing_impl.h | 2 + .../CGAL/Polygon_mesh_processing/smoothing.h | 17 +- .../Polygon_mesh_processing/CMakeLists.txt | 1 + .../test_compatible_remeshing.cpp | 3 +- .../test_curvature_flow.cpp | 5 +- 7 files changed, 82 insertions(+), 120 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/smoothing_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/smoothing_example.cpp index 6fc5f282ad3..1d5df41cc3e 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/smoothing_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/smoothing_example.cpp @@ -24,16 +24,10 @@ int main(int argc, char* argv[]){ return 1; } - - CGAL::Polygon_mesh_processing::compatible_remeshing( mesh, - faces(mesh), - edges(mesh), CGAL::Polygon_mesh_processing::parameters::number_of_iterations(3)); - - std::ofstream output("data/polygon3D_smoothed.off"); output << mesh; output.close(); diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h index 243c8fff5ab..68360162780 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h @@ -90,7 +90,7 @@ public: tree_ptr_->accelerate_distance_queries(); - min_edge_len_ = init_min_edge_length(); + min_sq_edge_len_ = init_min_edge_length(); //TODO: update constrained edges //check_constrained_edges(); @@ -102,7 +102,6 @@ public: std::size_t remove_degenerate_faces() { - std::size_t nb_removed_faces = 0; /* @@ -118,34 +117,27 @@ public: } */ - // repair.h + // from repair.h nb_removed_faces = CGAL::Polygon_mesh_processing::remove_degenerate_faces(mesh_); + // debug + std::cout<<"nb_collapsed_faces: "< edges_to_collapse, non_topologically_valid_collapses; - // collect short edges for(edge_descriptor e : edges(mesh_)) { if(edge_should_collapse(e)) - { edges_to_collapse.insert(e); - } } - - // collapse while(!edges_to_collapse.empty()) { @@ -161,11 +153,10 @@ public: continue; } - // take out from short_edges prev and prev(opposite), which will be collapsed halfedge_descriptor he = halfedge(e, mesh_); - // + // verbose - todo vertex_descriptor vs = source(he, mesh_); vertex_descriptor vt = target(he, mesh_); // @@ -178,11 +169,8 @@ public: non_topologically_valid_collapses.erase(edge(prev(he, mesh_), mesh_)); non_topologically_valid_collapses.erase(edge(prev(opposite(he, mesh_), mesh_), mesh_)); - - vertex_descriptor v = Euler::collapse_edge(e, mesh_); - // check if an out_edge now is too short for (edge_descriptor out_e : out_edges(v, mesh_)) { @@ -190,26 +178,18 @@ public: edges_to_collapse.insert(out_e); } - nb_collapsed_edges++; } edges_to_collapse.swap(non_topologically_valid_collapses); - } - - + // debug std::cout<<"nb_collapsed_edges: "<::reference output_type; - - output_type operator()(vertex_descriptor vd) const - { - return get(vpmap, vd); - } - - VertexPointMap vpmap; - }; - - - double init_min_edge_length() - { - vertex_iterator vi, ve; - std::pair vp; - - boost::tie(vi, ve) = vertices(mesh_); - - // to improve - Vertex_to_point v_to_p(vpmap_); - - Bbox_3 bbox= CGAL::bbox_3(boost::make_transform_iterator(vi, v_to_p), boost::make_transform_iterator(ve, v_to_p)); - - //try with .begin() - - return 0.01 * diagonal_length(bbox); - } - - double diagonal_length(const Bbox_3& bbox) - { - double dx = bbox.xmax() - bbox.xmin(); - double dy = bbox.ymax() - bbox.ymin(); - double dz = bbox.zmax() - bbox.zmin(); - - double diag = dx * dx + dy * dy + dz * dz; - return std::sqrt(diag); - } - - - // end degenerate functions - - Triangle triangle(face_descriptor f) const { halfedge_descriptor h = halfedge(f, mesh_); @@ -409,7 +316,6 @@ private: return Triangle(get(vpmap_, v1), get(vpmap_, v2), get(vpmap_, v3)); } -/* double compute_mean_curvature() { // gather points around v @@ -429,7 +335,7 @@ private: return (k1 + k2) / 2.0; } -*/ + std::pair cot_angles(const halfedge_descriptor& main_he, const He_pair& incd_edges) { vertex_descriptor v0 = source(main_he, mesh_); @@ -467,7 +373,6 @@ private: return incident_vertices; } - std::vector gather_all_points() { std::vector points; // todo: preallocate it and fill it by pointing @@ -479,6 +384,59 @@ private: return points; } + // degenerate fixing functions + + bool edge_should_collapse(edge_descriptor e) + { + halfedge_descriptor he = halfedge(e, mesh_); + Point s = get(vpmap_, source(he, mesh_)); + Point t = get(vpmap_, target(he, mesh_)); + + double sq_length = traits_.compute_squared_distance_3_object()(s, t); + + if(sq_length < min_sq_edge_len_) + return true; + else + return false; + } + + struct Vertex_to_point + { + Vertex_to_point(VertexPointMap vpmap) : vpmap(vpmap){} + + typedef typename boost::property_traits::reference output_type; + + output_type operator()(vertex_descriptor vd) const + { + return get(vpmap, vd); + } + + VertexPointMap vpmap; + }; + + double init_min_edge_length() + { + vertex_iterator vi, ve; + boost::tie(vi, ve) = vertices(mesh_); + Vertex_to_point v_to_p(vpmap_); + + Bbox_3 bbox= CGAL::bbox_3( + boost::make_transform_iterator(vi, v_to_p), + boost::make_transform_iterator(ve, v_to_p)); + + return 0.002 * diagonal_length(bbox); + } + + double diagonal_length(const Bbox_3& bbox) + { + double dx = bbox.xmax() - bbox.xmin(); + double dy = bbox.ymax() - bbox.ymin(); + double dz = bbox.zmax() - bbox.zmin(); + + double diag = dx * dx + dy * dy + dz * dz; + return std::sqrt(diag); + } + // data members // ------------ @@ -490,7 +448,7 @@ private: Triangle_list input_triangles_; Tree* tree_ptr_; GeomTraits traits_; - double min_edge_len_; + double min_sq_edge_len_; }; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h index c46ecca40a5..76cf3e7e8f0 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h @@ -118,6 +118,8 @@ public: //update constrained edges check_constrained_edges(); + + min_edge_len_ = init_min_edge_length(); } std::size_t remove_degenerate_faces() diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h index 3611f0df1ae..39075713527 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h @@ -28,7 +28,7 @@ namespace Polygon_mesh_processing { template -void compatible_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const EdgeRange& edges, const NamedParameters& np) +void compatible_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const EdgeRange& edges, const NamedParameters& np) { using boost::choose_param; using boost::get_param; @@ -96,10 +96,16 @@ void compatible_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const Edg #ifdef CGAL_PMP_REMESHING_VERBOSE t.stop(); std::cout << " done ("<< t.time() <<" sec)." << std::endl; + std::cout << "Removing degenerate edges and faces..." << std::endl; + t.reset(); t.start(); #endif + remesher.collapse_short_edges(); + remesher.remove_degenerate_faces(); #ifdef CGAL_PMP_REMESHING_VERBOSE + t.stop(); + std::cout << " done ("<< t.time() <<" sec)." << std::endl; std::cout << "#iter = " << nb_iterations << std::endl; std::cout << "Remeshing ..." << std::endl; t.reset(); t.start(); @@ -132,6 +138,11 @@ void compatible_remeshing(PolygonMesh& pmesh) compatible_remeshing(pmesh, faces(pmesh), edges(pmesh), parameters::all_default()); } +template +void compatible_remeshing(PolygonMesh& pmesh, const NamedParameters& np) +{ + compatible_remeshing(pmesh, faces(pmesh), edges(pmesh), np); +} @@ -165,11 +176,9 @@ void curvature_flow(PolygonMesh& pmesh, const NamedParameters& np) t.reset(); t.start(); #endif - internal::Curvature_flow curvature_remesher(pmesh, vpmap); curvature_remesher.init_remeshing(faces(pmesh)); - #ifdef CGAL_PMP_REMESHING_VERBOSE t.stop(); std::cout << " done ("<< t.time() <<" sec)." << std::endl; @@ -177,7 +186,7 @@ void curvature_flow(PolygonMesh& pmesh, const NamedParameters& np) t.reset(); t.start(); #endif - curvature_remesher.collapse_short_edges(); + //curvature_remesher.collapse_short_edges(); curvature_remesher.remove_degenerate_faces(); #ifdef CGAL_PMP_REMESHING_VERBOSE diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt index e997d969478..47dff129943 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt @@ -96,3 +96,4 @@ endif(EIGEN3_FOUND) create_single_source_cgal_program("test_pmp_clip.cpp") create_single_source_cgal_program("triangulate_hole_polyline_test.cpp") create_single_source_cgal_program("test_compatible_remeshing.cpp") + create_single_source_cgal_program("test_curvature_flow.cpp") diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_compatible_remeshing.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_compatible_remeshing.cpp index 78d32787567..41fad33ec99 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_compatible_remeshing.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_compatible_remeshing.cpp @@ -10,7 +10,7 @@ #define CGAL_PMP_REMESHING_VERBOSE -#define CGAL_TEST_COMP_REMESHING_OUTPUT +//#define CGAL_TEST_COMP_REMESHING_OUTPUT typedef CGAL::Exact_predicates_inexact_constructions_kernel K; @@ -35,7 +35,6 @@ int main(int argc, char* argv[]){ "data/polygon", "data/polygon3D", "data/blobby_3cc", - "data/cube_quad", "data/elephant", "data/degenerate_polygon", "data/sneaky_degenerate_polygon", diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_curvature_flow.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_curvature_flow.cpp index 45bd2268dc3..75cf52e3208 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_curvature_flow.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_curvature_flow.cpp @@ -33,10 +33,9 @@ int main(int argc, char* argv[]){ std::vector filenames = { "data/curved_polygon", - /*"data/polygon", + "data/polygon", "data/polygon3D", "data/blobby_3cc", - "data/cube_quad", "data/elephant", "data/degenerate_polygon", "data/sneaky_degenerate_polygon", @@ -50,7 +49,7 @@ int main(int argc, char* argv[]){ "data/tetra3", "data/tetra4", "data/two_tris_collinear", - "data/U"*/ + "data/U" }; From d5e42a4da5ccb9870c8bbd85fbbafdbc5b3717b2 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Wed, 26 Jul 2017 22:12:54 +0300 Subject: [PATCH 056/102] half subsampled sphere under curvature flow example --- .../curvature_flow_example.cpp | 42 +++++++++++++++++-- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/curvature_flow_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/curvature_flow_example.cpp index 5caf2c80a17..0b281e7e668 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/curvature_flow_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/curvature_flow_example.cpp @@ -5,17 +5,43 @@ #include #include +#include typedef CGAL::Exact_predicates_inexact_constructions_kernel K; typedef CGAL::Surface_mesh Mesh; +typedef typename Mesh::vertex_index vertex_index; +typedef typename Mesh::face_index face_index; +typedef typename Mesh::halfedge_index halfedge_index; + +std::set select(Mesh mesh, double x0) +{ + std::set f_selection; + + typedef typename boost::property_map::type VertexPointMap; + VertexPointMap vpmap = get(CGAL::vertex_point, mesh); + + + for(face_index f : faces(mesh)) + { + halfedge_index he = halfedge(f, mesh); + for(vertex_index v : vertices_around_face(he, mesh)) + { + if(get(vpmap, v).x() < x0) + f_selection.insert(f); + continue; + } + } + + return f_selection; +} int main(int argc, char* argv[]){ - const char* filename = "data/curved_polygon.off"; + const char* filename = "data/sphere.off"; std::ifstream input(filename); Mesh mesh; @@ -24,13 +50,23 @@ int main(int argc, char* argv[]){ return 1; } + std::cout<<"all faces: "< selected_faces = select(mesh, 0); + std::cout<<"selected faces: "< Date: Fri, 28 Jul 2017 15:48:42 +0300 Subject: [PATCH 057/102] all degenerate faces are taken out with remove_degenerate_faces - for now at least --- .../include/CGAL/Polygon_mesh_processing/smoothing.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h index 39075713527..f04f7a1d2f1 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h @@ -100,7 +100,7 @@ void compatible_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const Edge t.reset(); t.start(); #endif - remesher.collapse_short_edges(); + //remesher.collapse_short_edges(); remesher.remove_degenerate_faces(); #ifdef CGAL_PMP_REMESHING_VERBOSE From 843ab3623e4c76a03c7f06ddd2f533daef97d26c Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Sun, 30 Jul 2017 22:25:56 +0300 Subject: [PATCH 058/102] fix bug with curvature flow - sphere test is much better --- .../Isotropic_remeshing/curvature_flow_impl.h | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h index 68360162780..a17e5904f87 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h @@ -14,7 +14,6 @@ #include #include - #include #include @@ -208,22 +207,24 @@ public: // normals - /* + Vector vn = compute_vertex_normal(v, mesh_, Polygon_mesh_processing::parameters::vertex_point_map(vpmap_) .geom_traits(GeomTraits())); //traits_ - */ + + /* // normalize (kn) /* Vector kn = k_mean * vn; normalize(kn, GeomTraits()); //traits_ - - n_map[v] = kn; - */ + //n_map[v] = vn; + + + // find incident halfedges Edges_around_map he_map; @@ -244,6 +245,7 @@ public: */ + // maybe use a seperate function for this // with cot weights Vector weighted_barycenter = CGAL::NULL_VECTOR; double sum_c = 0; @@ -259,33 +261,34 @@ public: CGAL_assertion(!isinf(sum_c)); // displacement vector - Vector vec(get(vpmap_, target(hi, mesh_)) - get(vpmap_, source(hi, mesh_))); + Point Xi = get(vpmap_, source(hi, mesh_)); + Point Xj = get(vpmap_, target(hi, mesh_)); + Vector vec(Xj, Xi); // pointing to the point to be moved // add weight vec *= weight; // sum vecs weighted_barycenter += vec; - } // divide with total weight weighted_barycenter /= sum_c; + Point new_point = get(vpmap_, v) + weighted_barycenter; - Point new_location = get(vpmap_, v) + weighted_barycenter; // + kn ? - + // calculate location on the tangential plane + Point p = get(vpmap_, v);// original point + Point q = new_point; + Vector n = vn; + Point new_location = q + (n * Vector(q,p)) * n; // update location put(vpmap_, v, new_location); - } // not on border - } // all vertices - - } @@ -457,8 +460,6 @@ private: - - } // internal } // Polygon_mesh_processing } // CGAL From 86f948ca22f5ec90059dd660c98298b08450b00c Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 8 Aug 2017 16:44:35 +0200 Subject: [PATCH 059/102] fix compilation of smoothing_plugin --- .../internal/Isotropic_remeshing/smoothing_impl.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h index 76cf3e7e8f0..8019efecbf8 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h @@ -728,12 +728,12 @@ private: bool is_constrained(const edge_descriptor& e) { - get(ecmap_, e); + return get(ecmap_, e); } bool is_constrained(const vertex_descriptor& v) { - get(vcmap_, v); + return get(vcmap_, v); } void check_constrained_edges() From fca69df4cc23ab1aa376e6e25cb31120e1cfd9e2 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 8 Aug 2017 17:11:28 +0200 Subject: [PATCH 060/102] fix compilation --- .../internal/Isotropic_remeshing/smoothing_impl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h index 8019efecbf8..bcef812e711 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h @@ -682,7 +682,7 @@ private: double dot = CGAL::scalar_product(v1, v2); // transform to range [0, 2pi] - double res = atan2(-det, -dot) + M_PI; + double res = atan2(-det, -dot) + CGAL_PI; return res; } From b6833a00ce32f7a61a6d25cf1fd5e40619c2fcbf Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Tue, 8 Aug 2017 23:20:10 +0300 Subject: [PATCH 061/102] fixes on weights & degnerate cases --- .../Isotropic_remeshing/curvature_flow_impl.h | 121 ++++++++++++++---- .../Isotropic_remeshing/smoothing_impl.h | 53 +++----- .../CGAL/Polygon_mesh_processing/smoothing.h | 6 +- 3 files changed, 115 insertions(+), 65 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h index a17e5904f87..3e0cb2a937b 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h @@ -1,7 +1,7 @@ #ifndef CURVATURE_FLOW_IMPL_H #define CURVATURE_FLOW_IMPL_H -#include +//#include #include #include @@ -24,6 +24,57 @@ namespace Polygon_mesh_processing { namespace internal { +template +struct Cotangent_value_smoothing_impl +{ + + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + double tolerance = 1e-3; + double cot60 = 0.5774; + + template + double operator()(vertex_descriptor v0, vertex_descriptor v1, vertex_descriptor v2, const VertexPointMap& ppmap) + { + typedef typename Kernel_traits< + typename boost::property_traits::value_type >::Kernel::Vector_3 Vector; + + Vector a = get(ppmap, v0) - get(ppmap, v1); + Vector b = get(ppmap, v2) - get(ppmap, v1); + + double dot_ab = to_double(a*b); + Vector cross_ab = CGAL::cross_product(a, b); + + if(cross_ab.squared_length() < tolerance) + { + return cot60; + } + + return dot_ab / to_double(CGAL::approximate_sqrt(cross_ab*cross_ab)); + } +}; + +template::type> +class Cotangent_value_smoothing +{ + + PolygonMesh& mesh_; + VertexPointMap vpmap_; // no reference here, create a new one! + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + + + +public: + Cotangent_value_smoothing(PolygonMesh& pmesh, VertexPointMap vpmap) : mesh_(pmesh), vpmap_(vpmap){} + + double operator()(vertex_descriptor v0, vertex_descriptor v1, vertex_descriptor v2) + { + return Cotangent_value_smoothing_impl()(v0, v1, v2, vpmap_); + } +}; + + + template class Curvature_flow { @@ -103,19 +154,6 @@ public: { std::size_t nb_removed_faces = 0; - /* - for(face_descriptor f : faces(mesh_)) - { - Triangle tr = triangle(f); - if(tr.is_degenerate()) - { - halfedge_descriptor he = halfedge(f, mesh_); - Euler::remove_face(he, mesh_); - nb_removed_faces++; - } - } - */ - // from repair.h nb_removed_faces = CGAL::Polygon_mesh_processing::remove_degenerate_faces(mesh_); @@ -125,6 +163,7 @@ public: return nb_removed_faces; } + /* std::size_t collapse_short_edges() { std::size_t nb_collapsed_edges = 0; @@ -188,6 +227,7 @@ public: return nb_collapsed_edges; } + */ void curvature_smoothing() { @@ -253,12 +293,18 @@ public: { halfedge_descriptor hi = it->first; - //weight - std::pair a1a2 = cot_angles(hi, it->second); //check if correct - double weight = a1a2.first + a1a2.second; + // check if main_he is degenerate + double tolerance = 1e-3; + if(sqlength(hi)< tolerance) + { + continue; + // think of somehting better + } + // weight + std::pair a1a2 = cot_angles(hi, it->second); + double weight = a1a2.first + a1a2.second; sum_c += weight; - CGAL_assertion(!isinf(sum_c)); // displacement vector Point Xi = get(vpmap_, source(hi, mesh_)); @@ -319,6 +365,23 @@ private: return Triangle(get(vpmap_, v1), get(vpmap_, v2), get(vpmap_, v3)); } + double sqlength(const vertex_descriptor& v1, const vertex_descriptor& v2) const + { + return to_double(CGAL::squared_distance(get(vpmap_, v1), get(vpmap_, v2))); + } + + double sqlength(const halfedge_descriptor& h) const + { + vertex_descriptor v1 = target(h, mesh_); + vertex_descriptor v2 = source(h, mesh_); + return sqlength(v1, v2); + } + + double sqlength(const edge_descriptor& e) const + { + return sqlength(halfedge(e, mesh_)); + } + double compute_mean_curvature() { // gather points around v @@ -341,19 +404,24 @@ private: std::pair cot_angles(const halfedge_descriptor& main_he, const He_pair& incd_edges) { - vertex_descriptor v0 = source(main_he, mesh_); - vertex_descriptor vs = target(main_he, mesh_); + vertex_descriptor vs = source(main_he, mesh_); + vertex_descriptor vt = target(main_he, mesh_); vertex_descriptor v1 = target(incd_edges.first, mesh_); vertex_descriptor v2 = source(incd_edges.second, mesh_); + + Point p1 = get(vpmap_, v1); + Point p2 = get(vpmap_, v2); + CGAL_assertion(target(incd_edges.second, mesh_) == source(incd_edges.first, mesh_)); - double a1 = cot_calculator_(v0, v1, vs); - double a2 = cot_calculator_(v0, v2, vs); + // check degeneracies + halfedge_descriptor h_edge1 = incd_edges.first; + halfedge_descriptor h_edge2 = incd_edges.second; - // to check degeneracies + double a1 = cot_calculator_(vs, v1, vt); + double a2 = cot_calculator_(vs, v2, vt); return std::make_pair(a1, a2); - } std::vector points_around_vertex(vertex_descriptor v) @@ -445,9 +513,7 @@ private: // ------------ PolygonMesh& mesh_; VertexPointMap& vpmap_; - // Cotagent calculator class - CGAL::internal::Cotangent_value_Meyer< - PolygonMesh, VertexPointMap> cot_calculator_; + Cotangent_value_smoothing cot_calculator_; Triangle_list input_triangles_; Tree* tree_ptr_; GeomTraits traits_; @@ -459,7 +525,6 @@ private: - } // internal } // Polygon_mesh_processing } // CGAL diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h index bcef812e711..bf8e46012c9 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h @@ -110,7 +110,7 @@ public: { for (face_descriptor f : face_range) { - input_triangles_.push_back(triangle(f)); + input_triangles_.push_back(triangle(f)); //avoid push_back, reserve space } tree_ptr_ = new Tree(input_triangles_.begin(), input_triangles_.end()); @@ -126,19 +126,6 @@ public: { std::size_t nb_removed_faces = 0; - /* - for(face_descriptor f : faces(mesh_)) - { - Triangle tr = triangle(f); - if(tr.is_degenerate()) - { - halfedge_descriptor he = halfedge(f, mesh_); - Euler::remove_face(he, mesh_); - nb_removed_faces++; - } - } - */ - // from repair.h nb_removed_faces = CGAL::Polygon_mesh_processing::remove_degenerate_faces(mesh_); @@ -147,6 +134,7 @@ public: return nb_removed_faces; } + /* std::size_t collapse_short_edges() { std::size_t nb_collapsed_edges = 0; @@ -210,6 +198,7 @@ public: return nb_collapsed_edges; } + */ void angle_relaxation(bool use_weights) { @@ -595,7 +584,7 @@ private: { // get common vertex around which the edge is rotated - Point s = get(vpmap_, target(main_he, mesh_)); + Point vt = get(vpmap_, target(main_he, mesh_)); // pv is the vertex that is being moved Point pv = get(vpmap_, source(main_he, mesh_)); @@ -605,45 +594,43 @@ private: Point equidistant_p2 = get(vpmap_, source(incd_edges.second, mesh_)); CGAL_assertion(target(incd_edges.second, mesh_) == source(incd_edges.first, mesh_)); - Vector edge1(s, equidistant_p1); - Vector edge2(s, equidistant_p2); - Vector s_pv(s, pv); + Vector edge1(vt, equidistant_p1); + Vector edge2(vt, equidistant_p2); + Vector vt_pv(vt, pv); // check degenerate cases double tolerance = 1e-3; // to think about it - if ( edge1.squared_length() < tolerance || - edge2.squared_length() < tolerance || - sqlength(main_he) < tolerance || - (edge1 - s_pv).squared_length() < tolerance || - (edge2 - s_pv).squared_length() < tolerance ) + if ( edge1.squared_length() < tolerance || + edge2.squared_length() < tolerance || + sqlength(main_he) < tolerance || + (edge1 - vt_pv).squared_length() < tolerance || + (edge2 - vt_pv).squared_length() < tolerance ) { return CGAL::NULL_VECTOR; } - CGAL_assertion(s_pv.squared_length() > tolerance); + CGAL_assertion(vt_pv.squared_length() > tolerance); - // get bisector + // find bisector Vector bisector = CGAL::NULL_VECTOR; internal::normalize(edge1, traits_); internal::normalize(edge2, traits_); bisector = edge1 + edge2; - // under about 0.5 degrees deviation consider it flat if( bisector.squared_length() < 0.001 ) // -> length = 0.01 -> sin(theta) = 0.01 -> theta = 0.57 degrees { - // angle is (almost) 180 degrees, take the perpendicular - Vector normal_vec = find_perpendicular(edge1, s, pv); // normal to edge and found on (s-pv)'s plane + Vector normal_vec = find_perpendicular(edge1, vt, pv); // normal to edge and found on (vt-pv)'s plane CGAL_assertion(normal_vec != CGAL::NULL_VECTOR); CGAL_assertion(CGAL::scalar_product(edge1, normal_vec) < tolerance); - Segment b_segment(s, s + normal_vec); + Segment b_segment(vt, vt + normal_vec); Point b_segment_end = b_segment.target(); - if(CGAL::angle(b_segment_end, s, pv) == CGAL::OBTUSE) + if(CGAL::angle(b_segment_end, vt, pv) == CGAL::OBTUSE) { b_segment = b_segment.opposite(); } @@ -707,10 +694,10 @@ private: void correct_bisector(Vector& bisector_vec, const halfedge_descriptor& main_he) { // get common vertex around which the edge is rotated - Point s = get(vpmap_, target(main_he, mesh_)); + Point pt = get(vpmap_, target(main_he, mesh_)); // create a segment to be able to translate - Segment bisector(s, s + bisector_vec); + Segment bisector(pt, pt + bisector_vec); // scale double scale_factor = CGAL::sqrt( sqlength(main_he) / bisector.squared_length() ); @@ -718,7 +705,7 @@ private: bisector = bisector.transform(t_scale); // translate - Vector vec(bisector.source(), s); + Vector vec(bisector.source(), pt); typename GeomTraits::Aff_transformation_3 t_translate(CGAL::TRANSLATION, vec); bisector = bisector.transform(t_translate); diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h index f04f7a1d2f1..63ec0df9d89 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h @@ -26,7 +26,6 @@ namespace Polygon_mesh_processing { - template void compatible_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const EdgeRange& edges, const NamedParameters& np) { @@ -100,7 +99,6 @@ void compatible_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const Edge t.reset(); t.start(); #endif - //remesher.collapse_short_edges(); remesher.remove_degenerate_faces(); #ifdef CGAL_PMP_REMESHING_VERBOSE @@ -186,7 +184,6 @@ void curvature_flow(PolygonMesh& pmesh, const NamedParameters& np) t.reset(); t.start(); #endif - //curvature_remesher.collapse_short_edges(); curvature_remesher.remove_degenerate_faces(); #ifdef CGAL_PMP_REMESHING_VERBOSE @@ -197,7 +194,7 @@ void curvature_flow(PolygonMesh& pmesh, const NamedParameters& np) #endif curvature_remesher.curvature_smoothing(); - curvature_remesher.project_to_surface(); + //curvature_remesher.project_to_surface(); #ifdef CGAL_PMP_REMESHING_VERBOSE @@ -219,6 +216,7 @@ void curvature_flow(PolygonMesh& pmesh) + } // namespace Polygon_mesh_processing } // namespace CGAL From 27ebd0d8ea48b25a7369c7710f109880e3606075 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Wed, 9 Aug 2017 19:25:49 +0300 Subject: [PATCH 062/102] secure cot calculation & avoid division with zero weight --- .../Isotropic_remeshing/curvature_flow_impl.h | 169 ++++++++---------- .../CGAL/Polygon_mesh_processing/smoothing.h | 2 +- 2 files changed, 74 insertions(+), 97 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h index 3e0cb2a937b..5517a454299 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h @@ -1,7 +1,7 @@ #ifndef CURVATURE_FLOW_IMPL_H #define CURVATURE_FLOW_IMPL_H -//#include +#include #include #include @@ -24,56 +24,6 @@ namespace Polygon_mesh_processing { namespace internal { -template -struct Cotangent_value_smoothing_impl -{ - - typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - double tolerance = 1e-3; - double cot60 = 0.5774; - - template - double operator()(vertex_descriptor v0, vertex_descriptor v1, vertex_descriptor v2, const VertexPointMap& ppmap) - { - typedef typename Kernel_traits< - typename boost::property_traits::value_type >::Kernel::Vector_3 Vector; - - Vector a = get(ppmap, v0) - get(ppmap, v1); - Vector b = get(ppmap, v2) - get(ppmap, v1); - - double dot_ab = to_double(a*b); - Vector cross_ab = CGAL::cross_product(a, b); - - if(cross_ab.squared_length() < tolerance) - { - return cot60; - } - - return dot_ab / to_double(CGAL::approximate_sqrt(cross_ab*cross_ab)); - } -}; - -template::type> -class Cotangent_value_smoothing -{ - - PolygonMesh& mesh_; - VertexPointMap vpmap_; // no reference here, create a new one! - typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - - - -public: - Cotangent_value_smoothing(PolygonMesh& pmesh, VertexPointMap vpmap) : mesh_(pmesh), vpmap_(vpmap){} - - double operator()(vertex_descriptor v0, vertex_descriptor v1, vertex_descriptor v2) - { - return Cotangent_value_smoothing_impl()(v0, v1, v2, vpmap_); - } -}; - - template class Curvature_flow @@ -140,7 +90,7 @@ public: tree_ptr_->accelerate_distance_queries(); - min_sq_edge_len_ = init_min_edge_length(); + //min_sq_edge_len_ = init_min_edge_length(); //TODO: update constrained edges //check_constrained_edges(); @@ -261,9 +211,7 @@ public: normalize(kn, GeomTraits()); //traits_ */ - //n_map[v] = vn; - - + n_map[v] = vn; // find incident halfedges @@ -273,26 +221,15 @@ public: he_map[hi] = He_pair( next(hi, mesh_), prev(opposite(hi, mesh_), mesh_) ); - /* - // use barycenter - without cot weights - Vector displacement = CGAL::NULL_VECTOR; - for(halfedge_descriptor hi : halfedges_around_source(v, mesh_)) - { - displacement += Vector(get(vpmap_, target(hi, mesh_)) - get(vpmap_, source(hi, mesh_))); - } - barycenters[v] = get(vpmap_, v) + (displacement / halfedges_around_source(v, mesh_).size()) ; - Point new_location = barycenters[v] + n_map[v]; // point + vector - */ - - // maybe use a seperate function for this // with cot weights - Vector weighted_barycenter = CGAL::NULL_VECTOR; - double sum_c = 0; + Vector weighted_move = CGAL::NULL_VECTOR; + double sum_cot_weights = 0; for(it = he_map.begin(); it!= he_map.end(); ++it) { - halfedge_descriptor hi = it->first; + halfedge_descriptor hi = it->first; //main_he + /* // check if main_he is degenerate double tolerance = 1e-3; if(sqlength(hi)< tolerance) @@ -300,11 +237,14 @@ public: continue; // think of somehting better } + */ // weight - std::pair a1a2 = cot_angles(hi, it->second); + std::pair a1a2 = cot_angles(hi, it->second); // incd_edges double weight = a1a2.first + a1a2.second; - sum_c += weight; + sum_cot_weights += weight; + + // if I return 0 weight, then vec becomes 0. // displacement vector Point Xi = get(vpmap_, source(hi, mesh_)); @@ -313,28 +253,50 @@ public: // add weight vec *= weight; // sum vecs - weighted_barycenter += vec; + weighted_move += vec; } - // divide with total weight - weighted_barycenter /= sum_c; + // divide with total weight - be careful of a bloody division with zero. + if(sum_cot_weights != 0) // risky business + { + weighted_move /= sum_cot_weights; + } - Point new_point = get(vpmap_, v) + weighted_barycenter; - // calculate location on the tangential plane - Point p = get(vpmap_, v);// original point - Point q = new_point; - Vector n = vn; - Point new_location = q + (n * Vector(q,p)) * n; - - // update location - put(vpmap_, v, new_location); + Point weighted_barycenter = get(vpmap_, v) + weighted_move; + barycenters[v] = weighted_barycenter; } // not on border } // all vertices + // compute locations on tangent plane + typedef typename std::map::value_type VP; + std::map new_locations; + for(const VP& vp: barycenters) + { + Point p = get(vpmap_, vp.first); + Point q = vp.second; + Vector n = n_map[vp.first]; + + new_locations[vp.first] = q + ( n * Vector(q, p) ) * n ; + } + + // update location + for(const VP& vp : new_locations) + { + +#ifdef CGAL_PMP_COMPATIBLE_REMESHING_DEBUG +std::cout << "from: "<< get(vpmap_, vp.first); +#endif + put(vpmap_, vp.first, vp.second); + +#ifdef CGAL_PMP_COMPATIBLE_REMESHING_DEBUG +std::cout<<" moved at: "<< vp.second << std::endl; +#endif + } + } @@ -381,7 +343,7 @@ private: { return sqlength(halfedge(e, mesh_)); } - +/* double compute_mean_curvature() { // gather points around v @@ -401,7 +363,7 @@ private: return (k1 + k2) / 2.0; } - +*/ std::pair cot_angles(const halfedge_descriptor& main_he, const He_pair& incd_edges) { vertex_descriptor vs = source(main_he, mesh_); @@ -409,21 +371,35 @@ private: vertex_descriptor v1 = target(incd_edges.first, mesh_); vertex_descriptor v2 = source(incd_edges.second, mesh_); - Point p1 = get(vpmap_, v1); - Point p2 = get(vpmap_, v2); - CGAL_assertion(target(incd_edges.second, mesh_) == source(incd_edges.first, mesh_)); - // check degeneracies - halfedge_descriptor h_edge1 = incd_edges.first; - halfedge_descriptor h_edge2 = incd_edges.second; + Point p1 = get(vpmap_, v1); + Point p2 = get(vpmap_, v2); + Point pt = get(vpmap_, vt); + Point ps = get(vpmap_, vs); + Vector edge1(pt, p1); + Vector edge2(pt, p2); + Vector vec_main_he(pt, ps); + + double tolerance = 1e-3; + if ( edge1.squared_length() < tolerance || + edge2.squared_length() < tolerance || + sqlength(main_he) < tolerance || + (edge1 - vec_main_he).squared_length() < tolerance || + (edge2 - vec_main_he).squared_length() < tolerance ) + { + return std::make_pair(0, 0); + // zero means 90 degrees angle (and means also no weight) + } + + CGAL_assertion(vec_main_he.squared_length() > tolerance); double a1 = cot_calculator_(vs, v1, vt); double a2 = cot_calculator_(vs, v2, vt); return std::make_pair(a1, a2); } - +/* std::vector points_around_vertex(vertex_descriptor v) { std::vector incident_vertices; @@ -454,9 +430,9 @@ private: return points; } - +*/ // degenerate fixing functions - + /* bool edge_should_collapse(edge_descriptor e) { halfedge_descriptor he = halfedge(e, mesh_); @@ -508,12 +484,13 @@ private: return std::sqrt(diag); } + */ // data members // ------------ PolygonMesh& mesh_; VertexPointMap& vpmap_; - Cotangent_value_smoothing cot_calculator_; + CGAL::internal::Cotangent_value_Meyer_secure cot_calculator_; Triangle_list input_triangles_; Tree* tree_ptr_; GeomTraits traits_; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h index 63ec0df9d89..db8578aeee9 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h @@ -194,7 +194,7 @@ void curvature_flow(PolygonMesh& pmesh, const NamedParameters& np) #endif curvature_remesher.curvature_smoothing(); - //curvature_remesher.project_to_surface(); + curvature_remesher.project_to_surface(); #ifdef CGAL_PMP_REMESHING_VERBOSE From f8ffda08c2d3cf93acf648b756fe2038bce0f5d0 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Wed, 9 Aug 2017 23:29:09 +0300 Subject: [PATCH 063/102] use opposite direction for move vector & remove monge jet fitting code --- .../Isotropic_remeshing/curvature_flow_impl.h | 280 ++---------------- 1 file changed, 21 insertions(+), 259 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h index 5517a454299..db44d9434ca 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h @@ -5,7 +5,6 @@ #include #include -#include #include #include #include @@ -17,6 +16,7 @@ #include #include + namespace CGAL { namespace Polygon_mesh_processing { @@ -35,48 +35,25 @@ class Curvature_flow typedef typename boost::graph_traits::edge_descriptor edge_descriptor; typedef typename boost::graph_traits::vertex_iterator vertex_iterator; - - - typedef typename CGAL::Monge_via_jet_fitting Monge_via_jet_fitting; - typedef typename Monge_via_jet_fitting::Monge_form Monge_form; - typedef typename GeomTraits::Point_3 Point; typedef typename GeomTraits::Vector_3 Vector; typedef typename GeomTraits::FT FT; typedef typename GeomTraits::Triangle_3 Triangle; typedef std::vector Triangle_list; - // typedef std::pair He_pair; typedef std::map Edges_around_map; - typedef CGAL::AABB_triangle_primitive AABB_Primitive; typedef CGAL::AABB_traits AABB_Traits; typedef CGAL::AABB_tree Tree; - public: - - Curvature_flow(PolygonMesh& pmesh, VertexPointMap& vpmap) : mesh_(pmesh), vpmap_(vpmap), cot_calculator_(pmesh, vpmap) - { - - //std::vector points - /* std::size_t num_points = vertices(mesh_).size(); - std::size_t min_num_of_points = 6; // (d+1)(d+2)/2, for d=2 - if(num_points < min_num_of_points) - { - CGAL_error_msg("Not enough points in the mesh."); - } - - */ - - } - + Curvature_flow(PolygonMesh& pmesh, VertexPointMap& vpmap) : mesh_(pmesh), vpmap_(vpmap), cot_calculator_(pmesh, vpmap){} template void init_remeshing(const FaceRange& face_range) @@ -89,17 +66,11 @@ public: tree_ptr_ = new Tree(input_triangles_.begin(), input_triangles_.end()); tree_ptr_->accelerate_distance_queries(); - - //min_sq_edge_len_ = init_min_edge_length(); - //TODO: update constrained edges //check_constrained_edges(); } - - // fixing degenerates - std::size_t remove_degenerate_faces() { std::size_t nb_removed_faces = 0; @@ -107,120 +78,34 @@ public: // from repair.h nb_removed_faces = CGAL::Polygon_mesh_processing::remove_degenerate_faces(mesh_); - // debug +#ifdef CGAL_PMP_COMPATIBLE_REMESHING_DEBUG std::cout<<"nb_collapsed_faces: "< edges_to_collapse, non_topologically_valid_collapses; - - // collect short edges - for(edge_descriptor e : edges(mesh_)) - { - if(edge_should_collapse(e)) - edges_to_collapse.insert(e); - } - - // collapse - while(!edges_to_collapse.empty()) - { - while(!edges_to_collapse.empty()) - { - edge_descriptor e = *edges_to_collapse.begin(); - edges_to_collapse.erase(edges_to_collapse.begin()); - - // link condition - if(!Euler::does_satisfy_link_condition(e, mesh_)) - { - non_topologically_valid_collapses.insert(e); - continue; - } - - // take out from short_edges prev and prev(opposite), which will be collapsed - halfedge_descriptor he = halfedge(e, mesh_); - - // verbose - todo - vertex_descriptor vs = source(he, mesh_); - vertex_descriptor vt = target(he, mesh_); - // - - edges_to_collapse.erase(edge(prev(he, mesh_), mesh_)); - edges_to_collapse.erase(edge(prev(opposite(he, mesh_), mesh_), mesh_)); - - // shoot out edge to be collapsed from topologically_non_valid - non_topologically_valid_collapses.erase(e); - non_topologically_valid_collapses.erase(edge(prev(he, mesh_), mesh_)); - non_topologically_valid_collapses.erase(edge(prev(opposite(he, mesh_), mesh_), mesh_)); - - vertex_descriptor v = Euler::collapse_edge(e, mesh_); - - // check if an out_edge now is too short - for (edge_descriptor out_e : out_edges(v, mesh_)) - { - if(edge_should_collapse(out_e)) - edges_to_collapse.insert(out_e); - } - - nb_collapsed_edges++; - } - - edges_to_collapse.swap(non_topologically_valid_collapses); - } - - // debug - std::cout<<"nb_collapsed_edges: "< barycenters; std::map n_map; for(vertex_descriptor v : vertices(mesh_)) { - if(!is_border(v, mesh_)) // add && !is_constrained { - - - // mean curvature - //double k_mean = compute_mean_curvature(); - - // normals - Vector vn = compute_vertex_normal(v, mesh_, Polygon_mesh_processing::parameters::vertex_point_map(vpmap_) - .geom_traits(GeomTraits())); //traits_ - - - - /* - // normalize (kn) - /* - Vector kn = k_mean * vn; - normalize(kn, GeomTraits()); //traits_ - */ - + .geom_traits(traits_)); n_map[v] = vn; - // find incident halfedges Edges_around_map he_map; typename Edges_around_map::iterator it; for(halfedge_descriptor hi : halfedges_around_source(v, mesh_)) he_map[hi] = He_pair( next(hi, mesh_), prev(opposite(hi, mesh_), mesh_) ); - // maybe use a seperate function for this // with cot weights Vector weighted_move = CGAL::NULL_VECTOR; @@ -229,39 +114,24 @@ public: { halfedge_descriptor hi = it->first; //main_he - /* - // check if main_he is degenerate - double tolerance = 1e-3; - if(sqlength(hi)< tolerance) - { - continue; - // think of somehting better - } - */ - // weight - std::pair a1a2 = cot_angles(hi, it->second); // incd_edges - double weight = a1a2.first + a1a2.second; + double weight = cot_angles(hi, it->second); // incd_edges sum_cot_weights += weight; - // if I return 0 weight, then vec becomes 0. - // displacement vector Point Xi = get(vpmap_, source(hi, mesh_)); Point Xj = get(vpmap_, target(hi, mesh_)); - Vector vec(Xj, Xi); // pointing to the point to be moved - // add weight + Vector vec(Xi, Xj); + + // add weight. If weight is 0, then vec becomes 0. vec *= weight; // sum vecs weighted_move += vec; } - // divide with total weight - be careful of a bloody division with zero. - if(sum_cot_weights != 0) // risky business - { + // divide with total weight - if there is actually weight + if(sum_cot_weights != 0) weighted_move /= sum_cot_weights; - } - Point weighted_barycenter = get(vpmap_, v) + weighted_move; barycenters[v] = weighted_barycenter; @@ -281,6 +151,7 @@ public: Vector n = n_map[vp.first]; new_locations[vp.first] = q + ( n * Vector(q, p) ) * n ; + //new_locations[vp.first] = q; } // update location @@ -288,18 +159,17 @@ public: { #ifdef CGAL_PMP_COMPATIBLE_REMESHING_DEBUG -std::cout << "from: "<< get(vpmap_, vp.first); + std::cout << "from: "<< get(vpmap_, vp.first); #endif put(vpmap_, vp.first, vp.second); #ifdef CGAL_PMP_COMPATIBLE_REMESHING_DEBUG -std::cout<<" moved at: "<< vp.second << std::endl; + std::cout<<" moved at: "<< vp.second << std::endl; #endif } } - void project_to_surface() { for( vertex_descriptor v : vertices(mesh_)) @@ -314,9 +184,6 @@ std::cout<<" moved at: "<< vp.second << std::endl; } - - - private: Triangle triangle(face_descriptor f) const { @@ -343,28 +210,8 @@ private: { return sqlength(halfedge(e, mesh_)); } -/* - double compute_mean_curvature() - { - // gather points around v - std::vector incident_points = gather_all_points(); - Monge_form monge_form; - Monge_via_jet_fitting monge_fit; - - std::size_t d_fit = 2; // d_fit >= d_monge - std::size_t d_monge = 2; // need 2 principal coeeficients - std::size_t Nd = (d_fit + 1)*(d_fit + 1) / 2.0; - CGAL_assertion(incident_points.size() >= Nd); - - monge_form = monge_fit(incident_points.begin(), incident_points.end(), d_fit, d_monge); - const FT k1 = monge_form.principal_curvatures(0); - const FT k2 = monge_form.principal_curvatures(1); - - return (k1 + k2) / 2.0; - } -*/ - std::pair cot_angles(const halfedge_descriptor& main_he, const He_pair& incd_edges) + double cot_angles(const halfedge_descriptor& main_he, const He_pair& incd_edges) { vertex_descriptor vs = source(main_he, mesh_); vertex_descriptor vt = target(main_he, mesh_); @@ -388,8 +235,8 @@ private: (edge1 - vec_main_he).squared_length() < tolerance || (edge2 - vec_main_he).squared_length() < tolerance ) { - return std::make_pair(0, 0); - // zero means 90 degrees angle (and means also no weight) + return 0; + // zero means 90 degrees angle (also means no weight) } CGAL_assertion(vec_main_he.squared_length() > tolerance); @@ -397,100 +244,15 @@ private: double a1 = cot_calculator_(vs, v1, vt); double a2 = cot_calculator_(vs, v2, vt); - return std::make_pair(a1, a2); + return a1 + a2; } -/* - std::vector points_around_vertex(vertex_descriptor v) - { - std::vector incident_vertices; - for(halfedge_descriptor h : halfedges_around_target(v, mesh_)) - { - vertex_descriptor vs = source(h, mesh_); - incident_vertices.push_back(get(vpmap_, vs)); - } - - // temp assertion - std::vector incident_vertices2; - for(vertex_descriptor vi : vertices_around_target(v, mesh_)) - { - incident_vertices2.push_back(get(vpmap_, vi)); - } - CGAL_assertion(incident_vertices.size() == incident_vertices2.size()); - - return incident_vertices; - } - - std::vector gather_all_points() - { - std::vector points; // todo: preallocate it and fill it by pointing - for(vertex_descriptor v : vertices(mesh_)) - { - points.push_back(get(vpmap_, v)); - } - - return points; - } -*/ - // degenerate fixing functions - /* - bool edge_should_collapse(edge_descriptor e) - { - halfedge_descriptor he = halfedge(e, mesh_); - Point s = get(vpmap_, source(he, mesh_)); - Point t = get(vpmap_, target(he, mesh_)); - - double sq_length = traits_.compute_squared_distance_3_object()(s, t); - - if(sq_length < min_sq_edge_len_) - return true; - else - return false; - } - - struct Vertex_to_point - { - Vertex_to_point(VertexPointMap vpmap) : vpmap(vpmap){} - - typedef typename boost::property_traits::reference output_type; - - output_type operator()(vertex_descriptor vd) const - { - return get(vpmap, vd); - } - - VertexPointMap vpmap; - }; - - double init_min_edge_length() - { - vertex_iterator vi, ve; - boost::tie(vi, ve) = vertices(mesh_); - Vertex_to_point v_to_p(vpmap_); - - Bbox_3 bbox= CGAL::bbox_3( - boost::make_transform_iterator(vi, v_to_p), - boost::make_transform_iterator(ve, v_to_p)); - - return 0.002 * diagonal_length(bbox); - } - - double diagonal_length(const Bbox_3& bbox) - { - double dx = bbox.xmax() - bbox.xmin(); - double dy = bbox.ymax() - bbox.ymin(); - double dz = bbox.zmax() - bbox.zmin(); - - double diag = dx * dx + dy * dy + dz * dz; - return std::sqrt(diag); - } - - */ // data members - // ------------ PolygonMesh& mesh_; VertexPointMap& vpmap_; - CGAL::internal::Cotangent_value_Meyer_secure cot_calculator_; + //CGAL::internal::Cotangent_value_Meyer_secure cot_calculator_; + CGAL::internal::Cotangent_value_clamped_2 cot_calculator_; + //CGAL::internal::Cotangent_value_clamped cot_calculator_; Triangle_list input_triangles_; Tree* tree_ptr_; GeomTraits traits_; From 1b223ab1aa201ce151595adfca6f2b3f09cdc3a7 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Thu, 10 Aug 2017 01:34:32 +0300 Subject: [PATCH 064/102] improve demo plugin by separating functionalities --- .../CGAL/Polygon_mesh_processing/smoothing.h | 299 +++++++++++++++--- .../Plugins/PMP/Smoothing_plugin.cpp | 52 +-- .../Plugins/PMP/Smoothing_plugin.ui | 57 +++- 3 files changed, 330 insertions(+), 78 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h index db8578aeee9..7b3bcd465da 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h @@ -1,8 +1,6 @@ #ifndef CGAL_POLYGON_MESH_PROCESSING_SMOOTHING_H #define CGAL_POLYGON_MESH_PROCESSING_SMOOTHING_H -#define CGAL_PMP_REMESHING_VERBOSE - #include #include @@ -33,10 +31,10 @@ void compatible_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const Edge using boost::get_param; #ifdef CGAL_PMP_REMESHING_VERBOSE - CGAL::Timer t; - std::cout << "Remeshing parameters..."; - std::cout.flush(); - t.start(); + CGAL::Timer t; + std::cout << "Remeshing parameters..."; + std::cout.flush(); + t.start(); #endif //geom traits @@ -81,11 +79,11 @@ void compatible_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const Edge #ifdef CGAL_PMP_REMESHING_VERBOSE - t.stop(); - std::cout << "\rRemeshing parameters done ("<< t.time() <<" sec)" << std::endl; - std::cout << "Remesher construction..."; - std::cout.flush(); - t.reset(); t.start(); + t.stop(); + std::cout << "\rRemeshing parameters done ("<< t.time() <<" sec)" << std::endl; + std::cout << "Remesher construction..."; + std::cout.flush(); + t.reset(); t.start(); #endif CGAL::Polygon_mesh_processing::internal::Compatible_remesher @@ -93,20 +91,20 @@ void compatible_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const Edge remesher.init_remeshing(faces); #ifdef CGAL_PMP_REMESHING_VERBOSE - t.stop(); - std::cout << " done ("<< t.time() <<" sec)." << std::endl; - std::cout << "Removing degenerate edges and faces..." << std::endl; - t.reset(); t.start(); + t.stop(); + std::cout << " done ("<< t.time() <<" sec)." << std::endl; + std::cout << "Removing degenerate edges and faces..." << std::endl; + t.reset(); t.start(); #endif remesher.remove_degenerate_faces(); #ifdef CGAL_PMP_REMESHING_VERBOSE - t.stop(); - std::cout << " done ("<< t.time() <<" sec)." << std::endl; - std::cout << "#iter = " << nb_iterations << std::endl; - std::cout << "Remeshing ..." << std::endl; - t.reset(); t.start(); + t.stop(); + std::cout << " done ("<< t.time() <<" sec)." << std::endl; + std::cout << "#iter = " << nb_iterations << std::endl; + std::cout << "Remeshing ..." << std::endl; + t.reset(); t.start(); #endif for(unsigned int i=0; i +void angle_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const EdgeRange& edges, const NamedParameters& np) +{ + using boost::choose_param; + using boost::get_param; + +#ifdef CGAL_PMP_REMESHING_VERBOSE + CGAL::Timer t; + std::cout << "Remeshing parameters..."; + std::cout.flush(); + t.start(); +#endif + + //geom traits + typedef typename GetGeomTraits::type GeomTraits; + + //vpmap + typedef typename GetVertexPointMap::type VertexPointMap; + VertexPointMap vpmap = choose_param(get_param(np, internal_np::vertex_point), + get_property_map(CGAL::vertex_point, pmesh)); + + //vcmap + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::lookup_named_param_def < + internal_np::vertex_is_constrained_t, + NamedParameters, + internal::No_constraint_pmap//default + > ::type VCMap; + VCMap vcmap = choose_param(get_param(np, internal_np::vertex_is_constrained), + internal::No_constraint_pmap()); + + //ecmap + typedef typename boost::lookup_named_param_def < + internal_np::edge_is_constrained_t, + NamedParameters, + internal::Edge_constraint_map + > ::type ECMap; + // either fill map with given constrined edges or use default constructor for an NULL map + ECMap ecmap = (boost::is_same >::value) + ? choose_param(get_param(np, internal_np::edge_is_constrained), + internal::Edge_constraint_map(edges)) + : choose_param(get_param(np, internal_np::edge_is_constrained), + internal::Edge_constraint_map()); + + //nb_iterations + unsigned int nb_iterations = choose_param(get_param(np, internal_np::number_of_iterations), 1); + + //use weighted angles + bool use_weights = choose_param(get_param(np, internal_np::use_weights), false); + + + CGAL::Polygon_mesh_processing::internal::Compatible_remesher + remesher(pmesh, vpmap, vcmap, ecmap); + remesher.init_remeshing(faces); + +#ifdef CGAL_PMP_REMESHING_VERBOSE + t.stop(); + std::cout << " done ("<< t.time() <<" sec)." << std::endl; + std::cout << "Removing degenerate faces..." << std::endl; + t.reset(); t.start(); +#endif + + remesher.remove_degenerate_faces(); + +#ifdef CGAL_PMP_REMESHING_VERBOSE + t.stop(); + std::cout << " done ("<< t.time() <<" sec)." << std::endl; + std::cout << "#iter = " << nb_iterations << std::endl; + std::cout << "Remeshing ..." << std::endl; + t.reset(); t.start(); +#endif + + for(unsigned int i=0; i +void angle_remeshing(PolygonMesh& pmesh, const NamedParameters& np) +{ + angle_remeshing(pmesh, faces(pmesh), edges(pmesh), np); +} + +template +void angle_remeshing(PolygonMesh& pmesh) +{ + angle_remeshing(pmesh, faces(pmesh), edges(pmesh), parameters::all_default()); +} + + +template +void area_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const EdgeRange& edges, const NamedParameters& np) +{ + using boost::choose_param; + using boost::get_param; + +#ifdef CGAL_PMP_REMESHING_VERBOSE + CGAL::Timer t; + std::cout << "Remeshing parameters..."; + std::cout.flush(); + t.start(); +#endif + + //geom traits + typedef typename GetGeomTraits::type GeomTraits; + + //vpmap + typedef typename GetVertexPointMap::type VertexPointMap; + VertexPointMap vpmap = choose_param(get_param(np, internal_np::vertex_point), + get_property_map(CGAL::vertex_point, pmesh)); + + //vcmap + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::lookup_named_param_def < + internal_np::vertex_is_constrained_t, + NamedParameters, + internal::No_constraint_pmap//default + > ::type VCMap; + VCMap vcmap = choose_param(get_param(np, internal_np::vertex_is_constrained), + internal::No_constraint_pmap()); + + //ecmap + typedef typename boost::lookup_named_param_def < + internal_np::edge_is_constrained_t, + NamedParameters, + internal::Edge_constraint_map + > ::type ECMap; + // either fill map with given constrined edges or use default constructor for an NULL map + ECMap ecmap = (boost::is_same >::value) + ? choose_param(get_param(np, internal_np::edge_is_constrained), + internal::Edge_constraint_map(edges)) // to fix this + : choose_param(get_param(np, internal_np::edge_is_constrained), + internal::Edge_constraint_map()); + + //nb_iterations + unsigned int nb_iterations = choose_param(get_param(np, internal_np::number_of_iterations), 1); + + //gradient descent precision + double gd_precision = choose_param(get_param(np, internal_np::gradient_descent_precision), 0.001); + + + CGAL::Polygon_mesh_processing::internal::Compatible_remesher + remesher(pmesh, vpmap, vcmap, ecmap); + remesher.init_remeshing(faces); + +#ifdef CGAL_PMP_REMESHING_VERBOSE + t.stop(); + std::cout << " done ("<< t.time() <<" sec)." << std::endl; + std::cout << "Removing degenerate faces..." << std::endl; + t.reset(); t.start(); +#endif + + remesher.remove_degenerate_faces(); + +#ifdef CGAL_PMP_REMESHING_VERBOSE + t.stop(); + std::cout << " done ("<< t.time() <<" sec)." << std::endl; + std::cout << "#iter = " << nb_iterations << std::endl; + std::cout << "Remeshing ..." << std::endl; + t.reset(); t.start(); +#endif + + for(unsigned int i=0; i +void area_remeshing(PolygonMesh& pmesh, const NamedParameters& np) +{ + area_remeshing(pmesh, faces(pmesh), edges(pmesh), np); +} + +template +void area_remeshing(PolygonMesh& pmesh) +{ + area_remeshing(pmesh, faces(pmesh), edges(pmesh), parameters::all_default()); +} + +template // to fix: use constraits void curvature_flow(PolygonMesh& pmesh, const NamedParameters& np) { using boost::choose_param; using boost::get_param; #ifdef CGAL_PMP_REMESHING_VERBOSE - CGAL::Timer t; - std::cout << "Remeshing parameters..."; - std::cout.flush(); - t.start(); + CGAL::Timer t; + std::cout << "Remeshing parameters..."; + std::cout.flush(); + t.start(); #endif //vpmap @@ -167,41 +373,42 @@ void curvature_flow(PolygonMesh& pmesh, const NamedParameters& np) #ifdef CGAL_PMP_REMESHING_VERBOSE - t.stop(); - std::cout << "\rRemeshing parameters done ("<< t.time() <<" sec)" << std::endl; - std::cout << "Remesher construction..."; - std::cout.flush(); - t.reset(); t.start(); + t.stop(); + std::cout << "\rRemeshing parameters done ("<< t.time() <<" sec)" << std::endl; + std::cout << "Remesher construction..."; + std::cout.flush(); + t.reset(); t.start(); #endif internal::Curvature_flow curvature_remesher(pmesh, vpmap); curvature_remesher.init_remeshing(faces(pmesh)); #ifdef CGAL_PMP_REMESHING_VERBOSE - t.stop(); - std::cout << " done ("<< t.time() <<" sec)." << std::endl; - std::cout << "Removing degenerate edges..." << std::endl; - t.reset(); t.start(); + t.stop(); + std::cout << " done ("<< t.time() <<" sec)." << std::endl; + std::cout << "Removing degenerate edges..." << std::endl; + t.reset(); t.start(); #endif curvature_remesher.remove_degenerate_faces(); #ifdef CGAL_PMP_REMESHING_VERBOSE - t.stop(); - std::cout << " done ("<< t.time() <<" sec)." << std::endl; - std::cout << "Remeshing ..." << std::endl; - t.reset(); t.start(); + t.stop(); + std::cout << " done ("<< t.time() <<" sec)." << std::endl; + std::cout << "Remeshing ..." << std::endl; + t.reset(); t.start(); #endif curvature_remesher.curvature_smoothing(); - curvature_remesher.project_to_surface(); + //for now + //curvature_remesher.project_to_surface(); #ifdef CGAL_PMP_REMESHING_VERBOSE - t.stop(); - std::cout << "Remeshing done in "; - std::cout << t.time() << " sec." << std::endl; - std::cout<raise(); } - void on_Compatible_button_clicked() + void on_Apply_clicked() { const Scene_interface::Item_id index = scene->mainSelectionIndex(); Scene_polyhedron_item* poly_item = qobject_cast(scene->item(index)); - Polyhedron& pmesh = *poly_item->polyhedron(); - CGAL::Polygon_mesh_processing::compatible_remeshing(pmesh); - poly_item->invalidateOpenGLBuffers(); - Q_EMIT poly_item->itemChanged(); + if(ui_widget.Angle_checkBox->isChecked()) + { + unsigned int nb_iterations = ui_widget.Angle_spinBox->value(); + CGAL::Polygon_mesh_processing::angle_remeshing(pmesh); + poly_item->invalidateOpenGLBuffers(); + Q_EMIT poly_item->itemChanged(); + } + + if(ui_widget.Area_checkBox->isChecked()) + { + unsigned int nb_iterations = ui_widget.Area_spinBox->value(); + CGAL::Polygon_mesh_processing::area_remeshing(pmesh); + poly_item->invalidateOpenGLBuffers(); + Q_EMIT poly_item->itemChanged(); + } + + if(ui_widget.Curvature_checkBox->isChecked()) + { + unsigned int nb_iterations = ui_widget.Curvature_spinBox->value(); + CGAL::Polygon_mesh_processing::curvature_flow(pmesh, + CGAL::Polygon_mesh_processing::parameters::number_of_iterations(nb_iterations)); + poly_item->invalidateOpenGLBuffers(); + Q_EMIT poly_item->itemChanged(); + } + + + + + //poly_item->invalidateOpenGLBuffers(); + //Q_EMIT poly_item->itemChanged(); QApplication::restoreOverrideCursor(); } - void on_Curvature_button_clicked() - { - const Scene_interface::Item_id index = scene->mainSelectionIndex(); - Scene_polyhedron_item* poly_item = qobject_cast(scene->item(index)); - Polyhedron& pmesh = *poly_item->polyhedron(); - CGAL::Polygon_mesh_processing::curvature_flow(pmesh); - - poly_item->invalidateOpenGLBuffers(); - Q_EMIT poly_item->itemChanged(); - QApplication::restoreOverrideCursor(); - } private: diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.ui b/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.ui index 17036176c6c..cd942849bbc 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.ui +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.ui @@ -6,39 +6,68 @@ 0 0 - 400 - 300 + 378 + 229 Smoothing options - + - 90 - 60 + 80 + 130 221 51 - Compatible remeshing + Apply - + - 90 - 120 - 221 - 51 + 60 + 20 + 251 + 101 - - Curvature flow - + + + + + angle remeshing + + + + + + + + + + area remeshing + + + + + + + + + + Curvature flow + + + + + + + From dfb3a5c977064b83869151112f0fc813e80cf1ae Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Thu, 10 Aug 2017 11:29:47 +0300 Subject: [PATCH 065/102] plugin nb iterations parameter --- .../CGAL/Polygon_mesh_processing/smoothing.h | 23 ++++-- .../Plugins/PMP/Smoothing_plugin.cpp | 39 +++++++--- .../Plugins/PMP/Smoothing_plugin.ui | 78 ++++++++++++------- 3 files changed, 96 insertions(+), 44 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h index 7b3bcd465da..a420596d913 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h @@ -110,7 +110,7 @@ void compatible_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const Edge for(unsigned int i=0; i::type GeomTraits; + //nb_iterations + unsigned int nb_iterations = choose_param(get_param(np, internal_np::number_of_iterations), 1); #ifdef CGAL_PMP_REMESHING_VERBOSE t.stop(); @@ -395,14 +397,23 @@ void curvature_flow(PolygonMesh& pmesh, const NamedParameters& np) #ifdef CGAL_PMP_REMESHING_VERBOSE t.stop(); std::cout << " done ("<< t.time() <<" sec)." << std::endl; + std::cout << "#iter = " << nb_iterations << std::endl; std::cout << "Remeshing ..." << std::endl; t.reset(); t.start(); #endif - curvature_remesher.curvature_smoothing(); - //for now - //curvature_remesher.project_to_surface(); + for(unsigned int i=0; ihide(); } + void init_ui() + { + ui_widget.Angle_spinBox->setValue(1); + ui_widget.Area_spinBox->setValue(1); + ui_widget.Curvature_spinBox->setValue(1); + } + public Q_SLOTS: void smoothing_action() { dock_widget->show(); dock_widget->raise(); + + const Scene_interface::Item_id index = scene->mainSelectionIndex(); + Scene_polyhedron_item* poly_item = qobject_cast(scene->item(index)); + + if(poly_item) + { + init_ui(); + } } void on_Apply_clicked() @@ -99,34 +114,40 @@ public Q_SLOTS: if(ui_widget.Angle_checkBox->isChecked()) { - unsigned int nb_iterations = ui_widget.Angle_spinBox->value(); - CGAL::Polygon_mesh_processing::angle_remeshing(pmesh); + unsigned int nb_iter = ui_widget.Angle_spinBox->value(); + std::cout<<"Angle, nb_iterations---------->"<invalidateOpenGLBuffers(); Q_EMIT poly_item->itemChanged(); } if(ui_widget.Area_checkBox->isChecked()) { - unsigned int nb_iterations = ui_widget.Area_spinBox->value(); - CGAL::Polygon_mesh_processing::area_remeshing(pmesh); + unsigned int nb_iter = ui_widget.Area_spinBox->value(); + std::cout<<"Area, nb_iterations---------->"<invalidateOpenGLBuffers(); Q_EMIT poly_item->itemChanged(); } if(ui_widget.Curvature_checkBox->isChecked()) { - unsigned int nb_iterations = ui_widget.Curvature_spinBox->value(); + unsigned int nb_iter = ui_widget.Curvature_spinBox->value(); + std::cout<<"Curvature, nb_iterations---------->"<invalidateOpenGLBuffers(); Q_EMIT poly_item->itemChanged(); } - - //poly_item->invalidateOpenGLBuffers(); - //Q_EMIT poly_item->itemChanged(); QApplication::restoreOverrideCursor(); } diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.ui b/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.ui index cd942849bbc..e42aa033381 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.ui +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.ui @@ -6,8 +6,8 @@ 0 0 - 378 - 229 + 346 + 245 @@ -17,8 +17,8 @@ - 80 - 130 + 60 + 160 221 51 @@ -27,46 +27,66 @@ Apply - + - 60 + 20 20 - 251 - 101 + 311 + 131 - - - - - angle remeshing - - - - - - - - - - area remeshing - - - - + + - + Curvature flow - + + + + angle remeshing + + + + + + + area remeshing + + + + + + + + + + + type + + + Qt::AlignCenter + + + + + + + iterations + + + Qt::AlignCenter + + + From 3e34fdd5006ae777234b2541aaa9d7daf4cf8a0b Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Thu, 10 Aug 2017 22:02:32 +0300 Subject: [PATCH 066/102] another attempt to curvature flow --- .../Isotropic_remeshing/curvature_flow_impl.h | 111 +++++++++++++++++- .../CGAL/Polygon_mesh_processing/smoothing.h | 2 + 2 files changed, 108 insertions(+), 5 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h index db44d9434ca..6160a01acc4 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -16,6 +17,7 @@ #include #include +# define CGAL_PMP_COMPATIBLE_REMESHING_DEBUG namespace CGAL { @@ -121,7 +123,7 @@ public: // displacement vector Point Xi = get(vpmap_, source(hi, mesh_)); Point Xj = get(vpmap_, target(hi, mesh_)); - Vector vec(Xi, Xj); + Vector vec(Xj, Xi); // add weight. If weight is 0, then vec becomes 0. vec *= weight; @@ -133,7 +135,7 @@ public: if(sum_cot_weights != 0) weighted_move /= sum_cot_weights; - Point weighted_barycenter = get(vpmap_, v) + weighted_move; + Point weighted_barycenter = get(vpmap_, v) - weighted_move; barycenters[v] = weighted_barycenter; } // not on border @@ -151,7 +153,6 @@ public: Vector n = n_map[vp.first]; new_locations[vp.first] = q + ( n * Vector(q, p) ) * n ; - //new_locations[vp.first] = q; } // update location @@ -163,6 +164,106 @@ public: #endif put(vpmap_, vp.first, vp.second); +#ifdef CGAL_PMP_COMPATIBLE_REMESHING_DEBUG + std::cout<<" moved at: "<< vp.second << std::endl; +#endif + } + + } + + + void good_curvature_smoothing() + { + std::map n_map; + std::map barycenters; + + + for(vertex_descriptor v : vertices(mesh_)) + { + if(!is_border(v, mesh_)) // add && !is_constrained + { + // normals + Vector vn = compute_vertex_normal(v, mesh_, + Polygon_mesh_processing::parameters::vertex_point_map(vpmap_) + .geom_traits(traits_)); + n_map[v] = vn; + + + // area around vertex + double A = 0; + //take one halfedge whose target is v + for(halfedge_descriptor ht : halfedges_around_target(v, mesh_)) + { + // is it ok if it is degenerate? + A = area(faces_around_target(ht, mesh_), mesh_); + continue; + } + + // find incident halfedges + Edges_around_map he_map; + typename Edges_around_map::iterator it; + for(halfedge_descriptor hi : halfedges_around_source(v, mesh_)) + he_map[hi] = He_pair( next(hi, mesh_), prev(opposite(hi, mesh_), mesh_) ); + + + Vector weighted_move = CGAL::NULL_VECTOR; + for(it = he_map.begin(); it!= he_map.end(); ++it) + { + halfedge_descriptor hi = it->first; //main_he + + // weight + double weight = cot_angles(hi, it->second); // incd_edges + + // displacement vector + Point xi = get(vpmap_, source(hi, mesh_)); + Point xj = get(vpmap_, target(hi, mesh_)); + Vector vec(xj, xi); + + // add weight. + vec *= weight; + // sum vecs + weighted_move += vec; + std::cout<<"hi"; + } + + Vector curvature_normal = CGAL::NULL_VECTOR; + if (A != 0) + { + curvature_normal = weighted_move / (4 * A); + } + + Point old_point = get(vpmap_, v); + Point new_point = get(vpmap_, v) + curvature_normal; + barycenters[v] = new_point; + + } // not on border + + } // all vertices + + + /* + std::map new_locations; + for(const auto& vp: barycenters) + { + Point p = get(vpmap_, vp.first); + Point q = vp.second; + Vector n = n_map[vp.first]; + + new_locations[vp.first] = q + ( n * Vector(q, p) ) * n ; + } + */ + + + // update location + for(const auto& vp : barycenters) + //for(const auto& vp : new_locations) + { + +#ifdef CGAL_PMP_COMPATIBLE_REMESHING_DEBUG + std::cout << "from: "<< get(vpmap_, vp.first); +#endif + put(vpmap_, vp.first, vp.second); + #ifdef CGAL_PMP_COMPATIBLE_REMESHING_DEBUG std::cout<<" moved at: "<< vp.second << std::endl; #endif @@ -250,8 +351,8 @@ private: // data members PolygonMesh& mesh_; VertexPointMap& vpmap_; - //CGAL::internal::Cotangent_value_Meyer_secure cot_calculator_; - CGAL::internal::Cotangent_value_clamped_2 cot_calculator_; + CGAL::internal::Cotangent_value_Meyer_secure cot_calculator_; + //CGAL::internal::Cotangent_value_clamped_2 cot_calculator_; //CGAL::internal::Cotangent_value_clamped cot_calculator_; Triangle_list input_triangles_; Tree* tree_ptr_; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h index a420596d913..ac69e5b5fc9 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h @@ -410,6 +410,8 @@ void curvature_flow(PolygonMesh& pmesh, const NamedParameters& np) #endif curvature_remesher.curvature_smoothing(); + //curvature_remesher.good_curvature_smoothing(); + //for now //curvature_remesher.project_to_surface(); From 94f434231fedbfbcd2032a3fc0e3aa10a9a29abf Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Thu, 10 Aug 2017 23:01:12 +0300 Subject: [PATCH 067/102] clean redundant code & minor syntax corrections --- .../Isotropic_remeshing/curvature_flow_impl.h | 46 +-- .../Isotropic_remeshing/smoothing_impl.h | 292 ++++-------------- .../CGAL/Polygon_mesh_processing/smoothing.h | 117 ------- .../Plugins/PMP/Smoothing_plugin.cpp | 14 +- 4 files changed, 92 insertions(+), 377 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h index 6160a01acc4..ca46e8e117d 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h @@ -11,13 +11,15 @@ #include #include +#include +#include +#include #include -#include +#include #include #include -# define CGAL_PMP_COMPATIBLE_REMESHING_DEBUG namespace CGAL { @@ -60,7 +62,7 @@ public: template void init_remeshing(const FaceRange& face_range) { - for (face_descriptor f : face_range) + BOOST_FOREACH(face_descriptor f, face_range) { input_triangles_.push_back(triangle(f)); } @@ -80,7 +82,7 @@ public: // from repair.h nb_removed_faces = CGAL::Polygon_mesh_processing::remove_degenerate_faces(mesh_); -#ifdef CGAL_PMP_COMPATIBLE_REMESHING_DEBUG +#ifdef CGAL_PMP_SMOOTHING_DEBUG std::cout<<"nb_collapsed_faces: "< barycenters; std::map n_map; - for(vertex_descriptor v : vertices(mesh_)) + BOOST_FOREACH(vertex_descriptor v, vertices(mesh_)) { if(!is_border(v, mesh_)) // add && !is_constrained { @@ -105,11 +107,9 @@ public: // find incident halfedges Edges_around_map he_map; typename Edges_around_map::iterator it; - for(halfedge_descriptor hi : halfedges_around_source(v, mesh_)) + BOOST_FOREACH(halfedge_descriptor hi, halfedges_around_source(v, mesh_)) he_map[hi] = He_pair( next(hi, mesh_), prev(opposite(hi, mesh_), mesh_) ); - // maybe use a seperate function for this - // with cot weights Vector weighted_move = CGAL::NULL_VECTOR; double sum_cot_weights = 0; for(it = he_map.begin(); it!= he_map.end(); ++it) @@ -125,7 +125,7 @@ public: Point Xj = get(vpmap_, target(hi, mesh_)); Vector vec(Xj, Xi); - // add weight. If weight is 0, then vec becomes 0. + // add weight vec *= weight; // sum vecs weighted_move += vec; @@ -146,7 +146,7 @@ public: // compute locations on tangent plane typedef typename std::map::value_type VP; std::map new_locations; - for(const VP& vp: barycenters) + BOOST_FOREACH(const VP& vp, barycenters) { Point p = get(vpmap_, vp.first); Point q = vp.second; @@ -156,29 +156,29 @@ public: } // update location - for(const VP& vp : new_locations) + BOOST_FOREACH(const VP& vp, new_locations) { -#ifdef CGAL_PMP_COMPATIBLE_REMESHING_DEBUG +#ifdef CGAL_PMP_SMOOTHING_DEBUG std::cout << "from: "<< get(vpmap_, vp.first); #endif put(vpmap_, vp.first, vp.second); -#ifdef CGAL_PMP_COMPATIBLE_REMESHING_DEBUG +#ifdef CGAL_PMP_SMOOTHING_DEBUG std::cout<<" moved at: "<< vp.second << std::endl; #endif } } - + // test formula (14) void good_curvature_smoothing() { std::map n_map; std::map barycenters; - for(vertex_descriptor v : vertices(mesh_)) + BOOST_FOREACH(vertex_descriptor v, vertices(mesh_)) { if(!is_border(v, mesh_)) // add && !is_constrained { @@ -192,7 +192,7 @@ public: // area around vertex double A = 0; //take one halfedge whose target is v - for(halfedge_descriptor ht : halfedges_around_target(v, mesh_)) + BOOST_FOREACH(halfedge_descriptor ht, halfedges_around_target(v, mesh_)) { // is it ok if it is degenerate? A = area(faces_around_target(ht, mesh_), mesh_); @@ -202,7 +202,7 @@ public: // find incident halfedges Edges_around_map he_map; typename Edges_around_map::iterator it; - for(halfedge_descriptor hi : halfedges_around_source(v, mesh_)) + BOOST_FOREACH(halfedge_descriptor hi, halfedges_around_source(v, mesh_)) he_map[hi] = He_pair( next(hi, mesh_), prev(opposite(hi, mesh_), mesh_) ); @@ -243,7 +243,7 @@ public: /* std::map new_locations; - for(const auto& vp: barycenters) + BOOST_FOREACH(const auto& vp, barycenters) { Point p = get(vpmap_, vp.first); Point q = vp.second; @@ -255,16 +255,16 @@ public: // update location - for(const auto& vp : barycenters) - //for(const auto& vp : new_locations) + BOOST_FOREACH(const auto& vp, barycenters) + //BOOST_FOREACH(const auto& vp, new_locations) { -#ifdef CGAL_PMP_COMPATIBLE_REMESHING_DEBUG +#ifdef CGAL_PMP_SMOOTHING_DEBUG std::cout << "from: "<< get(vpmap_, vp.first); #endif put(vpmap_, vp.first, vp.second); -#ifdef CGAL_PMP_COMPATIBLE_REMESHING_DEBUG +#ifdef CGAL_PMP_SMOOTHING_DEBUG std::cout<<" moved at: "<< vp.second << std::endl; #endif } @@ -273,7 +273,7 @@ public: void project_to_surface() { - for( vertex_descriptor v : vertices(mesh_)) + BOOST_FOREACH(vertex_descriptor v, vertices(mesh_)) { if(!is_border(v, mesh_) ) // todo: && !is_constrained(v) { diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h index bf8e46012c9..b2ccfd3185b 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h @@ -14,6 +14,12 @@ #include #include +#include +#include +#include +#include +#include + namespace CGAL { @@ -27,7 +33,6 @@ namespace internal { template struct Edge_constraint_map { - typedef typename boost::graph_traits::edge_descriptor edge_descriptor; boost::shared_ptr> constrained_edges_ptr; @@ -51,7 +56,6 @@ public: friend bool get(const Edge_constraint_map& map, const edge_descriptor& e) { - // assertion on pmesh return map.constrained_edges_ptr->find(e) != map.constrained_edges_ptr->end(); } @@ -65,11 +69,9 @@ public: map.constrained_edges_ptr->erase(e); } - }; - template class Compatible_remesher { @@ -108,18 +110,17 @@ public: template void init_remeshing(const FaceRange& face_range) { - for (face_descriptor f : face_range) + BOOST_FOREACH(face_descriptor f, face_range) { - input_triangles_.push_back(triangle(f)); //avoid push_back, reserve space + // todo: avoid push back and reserve the space + input_triangles_.push_back(triangle(f)); } tree_ptr_ = new Tree(input_triangles_.begin(), input_triangles_.end()); tree_ptr_->accelerate_distance_queries(); - //update constrained edges + // update constrained edges check_constrained_edges(); - - min_edge_len_ = init_min_edge_length(); } std::size_t remove_degenerate_faces() @@ -129,91 +130,25 @@ public: // from repair.h nb_removed_faces = CGAL::Polygon_mesh_processing::remove_degenerate_faces(mesh_); +#ifdef CGAL_PMP_SMOOTHING_DEBUG std::cout<<"nb_collapsed_faces: "< edges_to_collapse, non_topologically_valid_collapses; - - // collect short edges - for(edge_descriptor e : edges(mesh_)) - { - if(edge_should_collapse(e)) - edges_to_collapse.insert(e); - } - - // collapse - while(!edges_to_collapse.empty()) - { - while(!edges_to_collapse.empty()) - { - edge_descriptor e = *edges_to_collapse.begin(); - edges_to_collapse.erase(edges_to_collapse.begin()); - - // link condition - if(!Euler::does_satisfy_link_condition(e, mesh_)) - { - non_topologically_valid_collapses.insert(e); - continue; - } - - // take out from short_edges prev and prev(opposite), which will be collapsed - halfedge_descriptor he = halfedge(e, mesh_); - - // verbose - todo - vertex_descriptor vs = source(he, mesh_); - vertex_descriptor vt = target(he, mesh_); - // - - edges_to_collapse.erase(edge(prev(he, mesh_), mesh_)); - edges_to_collapse.erase(edge(prev(opposite(he, mesh_), mesh_), mesh_)); - - // shoot out edge to be collapsed from topologically_non_valid - non_topologically_valid_collapses.erase(e); - non_topologically_valid_collapses.erase(edge(prev(he, mesh_), mesh_)); - non_topologically_valid_collapses.erase(edge(prev(opposite(he, mesh_), mesh_), mesh_)); - - vertex_descriptor v = Euler::collapse_edge(e, mesh_); - - // check if an out_edge now is too short - for (edge_descriptor out_e : out_edges(v, mesh_)) - { - if(edge_should_collapse(out_e)) - edges_to_collapse.insert(out_e); - } - - nb_collapsed_edges++; - } - - edges_to_collapse.swap(non_topologically_valid_collapses); - } - - // debug - std::cout<<"nb_collapsed_edges: "< barycenters; - //boost::vector_property_map n_map; std::map n_map; - - for(vertex_descriptor v : vertices(mesh_)) + BOOST_FOREACH(vertex_descriptor v, vertices(mesh_)) { if(!is_border(v, mesh_) && !is_constrained(v)) { -#ifdef CGAL_PMP_COMPATIBLE_REMESHING_DEBUG -std::cout<<"processing vertex: "<< v << std::endl; +#ifdef CGAL_PMP_SMOOTHING_DEBUG + std::cout<<"processing vertex: "<< v << std::endl; #endif // compute normal to v @@ -224,28 +159,12 @@ std::cout<<"processing vertex: "<< v << std::endl; Edges_around_map he_map; typename Edges_around_map::iterator it; - - for(halfedge_descriptor hi : halfedges_around_source(v, mesh_)) // or make it around target + BOOST_FOREACH(halfedge_descriptor hi, halfedges_around_source(v, mesh_)) he_map[hi] = He_pair( next(hi, mesh_), prev(opposite(hi, mesh_), mesh_) ); -#ifdef CGAL_PMP_COMPATIBLE_REMESHING_DEBUG -for(it = he_map.begin(); it!=he_map.end(); ++it) -{ - halfedge_descriptor main_he = it->first; - He_pair he_pair = it->second; - std::cout<< "main: " << main_he; - std::cout<<" ("<"<< target(main_he, mesh_)<<")"; - std::cout<< " - incident: "<< he_pair.first; - std::cout<<" ("<"<< target(he_pair.first, mesh_)<<")"; - std::cout<<" and " << he_pair.second; - std::cout<<" ("<"<< target(he_pair.second, mesh_)<<")"<first; @@ -255,12 +174,12 @@ for(it = he_map.begin(); it!=he_map.end(); ++it) // calculate angle double angle = get_angle(incident_pair, vn); - if(angle < 1e-5) // temp + if(angle < 1e-5) continue; //small angles have more weight double weight = 1.0 / (angle*angle); - opposite_weight_factor += weight; + weights_sum += weight; if(use_weights) move += weight * rotated_edge; @@ -269,44 +188,39 @@ for(it = he_map.begin(); it!=he_map.end(); ++it) } // if at least 1 angle was summed - if(use_weights && opposite_weight_factor != 0) - move /= opposite_weight_factor; + if(use_weights && weights_sum != 0) + move /= weights_sum; else move /= CGAL::to_double(he_map.size()); - barycenters[v] = (get(vpmap_, v) + move) ; - } // not on border } // for each v - - // compute locations on tangent plane typedef typename std::map::value_type VP; std::map new_locations; - for(const VP& vp: barycenters) + BOOST_FOREACH(const VP& vp, barycenters) { - Point q = vp.second; Point p = get(vpmap_, vp.first); + Point q = vp.second; Vector n = n_map[vp.first]; new_locations[vp.first] = q + ( n * Vector(q, p) ) * n ; } - - // perform moves - for(const VP& vp : new_locations) + // update location + BOOST_FOREACH(const VP& vp, new_locations) { -#ifdef CGAL_PMP_COMPATIBLE_REMESHING_DEBUG -std::cout << "from: "<< get(vpmap_, vp.first); +#ifdef CGAL_PMP_SMOOTHING_DEBUG + std::cout << "from: "<< get(vpmap_, vp.first); #endif put(vpmap_, vp.first, vp.second); -#ifdef CGAL_PMP_COMPATIBLE_REMESHING_DEBUG -std::cout<<" moved at: "<< vp.second << std::endl; +#ifdef CGAL_PMP_SMOOTHING_DEBUG + std::cout<<" moved at: "<< vp.second << std::endl; #endif } @@ -315,26 +229,26 @@ std::cout<<" moved at: "<< vp.second << std::endl; void area_relaxation(const double& precision) { - count_non_convex_energy_ = 0; //temp; +#ifdef CGAL_PMP_SMOOTHING_DEBUG + count_non_convex_energy_ = 0; +#endif + unsigned int moved_points = 0; - for(vertex_descriptor v : vertices(mesh_)) + BOOST_FOREACH(vertex_descriptor v, vertices(mesh_)) { - if(!is_border(v, mesh_) && !is_constrained(v)) { - if (gradient_descent(v, precision)) { moved_points++; } - } // not on border - + } } -#ifdef CGAL_PMP_COMPATIBLE_REMESHING_DEBUG +#ifdef CGAL_PMP_SMOOTHING_DEBUG std::cout<<"moved points: "< calc_areas(const vertex_descriptor& v) { std::vector areas; - for(halfedge_descriptor h : halfedges_around_source(v, mesh_)) + BOOST_FOREACH(halfedge_descriptor h, halfedges_around_source(v, mesh_)) { vertex_descriptor pi = source(next(h, mesh_), mesh_); vertex_descriptor pi1 = target(next(h, mesh_), mesh_); @@ -476,7 +390,7 @@ private: void compute_derivatives(double& drdx, double& drdy, double& drdz, const vertex_descriptor& v, const double& S_av) { - for(halfedge_descriptor h : halfedges_around_source(v, mesh_)) + BOOST_FOREACH(halfedge_descriptor h, halfedges_around_source(v, mesh_)) { vertex_descriptor pi = source(next(h, mesh_), mesh_); vertex_descriptor pi1 = target(next(h, mesh_), mesh_); @@ -502,7 +416,6 @@ private: bool gradient_descent(const vertex_descriptor& v, const double& precision) { - bool move_flag; double x, y, z, x_new, y_new, z_new, drdx, drdy, drdz; x = get(vpmap_, v).x(); @@ -516,11 +429,6 @@ private: if(energy == 0) return false; -#ifdef CGAL_PMP_COMPATIBLE_REMESHING_DEBUG - std::ofstream out("data/energy.txt"); - std::ofstream out("data/coords.txt"); - std::ofstream out("data/areas.txt"); -#endif double energy_new = 0; double relative_energy = precision + 1; unsigned int t = 1; @@ -534,16 +442,6 @@ private: drdx=0, drdy=0, drdz=0; compute_derivatives(drdx, drdy, drdz, v, S_av); -#ifdef CGAL_PMP_COMPATIBLE_REMESHING_DEBUG - std::vector areas = calc_areas(v); - std::cout<<"v= "< tolerance); + CGAL_assertion(vec_main_he.squared_length() > tolerance); // find bisector Vector bisector = CGAL::NULL_VECTOR; @@ -622,15 +521,15 @@ private: if( bisector.squared_length() < 0.001 ) // -> length = 0.01 -> sin(theta) = 0.01 -> theta = 0.57 degrees { // angle is (almost) 180 degrees, take the perpendicular - Vector normal_vec = find_perpendicular(edge1, vt, pv); // normal to edge and found on (vt-pv)'s plane + Vector normal_vec = find_perpendicular(edge1, pt, ps); // normal to edge and found on (vec_main_he)'s plane CGAL_assertion(normal_vec != CGAL::NULL_VECTOR); CGAL_assertion(CGAL::scalar_product(edge1, normal_vec) < tolerance); - Segment b_segment(vt, vt + normal_vec); + Segment b_segment(pt, pt + normal_vec); Point b_segment_end = b_segment.target(); - if(CGAL::angle(b_segment_end, vt, pv) == CGAL::OBTUSE) + if(CGAL::angle(b_segment_end, pt, ps) == CGAL::OBTUSE) { b_segment = b_segment.opposite(); } @@ -640,16 +539,12 @@ private: correct_bisector(bisector, main_he); - double target_length = CGAL::sqrt(sqlength(main_he)); double bisector_length = CGAL::sqrt(bisector.squared_length()); - - CGAL_assertion( ( target_length - tolerance < bisector_length ) && ( bisector_length < target_length + tolerance ) ); - return bisector; } @@ -725,7 +620,7 @@ private: void check_constrained_edges() { - for(edge_descriptor e : edges(mesh_)) + BOOST_FOREACH(edge_descriptor e, edges(mesh_)) { if (is_constrained(e)) { @@ -737,58 +632,6 @@ private: } } - // degenerate fixing functions - - bool edge_should_collapse(edge_descriptor e) - { - halfedge_descriptor he = halfedge(e, mesh_); - Point s = get(vpmap_, source(he, mesh_)); - Point t = get(vpmap_, target(he, mesh_)); - - double sq_length = traits_.compute_squared_distance_3_object()(s, t); - - if(sq_length < min_edge_len_) - return true; - else - return false; - } - - struct Vertex_to_point - { - Vertex_to_point(VertexPointMap vpmap) : vpmap(vpmap){} - - typedef typename boost::property_traits::reference output_type; - - output_type operator()(vertex_descriptor vd) const - { - return get(vpmap, vd); - } - - VertexPointMap vpmap; - }; - - double init_min_edge_length() - { - vertex_iterator vi, ve; - boost::tie(vi, ve) = vertices(mesh_); - Vertex_to_point v_to_p(vpmap_); - - Bbox_3 bbox= CGAL::bbox_3( - boost::make_transform_iterator(vi, v_to_p), - boost::make_transform_iterator(ve, v_to_p)); - - return 0.01 * diagonal_length(bbox); - } - - double diagonal_length(const Bbox_3& bbox) - { - double dx = bbox.xmax() - bbox.xmin(); - double dy = bbox.ymax() - bbox.ymin(); - double dz = bbox.zmax() - bbox.zmin(); - - double diag = dx * dx + dy * dy + dz * dz; - return std::sqrt(diag); - } @@ -799,10 +642,11 @@ private: EdgeConstraintMap ecmap_; Triangle_list input_triangles_; Tree* tree_ptr_; - unsigned int count_non_convex_energy_; GeomTraits traits_; - double min_edge_len_; +#ifdef CGAL_PMP_SMOOTHING_DEBUG + unsigned int count_non_convex_energy_; +#endif }; @@ -810,14 +654,6 @@ private: - - - - - - - - } //namespace internal } // namespace Polygon_mesh_processing } // namespace CGAL diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h index ac69e5b5fc9..13992f36960 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h @@ -24,123 +24,6 @@ namespace Polygon_mesh_processing { -template -void compatible_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const EdgeRange& edges, const NamedParameters& np) -{ - using boost::choose_param; - using boost::get_param; - -#ifdef CGAL_PMP_REMESHING_VERBOSE - CGAL::Timer t; - std::cout << "Remeshing parameters..."; - std::cout.flush(); - t.start(); -#endif - - //geom traits - typedef typename GetGeomTraits::type GeomTraits; - - //vpmap - typedef typename GetVertexPointMap::type VertexPointMap; - VertexPointMap vpmap = choose_param(get_param(np, internal_np::vertex_point), - get_property_map(CGAL::vertex_point, pmesh)); - - //vcmap - typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - typedef typename boost::lookup_named_param_def < - internal_np::vertex_is_constrained_t, - NamedParameters, - internal::No_constraint_pmap//default - > ::type VCMap; - VCMap vcmap = choose_param(get_param(np, internal_np::vertex_is_constrained), - internal::No_constraint_pmap()); - - //ecmap - typedef typename boost::lookup_named_param_def < - internal_np::edge_is_constrained_t, - NamedParameters, - internal::Edge_constraint_map - > ::type ECMap; - // either fill map with given constrined edges or use default constructor for an NULL map - ECMap ecmap = (boost::is_same >::value) - ? choose_param(get_param(np, internal_np::edge_is_constrained), - internal::Edge_constraint_map(edges)) - : choose_param(get_param(np, internal_np::edge_is_constrained), - internal::Edge_constraint_map()); - - //nb_iterations - unsigned int nb_iterations = choose_param(get_param(np, internal_np::number_of_iterations), 1); - - //gradient descent precision - double gd_precision = choose_param(get_param(np, internal_np::gradient_descent_precision), 0.001); - - //use weighted angles - bool use_weights = choose_param(get_param(np, internal_np::use_weights), false); - - -#ifdef CGAL_PMP_REMESHING_VERBOSE - t.stop(); - std::cout << "\rRemeshing parameters done ("<< t.time() <<" sec)" << std::endl; - std::cout << "Remesher construction..."; - std::cout.flush(); - t.reset(); t.start(); -#endif - - CGAL::Polygon_mesh_processing::internal::Compatible_remesher - remesher(pmesh, vpmap, vcmap, ecmap); - remesher.init_remeshing(faces); - -#ifdef CGAL_PMP_REMESHING_VERBOSE - t.stop(); - std::cout << " done ("<< t.time() <<" sec)." << std::endl; - std::cout << "Removing degenerate edges and faces..." << std::endl; - t.reset(); t.start(); -#endif - - remesher.remove_degenerate_faces(); - -#ifdef CGAL_PMP_REMESHING_VERBOSE - t.stop(); - std::cout << " done ("<< t.time() <<" sec)." << std::endl; - std::cout << "#iter = " << nb_iterations << std::endl; - std::cout << "Remeshing ..." << std::endl; - t.reset(); t.start(); -#endif - - for(unsigned int i=0; i -void compatible_remeshing(PolygonMesh& pmesh) -{ - compatible_remeshing(pmesh, faces(pmesh), edges(pmesh), parameters::all_default()); -} - -template -void compatible_remeshing(PolygonMesh& pmesh, const NamedParameters& np) -{ - compatible_remeshing(pmesh, faces(pmesh), edges(pmesh), np); -} - - template void angle_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const EdgeRange& edges, const NamedParameters& np) { diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.cpp index fc0a83c8514..7a1bde0557e 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.cpp @@ -112,12 +112,13 @@ public Q_SLOTS: Scene_polyhedron_item* poly_item = qobject_cast(scene->item(index)); Polyhedron& pmesh = *poly_item->polyhedron(); + QApplication::setOverrideCursor(Qt::WaitCursor); + if(ui_widget.Angle_checkBox->isChecked()) { unsigned int nb_iter = ui_widget.Angle_spinBox->value(); - std::cout<<"Angle, nb_iterations---------->"<invalidateOpenGLBuffers(); Q_EMIT poly_item->itemChanged(); @@ -126,10 +127,8 @@ public Q_SLOTS: if(ui_widget.Area_checkBox->isChecked()) { unsigned int nb_iter = ui_widget.Area_spinBox->value(); - std::cout<<"Area, nb_iterations---------->"<invalidateOpenGLBuffers(); Q_EMIT poly_item->itemChanged(); @@ -138,16 +137,13 @@ public Q_SLOTS: if(ui_widget.Curvature_checkBox->isChecked()) { unsigned int nb_iter = ui_widget.Curvature_spinBox->value(); - std::cout<<"Curvature, nb_iterations---------->"<invalidateOpenGLBuffers(); Q_EMIT poly_item->itemChanged(); } - - QApplication::restoreOverrideCursor(); } From 1d8f62963ad0484501c13cf7971dd7a9f0d9984a Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Fri, 11 Aug 2017 20:00:10 +0300 Subject: [PATCH 069/102] use constrained vertices on all types of smoothing --- .../Isotropic_remeshing/curvature_flow_impl.h | 58 +++++++---- .../Isotropic_remeshing/smoothing_impl.h | 66 ++----------- .../CGAL/Polygon_mesh_processing/smoothing.h | 95 +++++++++++++------ 3 files changed, 119 insertions(+), 100 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h index ca46e8e117d..6531523f88f 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h @@ -29,7 +29,7 @@ namespace internal { -template +template class Curvature_flow { @@ -37,31 +37,33 @@ class Curvature_flow typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::face_descriptor face_descriptor; typedef typename boost::graph_traits::edge_descriptor edge_descriptor; - typedef typename boost::graph_traits::vertex_iterator vertex_iterator; typedef typename GeomTraits::Point_3 Point; typedef typename GeomTraits::Vector_3 Vector; - typedef typename GeomTraits::FT FT; typedef typename GeomTraits::Triangle_3 Triangle; typedef std::vector Triangle_list; - // - typedef std::pair He_pair; - typedef std::map Edges_around_map; - typedef CGAL::AABB_triangle_primitive AABB_Primitive; typedef CGAL::AABB_traits AABB_Traits; typedef CGAL::AABB_tree Tree; + // + typedef std::pair He_pair; + typedef std::map Edges_around_map; public: - Curvature_flow(PolygonMesh& pmesh, VertexPointMap& vpmap) : mesh_(pmesh), vpmap_(vpmap), cot_calculator_(pmesh, vpmap){} + Curvature_flow(PolygonMesh& pmesh, VertexPointMap& vpmap, VertexConstraintMap& vcmap, EdgeConstraintMap& ecmap) : + mesh_(pmesh), vpmap_(vpmap), vcmap_(vcmap), ecmap_(ecmap), cot_calculator_(pmesh, vpmap) + {} template void init_remeshing(const FaceRange& face_range) { + + check_constraints(); + BOOST_FOREACH(face_descriptor f, face_range) { input_triangles_.push_back(triangle(f)); @@ -70,9 +72,6 @@ public: tree_ptr_ = new Tree(input_triangles_.begin(), input_triangles_.end()); tree_ptr_->accelerate_distance_queries(); - //TODO: update constrained edges - //check_constrained_edges(); - } std::size_t remove_degenerate_faces() @@ -96,8 +95,9 @@ public: BOOST_FOREACH(vertex_descriptor v, vertices(mesh_)) { - if(!is_border(v, mesh_)) // add && !is_constrained + if(!is_border(v, mesh_) && !is_constrained(v)) { + // normals Vector vn = compute_vertex_normal(v, mesh_, Polygon_mesh_processing::parameters::vertex_point_map(vpmap_) @@ -348,17 +348,43 @@ private: return a1 + a2; } + bool is_constrained(const edge_descriptor& e) + { + return get(ecmap_, e); + } + + bool is_constrained(const vertex_descriptor& v) + { + return get(vcmap_, v); + } + + void check_constraints() + { + BOOST_FOREACH(edge_descriptor e, edges(mesh_)) + { + if (is_constrained(e)) + { + vertex_descriptor vs = source(e, mesh_); + vertex_descriptor vt = target(e, mesh_); + put(vcmap_, vs, true); + put(vcmap_, vt, true); + } + } + } + // data members PolygonMesh& mesh_; VertexPointMap& vpmap_; - CGAL::internal::Cotangent_value_Meyer_secure cot_calculator_; - //CGAL::internal::Cotangent_value_clamped_2 cot_calculator_; - //CGAL::internal::Cotangent_value_clamped cot_calculator_; + VertexConstraintMap vcmap_; + EdgeConstraintMap ecmap_; Triangle_list input_triangles_; Tree* tree_ptr_; GeomTraits traits_; double min_sq_edge_len_; - + // from Weights.h + CGAL::internal::Cotangent_value_Meyer_secure cot_calculator_; + //CGAL::internal::Cotangent_value_clamped_2 cot_calculator_; + //CGAL::internal::Cotangent_value_clamped cot_calculator_; }; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h index b2ccfd3185b..dd808bc9d77 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h @@ -29,56 +29,12 @@ namespace internal { - -template -struct Edge_constraint_map -{ - typedef typename boost::graph_traits::edge_descriptor edge_descriptor; - - boost::shared_ptr> constrained_edges_ptr; - -public: - typedef edge_descriptor key_type; - typedef bool value_type; - typedef value_type& reference; - typedef boost::read_write_property_map_tag category; - - Edge_constraint_map() : constrained_edges_ptr(new std::set() ) - {} - - Edge_constraint_map(const EdgeRange& edges) : constrained_edges_ptr(new std::set() ) - { - for (edge_descriptor e : edges) - { - constrained_edges_ptr->insert(e); - } - } - - friend bool get(const Edge_constraint_map& map, const edge_descriptor& e) - { - return map.constrained_edges_ptr->find(e) != map.constrained_edges_ptr->end(); - } - - friend void put(const Edge_constraint_map& map, const edge_descriptor& e) - { - map.constrained_edges_ptr->insert(e); - } - - friend void remove(const Edge_constraint_map& map, const edge_descriptor& e) - { - map.constrained_edges_ptr->erase(e); - } - -}; - - -template +template class Compatible_remesher { typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - typedef typename boost::graph_traits::vertex_iterator vertex_iterator; typedef typename boost::graph_traits::face_descriptor face_descriptor; typedef typename boost::graph_traits::edge_descriptor edge_descriptor; @@ -98,7 +54,7 @@ class Compatible_remesher public: - Compatible_remesher(PolygonMesh& pmesh, VertexPointMap& vpmap, VertexConstraitMap& vcmap, EdgeConstraintMap& ecmap) : + Compatible_remesher(PolygonMesh& pmesh, VertexPointMap& vpmap, VertexConstraintMap& vcmap, EdgeConstraintMap& ecmap) : mesh_(pmesh), vpmap_(vpmap), vcmap_(vcmap), ecmap_(ecmap) {} @@ -109,7 +65,9 @@ public: template void init_remeshing(const FaceRange& face_range) - { + { + check_constraints(); + BOOST_FOREACH(face_descriptor f, face_range) { // todo: avoid push back and reserve the space @@ -119,8 +77,6 @@ public: tree_ptr_ = new Tree(input_triangles_.begin(), input_triangles_.end()); tree_ptr_->accelerate_distance_queries(); - // update constrained edges - check_constrained_edges(); } std::size_t remove_degenerate_faces() @@ -147,10 +103,6 @@ public: if(!is_border(v, mesh_) && !is_constrained(v)) { -#ifdef CGAL_PMP_SMOOTHING_DEBUG - std::cout<<"processing vertex: "<< v << std::endl; -#endif - // compute normal to v Vector vn = compute_vertex_normal(v, mesh_, Polygon_mesh_processing::parameters::vertex_point_map(vpmap_) @@ -177,7 +129,7 @@ public: if(angle < 1e-5) continue; - //small angles have more weight + // small angles carry more weight double weight = 1.0 / (angle*angle); weights_sum += weight; @@ -239,6 +191,8 @@ public: { if(!is_border(v, mesh_) && !is_constrained(v)) { + + if (gradient_descent(v, precision)) { moved_points++; @@ -618,7 +572,7 @@ private: return get(vcmap_, v); } - void check_constrained_edges() + void check_constraints() { BOOST_FOREACH(edge_descriptor e, edges(mesh_)) { @@ -638,7 +592,7 @@ private: private: PolygonMesh& mesh_; VertexPointMap& vpmap_; - VertexConstraitMap vcmap_; + VertexConstraintMap vcmap_; EdgeConstraintMap ecmap_; Triangle_list input_triangles_; Tree* tree_ptr_; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h index 13992f36960..cbaf3e70818 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h @@ -24,8 +24,8 @@ namespace Polygon_mesh_processing { -template -void angle_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const EdgeRange& edges, const NamedParameters& np) +template +void angle_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const NamedParameters& np) { using boost::choose_param; using boost::get_param; @@ -45,6 +45,11 @@ void angle_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const EdgeRange VertexPointMap vpmap = choose_param(get_param(np, internal_np::vertex_point), get_property_map(CGAL::vertex_point, pmesh)); + //fimap + typedef typename GetFaceIndexMap::type FIMap; + FIMap fimap = choose_param(get_param(np, internal_np::face_index), + get_property_map(face_index, pmesh)); + //vcmap typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::lookup_named_param_def < @@ -59,14 +64,13 @@ void angle_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const EdgeRange typedef typename boost::lookup_named_param_def < internal_np::edge_is_constrained_t, NamedParameters, - internal::Edge_constraint_map + internal::Border_constraint_pmap > ::type ECMap; - // either fill map with given constrined edges or use default constructor for an NULL map - ECMap ecmap = (boost::is_same >::value) + ECMap ecmap = (boost::is_same >::value) ? choose_param(get_param(np, internal_np::edge_is_constrained), - internal::Edge_constraint_map(edges)) + internal::Border_constraint_pmap(pmesh, faces, fimap)) : choose_param(get_param(np, internal_np::edge_is_constrained), - internal::Edge_constraint_map()); + internal::Border_constraint_pmap()); //nb_iterations unsigned int nb_iterations = choose_param(get_param(np, internal_np::number_of_iterations), 1); @@ -74,8 +78,7 @@ void angle_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const EdgeRange //use weighted angles bool use_weights = choose_param(get_param(np, internal_np::use_weights), false); - - CGAL::Polygon_mesh_processing::internal::Compatible_remesher + internal::Compatible_remesher remesher(pmesh, vpmap, vcmap, ecmap); remesher.init_remeshing(faces); @@ -119,18 +122,18 @@ void angle_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const EdgeRange template void angle_remeshing(PolygonMesh& pmesh, const NamedParameters& np) { - angle_remeshing(pmesh, faces(pmesh), edges(pmesh), np); + angle_remeshing(pmesh, faces(pmesh), np); } template void angle_remeshing(PolygonMesh& pmesh) { - angle_remeshing(pmesh, faces(pmesh), edges(pmesh), parameters::all_default()); + angle_remeshing(pmesh, faces(pmesh), parameters::all_default()); } -template -void area_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const EdgeRange& edges, const NamedParameters& np) +template +void area_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const NamedParameters& np) { using boost::choose_param; using boost::get_param; @@ -150,6 +153,11 @@ void area_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const EdgeRange& VertexPointMap vpmap = choose_param(get_param(np, internal_np::vertex_point), get_property_map(CGAL::vertex_point, pmesh)); + //fimap + typedef typename GetFaceIndexMap::type FIMap; + FIMap fimap = choose_param(get_param(np, internal_np::face_index), + get_property_map(face_index, pmesh)); + //vcmap typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::lookup_named_param_def < @@ -164,14 +172,13 @@ void area_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const EdgeRange& typedef typename boost::lookup_named_param_def < internal_np::edge_is_constrained_t, NamedParameters, - internal::Edge_constraint_map + internal::Border_constraint_pmap > ::type ECMap; - // either fill map with given constrined edges or use default constructor for an NULL map - ECMap ecmap = (boost::is_same >::value) + ECMap ecmap = (boost::is_same >::value) ? choose_param(get_param(np, internal_np::edge_is_constrained), - internal::Edge_constraint_map(edges)) // to fix this + internal::Border_constraint_pmap(pmesh, faces, fimap)) : choose_param(get_param(np, internal_np::edge_is_constrained), - internal::Edge_constraint_map()); + internal::Border_constraint_pmap()); //nb_iterations unsigned int nb_iterations = choose_param(get_param(np, internal_np::number_of_iterations), 1); @@ -179,8 +186,7 @@ void area_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const EdgeRange& //gradient descent precision double gd_precision = choose_param(get_param(np, internal_np::gradient_descent_precision), 0.001); - - CGAL::Polygon_mesh_processing::internal::Compatible_remesher + internal::Compatible_remesher remesher(pmesh, vpmap, vcmap, ecmap); remesher.init_remeshing(faces); @@ -224,17 +230,17 @@ void area_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const EdgeRange& template void area_remeshing(PolygonMesh& pmesh, const NamedParameters& np) { - area_remeshing(pmesh, faces(pmesh), edges(pmesh), np); + area_remeshing(pmesh, faces(pmesh), np); } template void area_remeshing(PolygonMesh& pmesh) { - area_remeshing(pmesh, faces(pmesh), edges(pmesh), parameters::all_default()); + area_remeshing(pmesh, faces(pmesh), parameters::all_default()); } -template // to fix: use constraits -void curvature_flow(PolygonMesh& pmesh, const NamedParameters& np) +template +void curvature_flow(PolygonMesh& pmesh, const FaceRange& faces, const NamedParameters& np) { using boost::choose_param; using boost::get_param; @@ -246,13 +252,40 @@ void curvature_flow(PolygonMesh& pmesh, const NamedParameters& np) t.start(); #endif + // GeomTraits + typedef typename GetGeomTraits::type GeomTraits; + //vpmap typedef typename GetVertexPointMap::type VertexPointMap; VertexPointMap vpmap = choose_param(get_param(np, internal_np::vertex_point), get_property_map(CGAL::vertex_point, pmesh)); - // GeomTraits - typedef typename GetGeomTraits::type GeomTraits; + //fimap + typedef typename GetFaceIndexMap::type FIMap; + FIMap fimap = choose_param(get_param(np, internal_np::face_index), + get_property_map(face_index, pmesh)); + + //vcmap + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::lookup_named_param_def < + internal_np::vertex_is_constrained_t, + NamedParameters, + internal::No_constraint_pmap//default + > ::type VCMap; + VCMap vcmap = choose_param(get_param(np, internal_np::vertex_is_constrained), + internal::No_constraint_pmap()); + + //ecmap + typedef typename boost::lookup_named_param_def < + internal_np::edge_is_constrained_t, + NamedParameters, + internal::Border_constraint_pmap + > ::type ECMap; + ECMap ecmap = (boost::is_same >::value) + ? choose_param(get_param(np, internal_np::edge_is_constrained), + internal::Border_constraint_pmap(pmesh, faces, fimap)) + : choose_param(get_param(np, internal_np::edge_is_constrained), + internal::Border_constraint_pmap()); //nb_iterations unsigned int nb_iterations = choose_param(get_param(np, internal_np::number_of_iterations), 1); @@ -265,8 +298,9 @@ void curvature_flow(PolygonMesh& pmesh, const NamedParameters& np) t.reset(); t.start(); #endif - internal::Curvature_flow curvature_remesher(pmesh, vpmap); - curvature_remesher.init_remeshing(faces(pmesh)); + internal::Curvature_flow + curvature_remesher(pmesh, vpmap, vcmap, ecmap); + curvature_remesher.init_remeshing(faces); #ifdef CGAL_PMP_REMESHING_VERBOSE t.stop(); @@ -307,7 +341,12 @@ void curvature_flow(PolygonMesh& pmesh, const NamedParameters& np) std::cout< +void curvature_flow(PolygonMesh& pmesh, const NamedParameters& np) +{ + curvature_flow(pmesh, faces(pmesh), np); } template From e6d3c9224c0856d81624c0cc29d5470c64c23380 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Sat, 12 Aug 2017 16:44:36 +0300 Subject: [PATCH 070/102] change directory --- .../{Isotropic_remeshing => Smoothing}/curvature_flow_impl.h | 0 .../internal/{Isotropic_remeshing => Smoothing}/smoothing_impl.h | 1 - 2 files changed, 1 deletion(-) rename Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/{Isotropic_remeshing => Smoothing}/curvature_flow_impl.h (100%) rename Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/{Isotropic_remeshing => Smoothing}/smoothing_impl.h (99%) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/curvature_flow_impl.h similarity index 100% rename from Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/curvature_flow_impl.h rename to Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/curvature_flow_impl.h diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h similarity index 99% rename from Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h rename to Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h index dd808bc9d77..716ced7e1c8 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/smoothing_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h @@ -504,7 +504,6 @@ private: double get_angle(const He_pair& incd_edges, const Vector& vn) { - Point s = get(vpmap_, source(incd_edges.first, mesh_)); Point p1 = get(vpmap_, target(incd_edges.first, mesh_)); Point p2 = get(vpmap_, source(incd_edges.second, mesh_)); From 42e7d12df65e9c93b524083918d5d2dc6f9ca472 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Sat, 12 Aug 2017 22:58:00 +0300 Subject: [PATCH 071/102] debugging curvature flow --- .../internal/Smoothing/curvature_flow_impl.h | 156 ++++++++++++++---- .../internal/Smoothing/smoothing_impl.h | 12 +- .../CGAL/Polygon_mesh_processing/smoothing.h | 10 +- 3 files changed, 139 insertions(+), 39 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/curvature_flow_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/curvature_flow_impl.h index 6531523f88f..a5a36a985b2 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/curvature_flow_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/curvature_flow_impl.h @@ -20,6 +20,7 @@ #include #include +#include namespace CGAL { @@ -41,6 +42,7 @@ class Curvature_flow typedef typename GeomTraits::Point_3 Point; typedef typename GeomTraits::Vector_3 Vector; typedef typename GeomTraits::Triangle_3 Triangle; + typedef typename GeomTraits::FT FT; typedef std::vector Triangle_list; typedef CGAL::AABB_triangle_primitive AABB_Primitive; @@ -48,15 +50,32 @@ class Curvature_flow typedef CGAL::AABB_tree Tree; // - typedef std::pair He_pair; - typedef std::map Edges_around_map; + typedef std::pair he_pair; + typedef std::map Edges_around_map; + + typedef typename CGAL::Monge_via_jet_fitting Monge_via_jet_fitting; + typedef typename Monge_via_jet_fitting::Monge_form Monge_form; + public: Curvature_flow(PolygonMesh& pmesh, VertexPointMap& vpmap, VertexConstraintMap& vcmap, EdgeConstraintMap& ecmap) : mesh_(pmesh), vpmap_(vpmap), vcmap_(vcmap), ecmap_(ecmap), cot_calculator_(pmesh, vpmap) - {} + { + + /* + std::size_t num_points = vertices(mesh_).size(); + std::size_t min_num_of_points = 6; // (d+1)(d+2)/2, for d=2 + if(num_points < min_num_of_points) + { + CGAL_error_msg("Find curvature: Not enough points in the mesh."); + } + */ + + + + } template void init_remeshing(const FaceRange& face_range) @@ -72,6 +91,8 @@ public: tree_ptr_ = new Tree(input_triangles_.begin(), input_triangles_.end()); tree_ptr_->accelerate_distance_queries(); + //mean_k_ = compute_mean_curvature(); + } std::size_t remove_degenerate_faces() @@ -88,6 +109,8 @@ public: return nb_removed_faces; } + + void curvature_smoothing() { std::map barycenters; @@ -104,45 +127,54 @@ public: .geom_traits(traits_)); n_map[v] = vn; + // find incident halfedges Edges_around_map he_map; typename Edges_around_map::iterator it; BOOST_FOREACH(halfedge_descriptor hi, halfedges_around_source(v, mesh_)) - he_map[hi] = He_pair( next(hi, mesh_), prev(opposite(hi, mesh_), mesh_) ); + he_map[hi] = he_pair( next(hi, mesh_), prev(opposite(hi, mesh_), mesh_) ); - Vector weighted_move = CGAL::NULL_VECTOR; + + // calculate movement + Vector curvature_normal = CGAL::NULL_VECTOR; double sum_cot_weights = 0; for(it = he_map.begin(); it!= he_map.end(); ++it) { - halfedge_descriptor hi = it->first; //main_he + halfedge_descriptor hi = it->first; + he_pair incd_edges = it->second; // weight - double weight = cot_angles(hi, it->second); // incd_edges + double weight = cot_angles(hi, incd_edges); sum_cot_weights += weight; // displacement vector Point Xi = get(vpmap_, source(hi, mesh_)); Point Xj = get(vpmap_, target(hi, mesh_)); - Vector vec(Xj, Xi); + //Vector vec(Xj, Xi); + Vector vec(Xi, Xj); // add weight vec *= weight; + // sum vecs - weighted_move += vec; + curvature_normal += vec; } // divide with total weight - if there is actually weight if(sum_cot_weights != 0) - weighted_move /= sum_cot_weights; + curvature_normal /= sum_cot_weights; - Point weighted_barycenter = get(vpmap_, v) - weighted_move; + //Point weighted_barycenter = get(vpmap_, v) - curvature_normal; + Point weighted_barycenter = get(vpmap_, v) + curvature_normal; barycenters[v] = weighted_barycenter; } // not on border } // all vertices + typedef typename std::map::value_type VP; + /* // compute locations on tangent plane typedef typename std::map::value_type VP; std::map new_locations; @@ -155,10 +187,13 @@ public: new_locations[vp.first] = q + ( n * Vector(q, p) ) * n ; } - // update location - BOOST_FOREACH(const VP& vp, new_locations) - { + */ + // update location + //BOOST_FOREACH(const VP& vp, new_locations) // uncomment for tangent plane + BOOST_FOREACH(const VP& vp, barycenters) + { +#define CGAL_PMP_SMOOTHING_DEBUG #ifdef CGAL_PMP_SMOOTHING_DEBUG std::cout << "from: "<< get(vpmap_, vp.first); #endif @@ -194,46 +229,55 @@ public: //take one halfedge whose target is v BOOST_FOREACH(halfedge_descriptor ht, halfedges_around_target(v, mesh_)) { - // is it ok if it is degenerate? + // is it ok if a face is degenerate? A = area(faces_around_target(ht, mesh_), mesh_); continue; } + // find incident halfedges Edges_around_map he_map; typename Edges_around_map::iterator it; BOOST_FOREACH(halfedge_descriptor hi, halfedges_around_source(v, mesh_)) - he_map[hi] = He_pair( next(hi, mesh_), prev(opposite(hi, mesh_), mesh_) ); + he_map[hi] = he_pair( next(hi, mesh_), prev(opposite(hi, mesh_), mesh_) ); + // calculate movement Vector weighted_move = CGAL::NULL_VECTOR; for(it = he_map.begin(); it!= he_map.end(); ++it) { - halfedge_descriptor hi = it->first; //main_he + halfedge_descriptor hi = it->first; + he_pair incd_edges = it->second; // weight - double weight = cot_angles(hi, it->second); // incd_edges + double weight = cot_angles(hi, incd_edges); // displacement vector Point xi = get(vpmap_, source(hi, mesh_)); Point xj = get(vpmap_, target(hi, mesh_)); - Vector vec(xj, xi); + Vector vec(xi, xj); + + // add weight + vec *= weight; // comment out for just laplacian - // add weight. - vec *= weight; // sum vecs weighted_move += vec; - std::cout<<"hi"; } Vector curvature_normal = CGAL::NULL_VECTOR; if (A != 0) { curvature_normal = weighted_move / (4 * A); + //curvature_normal = weighted_move / he_map.size(); // just laplacian } + Point old_point = get(vpmap_, v); Point new_point = get(vpmap_, v) + curvature_normal; + +#ifdef CGAL_PMP_SMOOTHING_DEBUG + std::cout << "new location before projection: "<< new_point << std::endl; +#endif barycenters[v] = new_point; } // not on border @@ -241,7 +285,7 @@ public: } // all vertices - /* + // calculate location on tangential plane std::map new_locations; BOOST_FOREACH(const auto& vp, barycenters) { @@ -251,12 +295,11 @@ public: new_locations[vp.first] = q + ( n * Vector(q, p) ) * n ; } - */ // update location - BOOST_FOREACH(const auto& vp, barycenters) - //BOOST_FOREACH(const auto& vp, new_locations) + //BOOST_FOREACH(const auto& vp, barycenters) + BOOST_FOREACH(const auto& vp, new_locations) { #ifdef CGAL_PMP_SMOOTHING_DEBUG @@ -312,7 +355,7 @@ private: return sqlength(halfedge(e, mesh_)); } - double cot_angles(const halfedge_descriptor& main_he, const He_pair& incd_edges) + double cot_angles(const halfedge_descriptor& main_he, const he_pair& incd_edges) { vertex_descriptor vs = source(main_he, mesh_); vertex_descriptor vt = target(main_he, mesh_); @@ -325,10 +368,11 @@ private: Point p2 = get(vpmap_, v2); Point pt = get(vpmap_, vt); Point ps = get(vpmap_, vs); + + // avoid degenerate cases Vector edge1(pt, p1); Vector edge2(pt, p2); Vector vec_main_he(pt, ps); - double tolerance = 1e-3; if ( edge1.squared_length() < tolerance || edge2.squared_length() < tolerance || @@ -348,6 +392,61 @@ private: return a1 + a2; } + /* + double compute_mean_curvature() + { + // gather points around v + std::vector incident_points = gather_all_points(); + + Monge_form monge_form; + Monge_via_jet_fitting monge_fit; + + std::size_t d_fit = 2; // d_fit >= d_monge + std::size_t d_monge = 2; // need 2 principal coeeficients + std::size_t Nd = (d_fit + 1)*(d_fit + 1) / 2.0; + CGAL_assertion(incident_points.size() >= Nd); + + monge_form = monge_fit(incident_points.begin(), incident_points.end(), d_fit, d_monge); + const double k1 = monge_form.principal_curvatures(0); + const double k2 = monge_form.principal_curvatures(1); + + return (k1 + k2) / 2.0; + } + + + std::vector points_around_vertex(vertex_descriptor v) + { + std::vector incident_vertices; + for(halfedge_descriptor h : halfedges_around_target(v, mesh_)) + { + vertex_descriptor vs = source(h, mesh_); + incident_vertices.push_back(get(vpmap_, vs)); + } + + // temp assertion + std::vector incident_vertices2; + for(vertex_descriptor vi : vertices_around_target(v, mesh_)) + { + incident_vertices2.push_back(get(vpmap_, vi)); + } + CGAL_assertion(incident_vertices.size() == incident_vertices2.size()); + + return incident_vertices; + } + + std::vector gather_all_points() + { + //TODO SEE IF THERE IS SOMTEHTING alREADY FOR POINTS + std::vector points; + for(vertex_descriptor v : vertices(mesh_)) + { + points.push_back(get(vpmap_, v)); // todo: preallocate it and fill it by pointing + } + + return points; + } + */ + bool is_constrained(const edge_descriptor& e) { return get(ecmap_, e); @@ -381,6 +480,7 @@ private: Tree* tree_ptr_; GeomTraits traits_; double min_sq_edge_len_; + //double mean_k_; // from Weights.h CGAL::internal::Cotangent_value_Meyer_secure cot_calculator_; //CGAL::internal::Cotangent_value_clamped_2 cot_calculator_; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h index 716ced7e1c8..3aa450d0e0b 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h @@ -49,8 +49,8 @@ class Compatible_remesher typedef CGAL::AABB_tree Tree; // - typedef std::pair He_pair; - typedef std::map Edges_around_map; + typedef std::pair he_pair; + typedef std::map Edges_around_map; public: @@ -112,7 +112,7 @@ public: Edges_around_map he_map; typename Edges_around_map::iterator it; BOOST_FOREACH(halfedge_descriptor hi, halfedges_around_source(v, mesh_)) - he_map[hi] = He_pair( next(hi, mesh_), prev(opposite(hi, mesh_), mesh_) ); + he_map[hi] = he_pair( next(hi, mesh_), prev(opposite(hi, mesh_), mesh_) ); // calculate movement Vector move = CGAL::NULL_VECTOR; @@ -120,7 +120,7 @@ public: for(it = he_map.begin(); it != he_map.end(); ++it) { halfedge_descriptor main_he = it->first; - He_pair incident_pair = it->second; + he_pair incident_pair = it->second; Vector rotated_edge = rotate_edge(main_he, incident_pair); @@ -434,7 +434,7 @@ private: return move_flag; } - Vector rotate_edge(const halfedge_descriptor& main_he, const He_pair& incd_edges) + Vector rotate_edge(const halfedge_descriptor& main_he, const he_pair& incd_edges) { // get common vertex around which the edge is rotated Point pt = get(vpmap_, target(main_he, mesh_)); // CORRECT SYNATX vt @@ -502,7 +502,7 @@ private: return bisector; } - double get_angle(const He_pair& incd_edges, const Vector& vn) + double get_angle(const he_pair& incd_edges, const Vector& vn) { Point s = get(vpmap_, source(incd_edges.first, mesh_)); Point p1 = get(vpmap_, target(incd_edges.first, mesh_)); diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h index cbaf3e70818..432d4a25e62 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h @@ -2,8 +2,8 @@ #define CGAL_POLYGON_MESH_PROCESSING_SMOOTHING_H -#include -#include +#include +#include #include #include @@ -326,11 +326,11 @@ void curvature_flow(PolygonMesh& pmesh, const FaceRange& faces, const NamedParam std::cout << " * Iteration " << (i + 1) << " *" << std::endl; #endif - curvature_remesher.curvature_smoothing(); - //curvature_remesher.good_curvature_smoothing(); + curvature_remesher.curvature_smoothing(); // normalized version sec 5.5 + //curvature_remesher.good_curvature_smoothing(); // formula 14 //for now - //curvature_remesher.project_to_surface(); + curvature_remesher.project_to_surface(); } From f1c793eab41bc95c92af14606c61b47323825a68 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Mon, 14 Aug 2017 11:16:18 +0300 Subject: [PATCH 072/102] reference manual documentation --- .../NamedParameters.txt | 37 +++++ .../PackageDescription.txt | 3 + .../doc/Polygon_mesh_processing/examples.txt | 2 + .../internal/Smoothing/curvature_flow_impl.h | 2 +- .../internal/Smoothing/smoothing_impl.h | 10 +- .../CGAL/Polygon_mesh_processing/smoothing.h | 153 +++++++++++++++++- .../demo/Polyhedron/cgal_test_with_cmake | 1 + 7 files changed, 192 insertions(+), 16 deletions(-) diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/NamedParameters.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/NamedParameters.txt index 4f6e1b32545..cf95b12a4ef 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/NamedParameters.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/NamedParameters.txt @@ -319,6 +319,43 @@ Monte-Carlo methods. \b Default value is `0` \cgalNPEnd +\cgalNPBegin{do_project} \anchor PMP_do_project +Parameter used in `random_perturbation()` to set whether vertices should be re-projected +to the input surface after their geometric perturbation. +\n +\b Type : `bool` \n +\b Default value is `true` +\cgalNPEnd + +\cgalNPBegin{random_seed} \anchor PMP_random_seed +Parameter used in `random_perturbation()` to choose a seed to initialize +the random number generator `CGAL::Random()`. +If this parameter is not provided, +the random number generator is initialized with `CGAL::Random()`, +and perturbation is not deterministic +(i.e. not reproducible from one run to the other). +\n +\b Type : `unsigned int` \n +\b Default is that this variable is not set +\cgalNPEnd + +\cgalNPBegin{use_weights} \anchor PMP_use_weights +Parameter used in `angle_remeshing()` to set whether angles should carry weights while remeshing +so that small angles carry more weight. +\n +\b Type : `bool` \n +\b Default is `false` +\cgalNPEnd + +\cgalNPBegin{gradient_descent_precision} \anchor PMP_gradient_descent_precision +Parameter used in `area_remeshing()` to set precision to be met while the relative energy +between iterations of each triagle is minimized. Triangle energy is defined based on its area compared to the +average area of all triagnles adjacent to the vertex that is being moved. +\n +\b Type : `double` \n +\b Default is `0.001` +\cgalNPEnd + \cgalNPTableEnd */ diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt index 397ddc5a57f..59da5265c0d 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt @@ -86,6 +86,9 @@ and provides a list of the parameters that are used in this package. ## Meshing Functions ## - `CGAL::Polygon_mesh_processing::fair()` - `CGAL::Polygon_mesh_processing::refine()` +- `CGAL::Polygon_mesh_processing::angle_remeshing()` +- `CGAL::Polygon_mesh_processing::area_remeshing()` +- `CGAL::Polygon_mesh_processing::curvature_flow()` - `CGAL::Polygon_mesh_processing::triangulate_face()` - `CGAL::Polygon_mesh_processing::triangulate_faces()` - \link PMP_meshing_grp `CGAL::Polygon_mesh_processing::isotropic_remeshing()` \endlink diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/examples.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/examples.txt index f47ca95cac6..8d0ababbfdb 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/examples.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/examples.txt @@ -18,4 +18,6 @@ \example Polygon_mesh_processing/corefinement_difference_remeshed.cpp \example Polygon_mesh_processing/corefinement_mesh_union.cpp \example Polygon_mesh_processing/corefinement_consecutive_bool_op.cpp +\example Polygon_mesh_processing/smoothing_example.cpp +\example Polygon_mesh_processing/curvature_flow_example.cpp */ diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/curvature_flow_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/curvature_flow_impl.h index a5a36a985b2..82b7afd993f 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/curvature_flow_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/curvature_flow_impl.h @@ -49,7 +49,7 @@ class Curvature_flow typedef CGAL::AABB_traits AABB_Traits; typedef CGAL::AABB_tree Tree; - // + // typedef std::pair he_pair; typedef std::map Edges_around_map; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h index 3aa450d0e0b..cda9938ee1f 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h @@ -48,7 +48,7 @@ class Compatible_remesher typedef CGAL::AABB_traits AABB_Traits; typedef CGAL::AABB_tree Tree; - // + // typedef std::pair he_pair; typedef std::map Edges_around_map; @@ -186,13 +186,10 @@ public: #endif unsigned int moved_points = 0; - BOOST_FOREACH(vertex_descriptor v, vertices(mesh_)) { if(!is_border(v, mesh_) && !is_constrained(v)) { - - if (gradient_descent(v, precision)) { moved_points++; @@ -314,7 +311,6 @@ private: { double energy = 0; unsigned int number_of_edges = 0; - BOOST_FOREACH(halfedge_descriptor h, halfedges_around_source(v, mesh_)) { vertex_descriptor pi = source(next(h, mesh_), mesh_); @@ -356,7 +352,7 @@ private: // r = Σ(S-S_av)^2 // dr/dx = 2 Σ(S - S_av) dS/dx // area of triangle with respect to (x_a, y_a, z_a) = - // (1/2) [(v_z - v_y)x_a + (v_x - v_z)y_a + (y_y - v_x)z_a + constants] + // (1/2) [(v_z - v_y)x_a + (v_x - v_z)y_a + (v_y - v_x)z_a + constants] // vector v is (x_c - x_b, y_c - y_b, z_c - z_b) drdx += (S - S_av) * 0.5 * (vec.z() - vec.y()); drdy += (S - S_av) * 0.5 * (vec.x() - vec.z()); @@ -417,7 +413,7 @@ private: return false; } - relative_energy = to_double( (energy - energy_new) / energy ); + relative_energy = CGAL::to_double( (energy - energy_new) / energy ); // update x = x_new; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h index 432d4a25e62..8ca3aa764f5 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h @@ -13,17 +13,60 @@ #include #endif - - - - namespace CGAL { namespace Polygon_mesh_processing { - - - +/*! +* \ingroup PMP_meshing_grp +* @brief smoothes a triangulated region of a polygon mesh. +* This function imrpoves the angles between triangle edges by moving not +* constrained vertices so that each pair of adjacent angles becomes equal. +* Optionally, small angles may carry more weight than larger ones. Projection +* to the initial surface is performed as a last step. +* for better result. +* +* @tparam PolygonMesh model of `MutableFaceGraph`. +* The descriptor types `boost::graph_traits::%face_descriptor` +* and `boost::graph_traits::%halfedge_descriptor` must be +* models of `Hashable`. +* If `PolygonMesh` has an internal property map for `CGAL::face_index_t`, +* and no `face_index_map` is given +* as a named parameter, then the internal one should be initialized +* @tparam FaceRange range of `boost::graph_traits::%face_descriptor`, + model of `Range`. Its iterator type is `ForwardIterator`. +* @tparam NamedParameters a sequence of \ref namedparameters +* +* @param pmesh a polygon mesh with triangulated surface patches to be remeshed +* @param faces the range of triangular faces defining one or several surface patches to be remeshed +* @param np optional sequence of \ref namedparameters among the ones listed below +* +* \cgalNamedParamsBegin +* \cgalParamBegin{geom_traits} a geometric traits class instance, model of `Kernel`. +* Exact constructions kernels are not supported by this function. +* \cgalParamEnd +* \cgalParamBegin{vertex_point_map} the property map with the points associated +* to the vertices of `pmesh`. Instance of a class model of `ReadWritePropertyMap`. +* \cgalParamEnd +* \cgalParamBegin{face_index_map} a property map containing the index of each face of `pmesh`. +* \cgalParamEnd +* \cgalParamBegin{number_of_iterations} the number of iterations for the +* sequence of atomic operations performed (listed in the above description) +* \cgalParamEnd +* \cgalParamBegin{edge_is_constrained_map} a property map containing the +* constrained-or-not status of each edge of `pmesh`. A constrained edge can be split +* or collapsed, but not flipped, nor its endpoints moved by smoothing. +* Note that patch boundary edges (i.e. incident to only one face in the range) +* are always considered as constrained edges. +* \cgalParamEnd +* \cgalParamBegin{vertex_is_constrained_map} a property map containing the +* constrained-or-not status of each vertex of `pmesh`. A constrained vertex +* cannot be modified at all during remeshing. +* \cgalParamEnd +* \cgalParamBegin{use_weights} If `true`, small angles carry more weight than larger ones. +* \cgalParamEnd +* \cgalNamedParamsEnd +*/ template void angle_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const NamedParameters& np) { @@ -131,7 +174,58 @@ void angle_remeshing(PolygonMesh& pmesh) angle_remeshing(pmesh, faces(pmesh), parameters::all_default()); } - +/*! +* \ingroup PMP_meshing_grp +* @brief uses triangle area as a criterion for smoothing. +* This function imrpoves the overall distribution of points over a mesh area +* by trying to form triangles as uniform as possible. Should be used in combination with angle remeshing +* to avoid creation of long and skiny triangles. Vertices are moved towards equalizing adjacent triangle +* areas using gradient descent. +* +* @tparam PolygonMesh model of `MutableFaceGraph`. +* The descriptor types `boost::graph_traits::%face_descriptor` +* and `boost::graph_traits::%halfedge_descriptor` must be +* models of `Hashable`. +* If `PolygonMesh` has an internal property map for `CGAL::face_index_t`, +* and no `face_index_map` is given +* as a named parameter, then the internal one should be initialized +* @tparam FaceRange range of `boost::graph_traits::%face_descriptor`, + model of `Range`. Its iterator type is `ForwardIterator`. +* @tparam NamedParameters a sequence of \ref namedparameters +* +* @param pmesh a polygon mesh with triangulated surface patches to be remeshed +* @param faces the range of triangular faces defining one or several surface patches to be remeshed +* @param np optional sequence of \ref namedparameters among the ones listed below +* +* \cgalNamedParamsBegin +* \cgalParamBegin{geom_traits} a geometric traits class instance, model of `Kernel`. +* Exact constructions kernels are not supported by this function. +* \cgalParamEnd +* \cgalParamBegin{vertex_point_map} the property map with the points associated +* to the vertices of `pmesh`. Instance of a class model of `ReadWritePropertyMap`. +* \cgalParamEnd +* \cgalParamBegin{face_index_map} a property map containing the index of each face of `pmesh`. +* \cgalParamEnd +* \cgalParamBegin{number_of_iterations} the number of iterations for the +* sequence of atomic operations performed (listed in the above description) +* \cgalParamEnd +* \cgalParamBegin{edge_is_constrained_map} a property map containing the +* constrained-or-not status of each edge of `pmesh`. A constrained edge can be split +* or collapsed, but not flipped, nor its endpoints moved by smoothing. +* Note that patch boundary edges (i.e. incident to only one face in the range) +* are always considered as constrained edges. +* \cgalParamEnd +* \cgalParamBegin{vertex_is_constrained_map} a property map containing the +* constrained-or-not status of each vertex of `pmesh`. A constrained vertex +* cannot be modified at all during remeshing. +* \cgalParamEnd +* \cgalParamBegin{gradient_descent_precision} The precision which is met during gradient descent refers to +* the relative energy between iterations of each triangle element which is minimized +* while one of its vertices is being moved. Triangle energy is defined based on its area compared to +* the average area of all triangles adjacent to the vertex that is being moved. Defaults to 0.001. +* \cgalParamEnd +* \cgalNamedParamsEnd +*/ template void area_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const NamedParameters& np) { @@ -239,6 +333,49 @@ void area_remeshing(PolygonMesh& pmesh) area_remeshing(pmesh, faces(pmesh), parameters::all_default()); } +/*! +* \ingroup PMP_meshing_grp +* @brief todo +* +* @tparam PolygonMesh model of `MutableFaceGraph`. +* The descriptor types `boost::graph_traits::%face_descriptor` +* and `boost::graph_traits::%halfedge_descriptor` must be +* models of `Hashable`. +* If `PolygonMesh` has an internal property map for `CGAL::face_index_t`, +* and no `face_index_map` is given +* as a named parameter, then the internal one should be initialized +* @tparam FaceRange range of `boost::graph_traits::%face_descriptor`, + model of `Range`. Its iterator type is `ForwardIterator`. +* @tparam NamedParameters a sequence of \ref namedparameters +* +* @param pmesh a polygon mesh with triangulated surface patches to be remeshed +* @param faces the range of triangular faces defining one or several surface patches to be remeshed +* @param np optional sequence of \ref namedparameters among the ones listed below +* +* \cgalNamedParamsBegin +* \cgalParamBegin{geom_traits} a geometric traits class instance, model of `Kernel`. +* Exact constructions kernels are not supported by this function. +* \cgalParamEnd +* \cgalParamBegin{vertex_point_map} the property map with the points associated +* to the vertices of `pmesh`. Instance of a class model of `ReadWritePropertyMap`. +* \cgalParamEnd +* \cgalParamBegin{face_index_map} a property map containing the index of each face of `pmesh`. +* \cgalParamEnd +* \cgalParamBegin{number_of_iterations} the number of iterations for the +* sequence of atomic operations performed (listed in the above description) +* \cgalParamEnd +* \cgalParamBegin{edge_is_constrained_map} a property map containing the +* constrained-or-not status of each edge of `pmesh`. A constrained edge can be split +* or collapsed, but not flipped, nor its endpoints moved by smoothing. +* Note that patch boundary edges (i.e. incident to only one face in the range) +* are always considered as constrained edges. +* \cgalParamEnd +* \cgalParamBegin{vertex_is_constrained_map} a property map containing the +* constrained-or-not status of each vertex of `pmesh`. A constrained vertex +* cannot be modified at all during remeshing. +* \cgalParamEnd +* \cgalNamedParamsEnd +*/ template void curvature_flow(PolygonMesh& pmesh, const FaceRange& faces, const NamedParameters& np) { diff --git a/Polyhedron/demo/Polyhedron/cgal_test_with_cmake b/Polyhedron/demo/Polyhedron/cgal_test_with_cmake index 029b2061b4d..9e209f7661b 100755 --- a/Polyhedron/demo/Polyhedron/cgal_test_with_cmake +++ b/Polyhedron/demo/Polyhedron/cgal_test_with_cmake @@ -196,6 +196,7 @@ triangulate_facets_plugin \ trivial_plugin \ vtk_plugin \ xyz_plugin \ +smoothing_plugin \ all do if ${MAKE_CMD} -f Makefile help | grep "$target" > /dev/null; then From b9865e26101ca9acddd7ee9c9672e08514018754 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Mon, 14 Aug 2017 13:48:41 +0300 Subject: [PATCH 073/102] user manual doc --- Documentation/doc/biblio/cgal_manual.bib | 38 +++++++++++++++++++ .../Polygon_mesh_processing.txt | 28 +++++++++++++- 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/Documentation/doc/biblio/cgal_manual.bib b/Documentation/doc/biblio/cgal_manual.bib index 1752954416c..efe3efa83d8 100644 --- a/Documentation/doc/biblio/cgal_manual.bib +++ b/Documentation/doc/biblio/cgal_manual.bib @@ -2722,6 +2722,44 @@ pages = "207--221" number = {5 }, year = {2011}, } + +@mastersthesis{cloop:mthesis, + author = {Charles Loop}, + title = {Smooth Subdivision Surfaces Based on Triangles}, + school = {University of Utah}, + year = 1987, +} + +@article{doo1978behaviour, + title={Behaviour of recursive division surfaces near extraordinary points}, + author={Doo, Daniel and Sabin, Malcolm}, + journal={Computer-Aided Design}, + volume={10}, + number={6}, + pages={356--360}, + year={1978}, + publisher={Elsevier} +} + +@article{doo1978behaviour, + title={High quality compatible triangulations}, + author={V. Surazhsky and C. Gotsman}, + journal={Engineering with Computers}, + volume={20}, + number={2}, + pages={147--156}, + year={2004}, + publisher={springer} +} + +@inproceedings{ cgal:dmsb-ifamdcf-99 + ,author = {M. Desbrun and M. Meyer and P. Schr{\"o}der and A. H. Barr} + ,title = {Implicit Fairing of Arbitrary Meshes using + Diffusion and Curvature Flow} + ,booktitle = "Computer Graphics (Proc. SIGGRAPH '99)" + ,year = 1999 + ,pages = {317--324} +} % ---------------------------------------------------------------------------- % END OF BIBFILE % ---------------------------------------------------------------------------- diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt index 4dfac665d86..e9b291eeb12 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt @@ -37,7 +37,8 @@ BGL \ref namedparameters are used to deal with optional parameters. \subsection PMPOutline Outline The algorithms described in this manual are organized in sections: - \ref PMPMeshing : meshing algorithms, including triangulation of non-triangulated -meshes, refinement, optimization by fairing, and isotropic remeshing of triangulated surface meshes. +meshes, refinement, optimization by fairing, isotropic remeshing of triangulated surface meshes +and smoothing algorithms. - \ref Coref_section : methods to corefine triangle meshes and to compute boolean operations out of corefined closed triangle meshes. - \ref PMPHoleFilling : available hole filling algorithms, which can possibly be combined with refinement and fairing. @@ -120,6 +121,31 @@ Isotropic remeshing. (a) Triangulated input surface mesh. (d) Surface mesh with the selection uniformly remeshed. \cgalFigureEnd +\subsection Smoothing + +Smoothing of a triangulated mesh area can be achieved with three algorithms. `CGAL::Polygon_mesh_processing::angle_remeshing()` +moves vertices so that the angles of its incident edges equalize, `CGAL::Polygon_mesh_processing::area_remeshing()` +moves vertices so that the areas of adjacent triangles equalize and `CGAL::Polygon_mesh_processing::curvature_flow()` +takes into account the mean curvature to calculate a weighted barycenter towards which vertices move incrementally. +In all cases border vertices are considered constrained and do not move at any step of the algorithms. +Also, all three smoothing algorithms as they are implemented they do no insert new vertices nor remove existing ones. +Selected existing vertices move based only on geometric mesh criteria. + +Angle and area remeshing algorithms are based on Surazhsky and Gotsman \cgalCite{cgal:sg-hqct-04}. When mesh connectivity +is highly irregular, `angle remeshing` may be used with angle weights so that small angles carry +more weight and with almost the same computational cost per iteration convergence may be achieved faster. +`Area remeshing`, since it considers only triangle areas as a smoothing criterion, may result in long and skinny triangles, +especially for meshes with highly irregular connectivity. As such, area remeshing is guaranteed to improve the spatial +distribution of the vertices over the area that is being remeshed. It should be used in combination with angle remeshing +for optimal result. Ideally, an area remeshing step between two angle remeshing steps will offer better result. + +The curvature flow algorithm for smoothing is based on Desbrun et al \cgalCite{cgal:dmsb-ifamdcf-99}. Curvature flow +smoothes the surface by moving along the surface normal with a speed equal to the mean curvature of the area that is being +smoothed. This means that if the surface is flat around a vertex, this vertex will not move (zero curvature). +Curvature flow smoothing offers best results in closed surface meshes, where vertices slide according to the curvature +and smooth the shape while the overall volume is being kept constant. + +[[[---to include images---]]] \subsection MeshingExamples Meshing Examples From 7b80d7be8951839267a2fbe0b332e91dcf0ce04c Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Mon, 14 Aug 2017 22:14:29 +0300 Subject: [PATCH 074/102] unit tests for smoothing --- Documentation/doc/biblio/cgal_manual.bib | 4 +- .../test_compatible_remeshing.cpp | 93 ------------ .../test_smoothing.cpp | 143 ++++++++++++++++++ 3 files changed, 145 insertions(+), 95 deletions(-) delete mode 100644 Polygon_mesh_processing/test/Polygon_mesh_processing/test_compatible_remeshing.cpp create mode 100644 Polygon_mesh_processing/test/Polygon_mesh_processing/test_smoothing.cpp diff --git a/Documentation/doc/biblio/cgal_manual.bib b/Documentation/doc/biblio/cgal_manual.bib index efe3efa83d8..3923b2f663d 100644 --- a/Documentation/doc/biblio/cgal_manual.bib +++ b/Documentation/doc/biblio/cgal_manual.bib @@ -2741,7 +2741,7 @@ pages = "207--221" publisher={Elsevier} } -@article{doo1978behaviour, +@article{cgal:sg-hqct-04, title={High quality compatible triangulations}, author={V. Surazhsky and C. Gotsman}, journal={Engineering with Computers}, @@ -2752,7 +2752,7 @@ pages = "207--221" publisher={springer} } -@inproceedings{ cgal:dmsb-ifamdcf-99 +@inproceedings{cgal:dmsb-ifamdcf-99 ,author = {M. Desbrun and M. Meyer and P. Schr{\"o}der and A. H. Barr} ,title = {Implicit Fairing of Arbitrary Meshes using Diffusion and Curvature Flow} diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_compatible_remeshing.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_compatible_remeshing.cpp deleted file mode 100644 index 41fad33ec99..00000000000 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_compatible_remeshing.cpp +++ /dev/null @@ -1,93 +0,0 @@ -#include -#include -#include -#include - -#include -#include - -#include - - -#define CGAL_PMP_REMESHING_VERBOSE -//#define CGAL_TEST_COMP_REMESHING_OUTPUT - - -typedef CGAL::Exact_predicates_inexact_constructions_kernel K; -typedef CGAL::Surface_mesh Mesh; - - - -int main(int argc, char* argv[]){ - - - - std::string filename; - std::ifstream input; - Mesh mesh; -#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT - std::ofstream output; -#endif - - - - std::vector filenames = { - "data/polygon", - "data/polygon3D", - "data/blobby_3cc", - "data/elephant", - "data/degenerate_polygon", - "data/sneaky_degenerate_polygon", - "data/joint_refined", - "data/mannequin-devil", - "data/mech-holes-shark", - "data/non_manifold_vertex", - "data/overlapping_triangles", - "data/tetra1", - "data/tetra2", - "data/tetra3", - "data/tetra4", - "data/two_tris_collinear", - "data/U", - "data/elephant-invalid", - "data/mech-holes-shark-invalid" - }; - - - for(auto i=0; i!= filenames.size(); ++i) - { - filename = filenames[i]+".off"; - input.open(filename); - - -#ifdef CGAL_PMP_REMESHING_VERBOSE -std::cout<<"case: "<< filename << std::endl; -#endif - - if (!input || !(input >> mesh) || mesh.is_empty()) { - std::cerr << "Not a valid .off file." << std::endl; - return 1; - } - input.close(); - - - CGAL::Polygon_mesh_processing::compatible_remeshing( - mesh, - faces(mesh), - edges(mesh), - CGAL::Polygon_mesh_processing::parameters::number_of_iterations(3)); - - - -#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT - output.open(filenames[i]+"_smoothed"+".off"); - output << mesh; - output.close(); -#endif - - } - - - - return 0; -} diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_smoothing.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_smoothing.cpp new file mode 100644 index 00000000000..846fb9a1e9a --- /dev/null +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_smoothing.cpp @@ -0,0 +1,143 @@ +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; +typedef CGAL::Surface_mesh Mesh; + +void calc_angles(Mesh& mesh, double& min_a, double& max_a, double& avg_a) +{ + using namespace boost::accumulators; + accumulator_set< double, + features< tag::min, tag::max, tag::mean > > acc; + + typename boost::property_map::type + vpmap = get(CGAL::vertex_point, mesh); + + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + double rad_to_deg = 180. / CGAL_PI; + + BOOST_FOREACH(halfedge_descriptor h, halfedges(mesh)) + { + if(face(h, mesh) == boost::graph_traits::null_face()) + continue; + + typename K::Point_3 a = get(vpmap, source(h, mesh)); + typename K::Point_3 b = get(vpmap, target(h, mesh)); + typename K::Point_3 c = get(vpmap, target(next(h, mesh), mesh)); + typename K::Vector_3 ba(b, a); + typename K::Vector_3 bc(b, c); + + double cos_angle = (ba * bc) + / std::sqrt(ba.squared_length() * bc.squared_length()); + + acc(std::acos(cos_angle) * rad_to_deg); + } + + min_a = extract_result< tag::min >(acc); + max_a = extract_result< tag::max >(acc); + avg_a = extract_result< tag::mean >(acc); +} + +void calc_areas(Mesh& mesh, double& min_a, double& max_a, double& avg_a) +{ + using namespace boost::accumulators; + accumulator_set< double, + features< tag::min, tag::max, tag::mean > > acc; + + typename boost::property_map::type + vpmap = get(CGAL::vertex_point, mesh); + + typedef typename boost::graph_traits::face_descriptor face_descriptor; + + BOOST_FOREACH(face_descriptor f, faces(mesh)) + { + if(f == boost::graph_traits::null_face()) + continue; + + double area = CGAL::Polygon_mesh_processing::face_area(f, mesh); + acc(area); + } + + min_a = extract_result< tag::min >(acc); + max_a = extract_result< tag::max >(acc); + avg_a = extract_result< tag::mean >(acc); +} + +template +bool check_value_equal(T a, T b) +{ + if (abs(a-b) > 1e-3) + { + std::cerr << "Value not equal! "; + std::cerr << a << " is not " << b << std::endl; + return false; + } + return true; +} + + +int main(int argc, char* argv[]){ + + std::string filename; + std::ifstream input; + Mesh mesh; + double min_a, max_a, mean_a; + + filename = "data/curved_polygon.off"; + input.open(filename); + if (!input || !(input >> mesh) || mesh.is_empty()) { + std::cerr << "Not a valid .off file." << std::endl; + return 1; + } + input.close(); + + calc_angles(mesh, min_a, max_a, mean_a); + + CGAL::Polygon_mesh_processing::angle_remeshing(mesh); + calc_angles(mesh, min_a, max_a, mean_a); + + if(!check_value_equal(min_a, 24.980)) + { + return EXIT_FAILURE; + } + if(!check_value_equal(max_a, 108.723)) + { + return EXIT_FAILURE; + } + + input.open(filename); + input>>mesh; + input.close(); + + CGAL::Polygon_mesh_processing::area_remeshing(mesh); + calc_areas(mesh, min_a, max_a, mean_a); + + if(!check_value_equal(min_a, 0.476)) + { + return EXIT_FAILURE; + } + if(!check_value_equal(max_a, 0.567)) + { + return EXIT_FAILURE; + } + if(!check_value_equal(mean_a, 0.542)) + { + return EXIT_FAILURE; + } + + return 0; +} From d7c114719d4bc0b83c73b44314e3b5c9c12d2961 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Tue, 15 Aug 2017 15:41:48 +0300 Subject: [PATCH 075/102] unit tests for curvature flow --- .../test_curvature_flow.cpp | 141 +++++++++++------- 1 file changed, 84 insertions(+), 57 deletions(-) diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_curvature_flow.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_curvature_flow.cpp index 75cf52e3208..9c39d9359a9 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_curvature_flow.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_curvature_flow.cpp @@ -7,82 +7,109 @@ #include #include +#include +#include -#define CGAL_PMP_REMESHING_VERBOSE -#define CGAL_TEST_COMP_REMESHING_OUTPUT - +#if defined(CGAL_LINKED_WITH_TBB) +#define TAG CGAL::Parallel_tag +#else +#define TAG CGAL::Sequential_tag +#endif typedef CGAL::Exact_predicates_inexact_constructions_kernel K; typedef CGAL::Surface_mesh Mesh; +typedef typename Mesh::vertex_index vertex_index; +typedef typename Mesh::face_index face_index; +typedef typename Mesh::halfedge_index halfedge_index; +std::set select(Mesh mesh, double x0) +{ + std::set f_selection; + + typedef typename boost::property_map::type VertexPointMap; + VertexPointMap vpmap = get(CGAL::vertex_point, mesh); + + + for(face_index f : faces(mesh)) + { + halfedge_index he = halfedge(f, mesh); + for(vertex_index v : vertices_around_face(he, mesh)) + { + if(get(vpmap, v).x() < x0) + f_selection.insert(f); + continue; + } + } + + return f_selection; +} int main(int argc, char* argv[]){ - - - std::string filename; - std::ifstream input; Mesh mesh; -#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT - std::ofstream output; -#endif + Mesh originalMesh; + std::ifstream input; + /*std::ofstream output;*/ + // flat test + input.open("data/polygon.off"); + if (!input || !(input >> mesh) || mesh.is_empty()) { + std::cerr << "Not a valid .off file." << std::endl; + return 1; + } + input.close(); + originalMesh = mesh; + CGAL::Polygon_mesh_processing::curvature_flow(mesh); - std::vector filenames = { - "data/curved_polygon", - "data/polygon", - "data/polygon3D", - "data/blobby_3cc", - "data/elephant", - "data/degenerate_polygon", - "data/sneaky_degenerate_polygon", - "data/joint_refined", - "data/mannequin-devil", - "data/mech-holes-shark", - "data/non_manifold_vertex", - "data/overlapping_triangles", - "data/tetra1", - "data/tetra2", - "data/tetra3", - "data/tetra4", - "data/two_tris_collinear", - "data/U" - }; + double dist = CGAL::Polygon_mesh_processing::approximate_Hausdorff_distance + (originalMesh, mesh, CGAL::Polygon_mesh_processing::parameters::number_of_points_per_area_unit(1000)); - - for(auto i=0; i!= filenames.size(); ++i) + if(dist > 1e-3) { - filename = filenames[i]+".off"; - input.open(filename); - - -#ifdef CGAL_PMP_REMESHING_VERBOSE -std::cout<<"case: "<< filename << std::endl; -#endif - - if (!input || !(input >> mesh) || mesh.is_empty()) { - std::cerr << "Not a valid .off file." << std::endl; - return 1; - } - input.close(); - - - CGAL::Polygon_mesh_processing::curvature_flow(mesh); - - - -#ifdef CGAL_TEST_COMP_REMESHING_OUTPUT - output.open(filenames[i]+"_smoothed"+".off"); - output << mesh; - output.close(); -#endif - + return EXIT_FAILURE; } + // half-sphere test + input.open("data/sphere.off"); + if (!input || !(input >> mesh) || mesh.is_empty()) { + std::cerr << "Not a valid .off file." << std::endl; + return 1; + } + input.close(); + // select half sphere + std::cout<<"all faces: "< selected_faces = select(mesh, 0); + std::cout<<"selected faces: "<(originalMesh, mesh, CGAL::Polygon_mesh_processing::parameters::number_of_points_per_area_unit(1000)); + + if(dist > 1e-3) + { + return EXIT_FAILURE; + } + + /* + output.open("data/half-sphere_smoothed.off"); + output << mesh; + output.close(); + */ + return 0; } From 6fadb2ba3a3a680c369c5f1252cc7597537790e0 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Tue, 15 Aug 2017 15:43:54 +0300 Subject: [PATCH 076/102] cmakelists for smoothing tests --- .../test/Polygon_mesh_processing/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt index 47dff129943..805844cfc34 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt @@ -95,5 +95,5 @@ endif(EIGEN3_FOUND) create_single_source_cgal_program("test_does_bound_a_volume.cpp") create_single_source_cgal_program("test_pmp_clip.cpp") create_single_source_cgal_program("triangulate_hole_polyline_test.cpp") - create_single_source_cgal_program("test_compatible_remeshing.cpp") + create_single_source_cgal_program("test_smoothing.cpp") create_single_source_cgal_program("test_curvature_flow.cpp") From 6100a85442ceff7db65df2fad8a3eb6ce0c1b78e Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Tue, 15 Aug 2017 16:07:00 +0300 Subject: [PATCH 077/102] examples --- .../curvature_flow_example.cpp | 49 ++----------------- .../smoothing_example.cpp | 13 ++--- 2 files changed, 8 insertions(+), 54 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/curvature_flow_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/curvature_flow_example.cpp index 0b281e7e668..e0f06e5504a 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/curvature_flow_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/curvature_flow_example.cpp @@ -5,44 +5,16 @@ #include #include -#include typedef CGAL::Exact_predicates_inexact_constructions_kernel K; typedef CGAL::Surface_mesh Mesh; -typedef typename Mesh::vertex_index vertex_index; -typedef typename Mesh::face_index face_index; -typedef typename Mesh::halfedge_index halfedge_index; - -std::set select(Mesh mesh, double x0) -{ - std::set f_selection; - - typedef typename boost::property_map::type VertexPointMap; - VertexPointMap vpmap = get(CGAL::vertex_point, mesh); - - - for(face_index f : faces(mesh)) - { - halfedge_index he = halfedge(f, mesh); - for(vertex_index v : vertices_around_face(he, mesh)) - { - if(get(vpmap, v).x() < x0) - f_selection.insert(f); - continue; - } - } - - return f_selection; -} - - int main(int argc, char* argv[]){ - - const char* filename = "data/sphere.off"; + const char* filename = "data/mannequin-devil.off"; std::ifstream input(filename); + std::ofstream output; Mesh mesh; if (!input || !(input >> mesh) || mesh.is_empty()) { @@ -50,27 +22,12 @@ int main(int argc, char* argv[]){ return 1; } - std::cout<<"all faces: "< selected_faces = select(mesh, 0); - std::cout<<"selected faces: "< Mesh; - - int main(int argc, char* argv[]){ - - const char* filename = "data/polygon3D.off"; + const char* filename = "data/elephant.off"; std::ifstream input(filename); Mesh mesh; @@ -24,11 +21,11 @@ int main(int argc, char* argv[]){ return 1; } - CGAL::Polygon_mesh_processing::compatible_remeshing( - mesh, - CGAL::Polygon_mesh_processing::parameters::number_of_iterations(3)); + CGAL::Polygon_mesh_processing::angle_remeshing(mesh); + CGAL::Polygon_mesh_processing::area_remeshing(mesh); + CGAL::Polygon_mesh_processing::angle_remeshing(mesh); - std::ofstream output("data/polygon3D_smoothed.off"); + std::ofstream output("data/elephant_smoothed.off"); output << mesh; output.close(); From 43a20f8a214ee1529284a0e8b593e7b8b6c7c16c Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Tue, 15 Aug 2017 18:57:43 +0300 Subject: [PATCH 078/102] selected vertices --- .../smoothing_example.cpp | 5 ++-- .../internal/Smoothing/curvature_flow_impl.h | 21 +++++++++---- .../internal/Smoothing/smoothing_impl.h | 30 +++++++++++++------ 3 files changed, 39 insertions(+), 17 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/smoothing_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/smoothing_example.cpp index 357d6db9242..ff5bd0b7c7e 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/smoothing_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/smoothing_example.cpp @@ -12,7 +12,7 @@ typedef CGAL::Surface_mesh Mesh; int main(int argc, char* argv[]){ - const char* filename = "data/elephant.off"; + const char* filename = "data/eight.off"; std::ifstream input(filename); Mesh mesh; @@ -25,11 +25,10 @@ int main(int argc, char* argv[]){ CGAL::Polygon_mesh_processing::area_remeshing(mesh); CGAL::Polygon_mesh_processing::angle_remeshing(mesh); - std::ofstream output("data/elephant_smoothed.off"); + std::ofstream output("data/eight_smoothed.off"); output << mesh; output.close(); - return 0; } diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/curvature_flow_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/curvature_flow_impl.h index 82b7afd993f..9806cc66dd0 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/curvature_flow_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/curvature_flow_impl.h @@ -80,6 +80,7 @@ public: template void init_remeshing(const FaceRange& face_range) { + check_vertex_range(face_range); check_constraints(); @@ -109,14 +110,12 @@ public: return nb_removed_faces; } - - void curvature_smoothing() { std::map barycenters; std::map n_map; - BOOST_FOREACH(vertex_descriptor v, vertices(mesh_)) + BOOST_FOREACH(vertex_descriptor v, vrange) { if(!is_border(v, mesh_) && !is_constrained(v)) { @@ -169,7 +168,6 @@ public: barycenters[v] = weighted_barycenter; } // not on border - } // all vertices typedef typename std::map::value_type VP; @@ -471,6 +469,16 @@ private: } } + template + void check_vertex_range(const FaceRange& face_range) + { + BOOST_FOREACH(face_descriptor f, face_range) + { + BOOST_FOREACH(vertex_descriptor v, vertices_around_face(halfedge(f, mesh_), mesh_)) + vrange.push_back(v); + } + } + // data members PolygonMesh& mesh_; VertexPointMap& vpmap_; @@ -479,7 +487,10 @@ private: Triangle_list input_triangles_; Tree* tree_ptr_; GeomTraits traits_; - double min_sq_edge_len_; + std::vector vrange; + + // to fix + //double min_sq_edge_len_; //double mean_k_; // from Weights.h CGAL::internal::Cotangent_value_Meyer_secure cot_calculator_; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h index cda9938ee1f..920611bb58b 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -27,6 +28,10 @@ namespace Polygon_mesh_processing { namespace internal { +enum Vertex_status{ + SELECTED, + CONTRAINED +}; template @@ -37,6 +42,7 @@ class Compatible_remesher typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::face_descriptor face_descriptor; typedef typename boost::graph_traits::edge_descriptor edge_descriptor; + typedef typename boost::graph_traits::vertex_iterator vertex_iterator; typedef typename GeomTraits::Point_3 Point; typedef typename GeomTraits::Vector_3 Vector; @@ -66,17 +72,15 @@ public: template void init_remeshing(const FaceRange& face_range) { + check_vertex_range(face_range); + check_constraints(); BOOST_FOREACH(face_descriptor f, face_range) - { - // todo: avoid push back and reserve the space input_triangles_.push_back(triangle(f)); - } tree_ptr_ = new Tree(input_triangles_.begin(), input_triangles_.end()); tree_ptr_->accelerate_distance_queries(); - } std::size_t remove_degenerate_faces() @@ -97,7 +101,8 @@ public: { std::map barycenters; std::map n_map; - BOOST_FOREACH(vertex_descriptor v, vertices(mesh_)) + + BOOST_FOREACH(vertex_descriptor v, vrange) { if(!is_border(v, mesh_) && !is_constrained(v)) @@ -194,9 +199,7 @@ public: { moved_points++; } - } - } #ifdef CGAL_PMP_SMOOTHING_DEBUG @@ -581,10 +584,18 @@ private: } } + template + void check_vertex_range(const FaceRange& face_range) + { + BOOST_FOREACH(face_descriptor f, face_range) + { + BOOST_FOREACH(vertex_descriptor v, vertices_around_face(halfedge(f, mesh_), mesh_)) + vrange.push_back(v); + } + } - -private: + // data members PolygonMesh& mesh_; VertexPointMap& vpmap_; VertexConstraintMap vcmap_; @@ -592,6 +603,7 @@ private: Triangle_list input_triangles_; Tree* tree_ptr_; GeomTraits traits_; + std::vector vrange; #ifdef CGAL_PMP_SMOOTHING_DEBUG unsigned int count_non_convex_energy_; From f899dbdec351684b391a39ab148c894195424685 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Tue, 15 Aug 2017 21:08:36 +0300 Subject: [PATCH 079/102] calculate movement in separate function --- .../internal/Smoothing/smoothing_impl.h | 99 +++++++++++-------- 1 file changed, 59 insertions(+), 40 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h index 920611bb58b..1ad205a6fe5 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h @@ -28,11 +28,6 @@ namespace Polygon_mesh_processing { namespace internal { -enum Vertex_status{ - SELECTED, - CONTRAINED -}; - template class Compatible_remesher @@ -120,35 +115,7 @@ public: he_map[hi] = he_pair( next(hi, mesh_), prev(opposite(hi, mesh_), mesh_) ); // calculate movement - Vector move = CGAL::NULL_VECTOR; - double weights_sum = 0; - for(it = he_map.begin(); it != he_map.end(); ++it) - { - halfedge_descriptor main_he = it->first; - he_pair incident_pair = it->second; - - Vector rotated_edge = rotate_edge(main_he, incident_pair); - - // calculate angle - double angle = get_angle(incident_pair, vn); - if(angle < 1e-5) - continue; - - // small angles carry more weight - double weight = 1.0 / (angle*angle); - weights_sum += weight; - - if(use_weights) - move += weight * rotated_edge; - else - move += rotated_edge; - } - - // if at least 1 angle was summed - if(use_weights && weights_sum != 0) - move /= weights_sum; - else - move /= CGAL::to_double(he_map.size()); + Vector move = calc_move(he_map, use_weights); barycenters[v] = (get(vpmap_, v) + move) ; @@ -433,6 +400,48 @@ private: return move_flag; } + Vector calc_move(const Edges_around_map& he_map, bool use_weights) + { + Vector move = CGAL::NULL_VECTOR; + double weights_sum = 0; + typename Edges_around_map::const_iterator it; + for(it = he_map.begin(); it != he_map.end(); ++it) + { + halfedge_descriptor main_he = it->first; + he_pair incident_pair = it->second; + + Vector rotated_edge = rotate_edge(main_he, incident_pair); + + // avoid zero angles + Point pt = get(vpmap_, source(incident_pair.first, mesh_)); + Point p1 = get(vpmap_, target(incident_pair.first, mesh_)); + Point p2 = get(vpmap_, source(incident_pair.second, mesh_)); + CGAL_assertion(target(incident_pair.second, mesh_) == source(incident_pair.first, mesh_)); + Vector e1(pt, p1); + Vector e2(pt, p2); + double angle = get_angle(e1, e2); + if(angle < 1e-5) + continue; + + // small angles carry more weight + double weight = 1.0 / (angle*angle); + weights_sum += weight; + + if(use_weights) + move += weight * rotated_edge; + else + move += rotated_edge; + } + + // if at least 1 angle was summed + if(use_weights && weights_sum != 0) + move /= weights_sum; + else + move /= CGAL::to_double(he_map.size()); + + return move; + } + Vector rotate_edge(const halfedge_descriptor& main_he, const he_pair& incd_edges) { // get common vertex around which the edge is rotated @@ -501,15 +510,15 @@ private: return bisector; } + // to be removed double get_angle(const he_pair& incd_edges, const Vector& vn) { - Point s = get(vpmap_, source(incd_edges.first, mesh_)); + Point pt = get(vpmap_, source(incd_edges.first, mesh_)); Point p1 = get(vpmap_, target(incd_edges.first, mesh_)); Point p2 = get(vpmap_, source(incd_edges.second, mesh_)); CGAL_assertion(target(incd_edges.second, mesh_) == source(incd_edges.first, mesh_)); - - Vector v1(s, p1); - Vector v2(s, p2); + Vector v1(pt, p1); + Vector v2(pt, p2); Vector cp = CGAL::cross_product(v1, v2); double det = CGAL::scalar_product(vn, cp); @@ -521,6 +530,16 @@ private: return res; } + double get_angle(const Vector& e1, const Vector& e2) + { + double angle = atan2(e2.y(), e2.x()) - atan2(e1.y(), e1.x()); + + if (angle < 0) + return angle += 2 * CGAL_PI; + else + return angle; + } + Vector find_perpendicular(const Vector& input_vec, const Point& s, const Point& pv) { @@ -590,7 +609,7 @@ private: BOOST_FOREACH(face_descriptor f, face_range) { BOOST_FOREACH(vertex_descriptor v, vertices_around_face(halfedge(f, mesh_), mesh_)) - vrange.push_back(v); + vrange.insert(v); } } @@ -603,7 +622,7 @@ private: Triangle_list input_triangles_; Tree* tree_ptr_; GeomTraits traits_; - std::vector vrange; + std::set vrange; #ifdef CGAL_PMP_SMOOTHING_DEBUG unsigned int count_non_convex_energy_; From b4d3259f3f81f46b06d6021b1fbcc1cb45956b01 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Wed, 16 Aug 2017 14:30:42 +0300 Subject: [PATCH 080/102] angle remeshing only if it impoves min angle --- .../internal/Smoothing/smoothing_impl.h | 705 ++++++++++-------- 1 file changed, 403 insertions(+), 302 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h index 1ad205a6fe5..00f6616fdfa 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h @@ -21,7 +21,7 @@ #include #include - +//#define CGAL_PMP_SMOOTHING_DEBUG namespace CGAL { namespace Polygon_mesh_processing { @@ -66,7 +66,7 @@ public: template void init_remeshing(const FaceRange& face_range) - { + { check_vertex_range(face_range); check_constraints(); @@ -97,12 +97,14 @@ public: std::map barycenters; std::map n_map; - BOOST_FOREACH(vertex_descriptor v, vrange) - { +#ifdef CGAL_PMP_SMOOTHING_DEBUG + non_imporving_min_angle_ = 0; +#endif + BOOST_FOREACH(vertex_descriptor v, vrange_) + { if(!is_border(v, mesh_) && !is_constrained(v)) { - // compute normal to v Vector vn = compute_vertex_normal(v, mesh_, Polygon_mesh_processing::parameters::vertex_point_map(vpmap_) @@ -114,6 +116,9 @@ public: BOOST_FOREACH(halfedge_descriptor hi, halfedges_around_source(v, mesh_)) he_map[hi] = he_pair( next(hi, mesh_), prev(opposite(hi, mesh_), mesh_) ); + // measure initial angles + measure_angles(he_map); + // calculate movement Vector move = calc_move(he_map, use_weights); @@ -138,16 +143,23 @@ public: BOOST_FOREACH(const VP& vp, new_locations) { -#ifdef CGAL_PMP_SMOOTHING_DEBUG - std::cout << "from: "<< get(vpmap_, vp.first); -#endif - put(vpmap_, vp.first, vp.second); + // iff movement impoves all angles + if(!does_it_impove(vp.first, vp.second)) + { #ifdef CGAL_PMP_SMOOTHING_DEBUG - std::cout<<" moved at: "<< vp.second << std::endl; + non_imporving_min_angle_++; #endif + continue; + } + + put(vpmap_, vp.first, vp.second); } +#ifdef CGAL_PMP_SMOOTHING_DEBUG + std::cout<<"moved: "<< vrange_.size() - non_imporving_min_angle_<<" points based on angle."< calc_areas(const vertex_descriptor& v) + { + std::vector areas; + BOOST_FOREACH(halfedge_descriptor h, halfedges_around_source(v, mesh_)) + { + vertex_descriptor pi = source(next(h, mesh_), mesh_); + vertex_descriptor pi1 = target(next(h, mesh_), mesh_); + double S = element_area(v, pi, pi1); + areas.push_back(S); + } + return areas; + } + + + // angle bisecting functions + // ------------------------- + Vector calc_move(const Edges_around_map& he_map, bool use_weights) + { + Vector move = CGAL::NULL_VECTOR; + double weights_sum = 0; + typename Edges_around_map::const_iterator it; + for(it = he_map.begin(); it != he_map.end(); ++it) + { + halfedge_descriptor main_he = it->first; + he_pair incident_pair = it->second; + + // avoid zero angles + Point pt = get(vpmap_, source(incident_pair.first, mesh_)); + Point p1 = get(vpmap_, target(incident_pair.first, mesh_)); + Point p2 = get(vpmap_, source(incident_pair.second, mesh_)); + CGAL_assertion(target(incident_pair.second, mesh_) == source(incident_pair.first, mesh_)); + Vector e1(pt, p1); + Vector e2(pt, p2); + double angle = get_angle(e1, e2); + if(angle < 1e-5) + continue; + + // rotate + Vector rotated_edge = rotate_edge(main_he, incident_pair); + + // small angles carry more weight + double weight = 1.0 / (angle*angle); + weights_sum += weight; + + if(use_weights) + move += weight * rotated_edge; + else + move += rotated_edge; + } + + // if at least 1 angle was summed + if(use_weights && weights_sum != 0) + move /= weights_sum; + else + move /= CGAL::to_double(he_map.size()); + + return move; + } + + Vector rotate_edge(const halfedge_descriptor& main_he, const he_pair& incd_edges) + { + // get common vertex around which the edge is rotated + Point pt = get(vpmap_, target(main_he, mesh_)); + + // ps is the vertex that is being moved + Point ps = get(vpmap_, source(main_he, mesh_)); + + // get "equidistant" points - in fact they are at equal angles + Point equidistant_p1 = get(vpmap_, target(incd_edges.first, mesh_)); + Point equidistant_p2 = get(vpmap_, source(incd_edges.second, mesh_)); + CGAL_assertion(target(incd_edges.second, mesh_) == source(incd_edges.first, mesh_)); + + Vector edge1(pt, equidistant_p1); + Vector edge2(pt, equidistant_p2); + Vector vec_main_he(pt, ps); + + // check degenerate cases + double tolerance = 1e-3; + + if ( edge1.squared_length() < tolerance || + edge2.squared_length() < tolerance || + sqlength(main_he) < tolerance || + (edge1 - vec_main_he).squared_length() < tolerance || + (edge2 - vec_main_he).squared_length() < tolerance ) + { + return CGAL::NULL_VECTOR; + } + + CGAL_assertion(vec_main_he.squared_length() > tolerance); + + // find bisector + Vector bisector = CGAL::NULL_VECTOR; + internal::normalize(edge1, traits_); + internal::normalize(edge2, traits_); + bisector = edge1 + edge2; + + // special case in angle bisecting: If no edge is actually degenerate + // but edge1 and edge2 are almost parallel, then by adding them the bisector is + // almost zero. + if( bisector.squared_length() < tolerance ) + { + // angle is (almost) 180 degrees, take the perpendicular + // which is normal to edge and tangent to the surface + Vector normal_vec = find_perpendicular(edge1, pt, ps); + + CGAL_assertion(normal_vec != CGAL::NULL_VECTOR); + CGAL_assertion(CGAL::scalar_product(edge1, normal_vec) < tolerance); + + Segment b_segment(pt, pt + normal_vec); + Point b_segment_end = b_segment.target(); + + if(CGAL::angle(b_segment_end, pt, ps) == CGAL::OBTUSE) + { + b_segment = b_segment.opposite(); + } + + bisector = Vector(b_segment); + } + + correct_bisector(bisector, main_he); + + double target_length = CGAL::sqrt(sqlength(main_he)); + double bisector_length = CGAL::sqrt(bisector.squared_length()); + + CGAL_assertion( ( target_length - tolerance < bisector_length ) && + ( bisector_length < target_length + tolerance ) ); + + return bisector; + } + + void correct_bisector(Vector& bisector_vec, const halfedge_descriptor& main_he) + { + // get common vertex around which the edge is rotated + Point pt = get(vpmap_, target(main_he, mesh_)); + + // create a segment to be able to translate + Segment bisector(pt, pt + bisector_vec); + + // scale + double scale_factor = CGAL::sqrt( sqlength(main_he) / bisector.squared_length() ); + typename GeomTraits::Aff_transformation_3 t_scale(CGAL::SCALING, scale_factor); + bisector = bisector.transform(t_scale); + + // translate + Vector vec(bisector.source(), pt); + typename GeomTraits::Aff_transformation_3 t_translate(CGAL::TRANSLATION, vec); + bisector = bisector.transform(t_translate); + + // take the opposite so that their sum is the overall displacement + bisector_vec = -Vector(bisector); + } + + Vector find_perpendicular(const Vector& input_vec, const Point& s, const Point& pv) + { + Vector s_pv(s, pv); + Vector aux_normal = CGAL::cross_product(input_vec, s_pv); + return CGAL::cross_product(aux_normal, input_vec); + } + + + // to be removed + double get_angle(const he_pair& incd_edges, const Vector& vn) + { + Point pt = get(vpmap_, source(incd_edges.first, mesh_)); + Point p1 = get(vpmap_, target(incd_edges.first, mesh_)); + Point p2 = get(vpmap_, source(incd_edges.second, mesh_)); + CGAL_assertion(target(incd_edges.second, mesh_) == source(incd_edges.first, mesh_)); + Vector v1(pt, p1); + Vector v2(pt, p2); + + Vector cp = CGAL::cross_product(v1, v2); + double det = CGAL::scalar_product(vn, cp); + double dot = CGAL::scalar_product(v1, v2); + + // transform to range [0, 2pi] + double res = atan2(-det, -dot) + CGAL_PI; + + return res; + } + + + // angle measurement & evaluation + // ------------------------------ + void measure_angles(const Edges_around_map& he_map) + { + min_angle_ = 2 * CGAL_PI; + typename Edges_around_map::const_iterator it; + for(it = he_map.begin(); it != he_map.end(); ++it) + { + halfedge_descriptor main_he = it->first; + he_pair incident_pair = it->second; + + calc_angles(main_he, incident_pair); + } + } + + void calc_angles(const halfedge_descriptor& main_he, const he_pair& incd_edges) + { + // get common vertex around which the edge is rotated + Point pt = get(vpmap_, target(main_he, mesh_)); + // ps is the vertex that is being moved + Point ps = get(vpmap_, source(main_he, mesh_)); + // get "equidistant" points - in fact they are at equal angles + Point equidistant_p1 = get(vpmap_, target(incd_edges.first, mesh_)); + Point equidistant_p2 = get(vpmap_, source(incd_edges.second, mesh_)); + CGAL_assertion(target(incd_edges.second, mesh_) == source(incd_edges.first, mesh_)); + + Vector edge1(pt, equidistant_p1); + Vector edge2(pt, equidistant_p2); + Vector vec_main_he(pt, ps); + + // angles in [0, 2pi] + double a1 = get_angle(edge1, vec_main_he); + double a2 = get_angle(edge2, vec_main_he); + + min_angle_ = std::min(min_angle_, std::min(a1, a2)); + } + + bool does_it_impove(const vertex_descriptor& v, const Point& new_location) + { + Edges_around_map he_map; + typename Edges_around_map::iterator it; + BOOST_FOREACH(halfedge_descriptor hi, halfedges_around_source(v, mesh_)) + he_map[hi] = he_pair( next(hi, mesh_), prev(opposite(hi, mesh_), mesh_) ); + + return evaluate_angles(he_map, new_location); + } + + bool evaluate_angles(const Edges_around_map& he_map, const Point& new_location) + { + typename Edges_around_map::const_iterator it; + for(it = he_map.begin(); it != he_map.end(); ++it) + { + halfedge_descriptor main_he = it->first; + he_pair incd_edges = it->second; + + // get common vertex around which the edge is rotated + Point pt = get(vpmap_, target(main_he, mesh_)); + // ps is the vertex that is being moved + Point new_point = new_location; + // get "equidistant" points + Point equidistant_p1 = get(vpmap_, target(incd_edges.first, mesh_)); + Point equidistant_p2 = get(vpmap_, source(incd_edges.second, mesh_)); + CGAL_assertion(target(incd_edges.second, mesh_) == source(incd_edges.first, mesh_)); + + Vector edge1(pt, equidistant_p1); + Vector edge2(pt, equidistant_p2); + Vector vec_main_he(pt, new_point); + + double a1 = get_angle(edge1, vec_main_he); + double a2 = get_angle(edge2, vec_main_he); + + if(a1 < min_angle_ || a2 < min_angle_) + return false; + } + + + + return true; + } + + double get_angle(const Vector& e1, const Vector& e2) + { + //double rad_to_deg = 180. / CGAL_PI; + double cos_angle = (e1 * e2) + / std::sqrt(e1.squared_length() * e2.squared_length()); + + return std::acos(cos_angle); //* rad_to_deg; + } + + + // gradient descent + // ---------------- + bool gradient_descent(const vertex_descriptor& v, const double& precision) + { + bool move_flag; + double x, y, z, x_new, y_new, z_new, drdx, drdy, drdz; + x = get(vpmap_, v).x(); + y = get(vpmap_, v).y(); + z = get(vpmap_, v).z(); + + double S_av = compute_average_area_around(v); + double energy = measure_energy(v, S_av); + + // if the adjacent areas are absolutely equal + if(energy == 0) + return false; + + double energy_new = 0; + double relative_energy = precision + 1; + unsigned int t = 1; + double eta0 = 0.01; + //double power_t = 0.25; + double t0 = 0.001; + double eta = eta0 / (1 + t0*t); + + while(relative_energy > precision) + { + drdx=0, drdy=0, drdz=0; + compute_derivatives(drdx, drdy, drdz, v, S_av); + + x_new = x - eta * drdx; + y_new = y - eta * drdy; + z_new = z - eta * drdz; + + Point moved(x_new, y_new, z_new); + energy_new = measure_energy(v, S_av, moved); + + if(energy_new < energy) + { + put(vpmap_, v, moved); + move_flag = true; + } + else + { + return false; + } + + relative_energy = CGAL::to_double( (energy - energy_new) / energy ); + + // update + x = x_new; + y = y_new; + z = z_new; + energy = energy_new; + t++; + + //eta = eta0 / pow(t, power_t); + eta = eta0 / (1 + t0 * t); + } + + return move_flag; + } + + void compute_derivatives(double& drdx, double& drdy, double& drdz, const vertex_descriptor& v, const double& S_av) + { + BOOST_FOREACH(halfedge_descriptor h, halfedges_around_source(v, mesh_)) + { + vertex_descriptor pi = source(next(h, mesh_), mesh_); + vertex_descriptor pi1 = target(next(h, mesh_), mesh_); + double S = element_area(v, pi, pi1); + + Vector vec(get(vpmap_, pi), get(vpmap_, pi1)); + + // minimize r: + // r = Σ(S-S_av)^2 + // dr/dx = 2 Σ(S - S_av) dS/dx + // area of triangle with respect to (x_a, y_a, z_a) = + // (1/2) [(v_z - v_y)x_a + (v_x - v_z)y_a + (v_y - v_x)z_a + constants] + // vector v is (x_c - x_b, y_c - y_b, z_c - z_b) + drdx += (S - S_av) * 0.5 * (vec.z() - vec.y()); + drdy += (S - S_av) * 0.5 * (vec.x() - vec.z()); + drdz += (S - S_av) * 0.5 * (vec.y() - vec.x()); + } + + drdx *= 2; + drdy *= 2; + drdz *= 2; + } + double element_area(const vertex_descriptor& p1, const vertex_descriptor& p2, const vertex_descriptor& p3) const @@ -294,291 +673,9 @@ private: return to_double( energy / (2 * number_of_edges) ); } - std::vector calc_areas(const vertex_descriptor& v) - { - std::vector areas; - BOOST_FOREACH(halfedge_descriptor h, halfedges_around_source(v, mesh_)) - { - vertex_descriptor pi = source(next(h, mesh_), mesh_); - vertex_descriptor pi1 = target(next(h, mesh_), mesh_); - double S = element_area(v, pi, pi1); - areas.push_back(S); - } - - return areas; - } - - void compute_derivatives(double& drdx, double& drdy, double& drdz, const vertex_descriptor& v, const double& S_av) - { - BOOST_FOREACH(halfedge_descriptor h, halfedges_around_source(v, mesh_)) - { - vertex_descriptor pi = source(next(h, mesh_), mesh_); - vertex_descriptor pi1 = target(next(h, mesh_), mesh_); - double S = element_area(v, pi, pi1); - - Vector vec(get(vpmap_, pi), get(vpmap_, pi1)); - - // minimize r: - // r = Σ(S-S_av)^2 - // dr/dx = 2 Σ(S - S_av) dS/dx - // area of triangle with respect to (x_a, y_a, z_a) = - // (1/2) [(v_z - v_y)x_a + (v_x - v_z)y_a + (v_y - v_x)z_a + constants] - // vector v is (x_c - x_b, y_c - y_b, z_c - z_b) - drdx += (S - S_av) * 0.5 * (vec.z() - vec.y()); - drdy += (S - S_av) * 0.5 * (vec.x() - vec.z()); - drdz += (S - S_av) * 0.5 * (vec.y() - vec.x()); - } - - drdx *= 2; - drdy *= 2; - drdz *= 2; - } - - bool gradient_descent(const vertex_descriptor& v, const double& precision) - { - bool move_flag; - double x, y, z, x_new, y_new, z_new, drdx, drdy, drdz; - x = get(vpmap_, v).x(); - y = get(vpmap_, v).y(); - z = get(vpmap_, v).z(); - - double S_av = compute_average_area_around(v); - double energy = measure_energy(v, S_av); - - // if the adjacent areas are absolutely equal - if(energy == 0) - return false; - - double energy_new = 0; - double relative_energy = precision + 1; - unsigned int t = 1; - double eta0 = 0.01; - //double power_t = 0.25; - double t0 = 0.001; - double eta = eta0 / (1 + t0*t); - - while(relative_energy > precision) - { - drdx=0, drdy=0, drdz=0; - compute_derivatives(drdx, drdy, drdz, v, S_av); - - x_new = x - eta * drdx; - y_new = y - eta * drdy; - z_new = z - eta * drdz; - - Point moved(x_new, y_new, z_new); - energy_new = measure_energy(v, S_av, moved); - - if(energy_new < energy) - { - put(vpmap_, v, moved); - move_flag = true; - } - else - { - -#ifdef CGAL_PMP_SMOOTHING_DEBUG - count_non_convex_energy_++; -#endif - return false; - } - - relative_energy = CGAL::to_double( (energy - energy_new) / energy ); - - // update - x = x_new; - y = y_new; - z = z_new; - energy = energy_new; - t++; - - //eta = eta0 / pow(t, power_t); - eta = eta0 / (1 + t0 * t); - - } - - return move_flag; - } - - Vector calc_move(const Edges_around_map& he_map, bool use_weights) - { - Vector move = CGAL::NULL_VECTOR; - double weights_sum = 0; - typename Edges_around_map::const_iterator it; - for(it = he_map.begin(); it != he_map.end(); ++it) - { - halfedge_descriptor main_he = it->first; - he_pair incident_pair = it->second; - - Vector rotated_edge = rotate_edge(main_he, incident_pair); - - // avoid zero angles - Point pt = get(vpmap_, source(incident_pair.first, mesh_)); - Point p1 = get(vpmap_, target(incident_pair.first, mesh_)); - Point p2 = get(vpmap_, source(incident_pair.second, mesh_)); - CGAL_assertion(target(incident_pair.second, mesh_) == source(incident_pair.first, mesh_)); - Vector e1(pt, p1); - Vector e2(pt, p2); - double angle = get_angle(e1, e2); - if(angle < 1e-5) - continue; - - // small angles carry more weight - double weight = 1.0 / (angle*angle); - weights_sum += weight; - - if(use_weights) - move += weight * rotated_edge; - else - move += rotated_edge; - } - - // if at least 1 angle was summed - if(use_weights && weights_sum != 0) - move /= weights_sum; - else - move /= CGAL::to_double(he_map.size()); - - return move; - } - - Vector rotate_edge(const halfedge_descriptor& main_he, const he_pair& incd_edges) - { - // get common vertex around which the edge is rotated - Point pt = get(vpmap_, target(main_he, mesh_)); // CORRECT SYNATX vt - - // ps is the vertex that is being moved - Point ps = get(vpmap_, source(main_he, mesh_)); - - // get "equidistant" points - in fact they are at equal angles - Point equidistant_p1 = get(vpmap_, target(incd_edges.first, mesh_)); - Point equidistant_p2 = get(vpmap_, source(incd_edges.second, mesh_)); - CGAL_assertion(target(incd_edges.second, mesh_) == source(incd_edges.first, mesh_)); - - Vector edge1(pt, equidistant_p1); - Vector edge2(pt, equidistant_p2); - Vector vec_main_he(pt, ps); - - // check degenerate cases - double tolerance = 1e-3; - - if ( edge1.squared_length() < tolerance || - edge2.squared_length() < tolerance || - sqlength(main_he) < tolerance || - (edge1 - vec_main_he).squared_length() < tolerance || - (edge2 - vec_main_he).squared_length() < tolerance ) - { - return CGAL::NULL_VECTOR; - } - - CGAL_assertion(vec_main_he.squared_length() > tolerance); - - // find bisector - Vector bisector = CGAL::NULL_VECTOR; - internal::normalize(edge1, traits_); - internal::normalize(edge2, traits_); - bisector = edge1 + edge2; - - // under about 0.5 degrees deviation consider it flat - if( bisector.squared_length() < 0.001 ) // -> length = 0.01 -> sin(theta) = 0.01 -> theta = 0.57 degrees - { - // angle is (almost) 180 degrees, take the perpendicular - Vector normal_vec = find_perpendicular(edge1, pt, ps); // normal to edge and found on (vec_main_he)'s plane - - CGAL_assertion(normal_vec != CGAL::NULL_VECTOR); - CGAL_assertion(CGAL::scalar_product(edge1, normal_vec) < tolerance); - - Segment b_segment(pt, pt + normal_vec); - Point b_segment_end = b_segment.target(); - - if(CGAL::angle(b_segment_end, pt, ps) == CGAL::OBTUSE) - { - b_segment = b_segment.opposite(); - } - - bisector = Vector(b_segment); - } - - correct_bisector(bisector, main_he); - - double target_length = CGAL::sqrt(sqlength(main_he)); - double bisector_length = CGAL::sqrt(bisector.squared_length()); - - CGAL_assertion( ( target_length - tolerance < bisector_length ) && - ( bisector_length < target_length + tolerance ) ); - - return bisector; - } - - // to be removed - double get_angle(const he_pair& incd_edges, const Vector& vn) - { - Point pt = get(vpmap_, source(incd_edges.first, mesh_)); - Point p1 = get(vpmap_, target(incd_edges.first, mesh_)); - Point p2 = get(vpmap_, source(incd_edges.second, mesh_)); - CGAL_assertion(target(incd_edges.second, mesh_) == source(incd_edges.first, mesh_)); - Vector v1(pt, p1); - Vector v2(pt, p2); - - Vector cp = CGAL::cross_product(v1, v2); - double det = CGAL::scalar_product(vn, cp); - double dot = CGAL::scalar_product(v1, v2); - - // transform to range [0, 2pi] - double res = atan2(-det, -dot) + CGAL_PI; - - return res; - } - - double get_angle(const Vector& e1, const Vector& e2) - { - double angle = atan2(e2.y(), e2.x()) - atan2(e1.y(), e1.x()); - - if (angle < 0) - return angle += 2 * CGAL_PI; - else - return angle; - } - - - Vector find_perpendicular(const Vector& input_vec, const Point& s, const Point& pv) - { - Vector s_pv(s, pv); - Vector aux_normal = CGAL::cross_product(input_vec, s_pv); - - return CGAL::cross_product(aux_normal, input_vec); - } - - Vector max_vector(const Vector& vec1, const Vector& vec2) - { - if (vec1.squared_length() > vec2.squared_length()) - return vec1; - else - return vec2; - } - - void correct_bisector(Vector& bisector_vec, const halfedge_descriptor& main_he) - { - // get common vertex around which the edge is rotated - Point pt = get(vpmap_, target(main_he, mesh_)); - - // create a segment to be able to translate - Segment bisector(pt, pt + bisector_vec); - - // scale - double scale_factor = CGAL::sqrt( sqlength(main_he) / bisector.squared_length() ); - typename GeomTraits::Aff_transformation_3 t_scale(CGAL::SCALING, scale_factor); - bisector = bisector.transform(t_scale); - - // translate - Vector vec(bisector.source(), pt); - typename GeomTraits::Aff_transformation_3 t_translate(CGAL::TRANSLATION, vec); - bisector = bisector.transform(t_translate); - - // take the opposite so that their sum is the overall displacement - bisector_vec = -Vector(bisector); - } + // functions for constrained vertices + // ----------------------------------- bool is_constrained(const edge_descriptor& e) { return get(ecmap_, e); @@ -609,12 +706,14 @@ private: BOOST_FOREACH(face_descriptor f, face_range) { BOOST_FOREACH(vertex_descriptor v, vertices_around_face(halfedge(f, mesh_), mesh_)) - vrange.insert(v); + vrange_.insert(v); } } // data members + // ------------ +private: PolygonMesh& mesh_; VertexPointMap& vpmap_; VertexConstraintMap vcmap_; @@ -622,10 +721,12 @@ private: Triangle_list input_triangles_; Tree* tree_ptr_; GeomTraits traits_; - std::set vrange; + std::set vrange_; + double min_angle_; #ifdef CGAL_PMP_SMOOTHING_DEBUG unsigned int count_non_convex_energy_; + unsigned int non_imporving_min_angle_; #endif From d3081ce2ffedc4e7778fa3885cd73688428f166b Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Wed, 16 Aug 2017 17:08:52 +0300 Subject: [PATCH 081/102] counting not moved points for debug --- .../internal/Smoothing/smoothing_impl.h | 91 +++---------------- 1 file changed, 13 insertions(+), 78 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h index 00f6616fdfa..5df668a00cd 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h @@ -21,7 +21,7 @@ #include #include -//#define CGAL_PMP_SMOOTHING_DEBUG +#define CGAL_PMP_SMOOTHING_DEBUG namespace CGAL { namespace Polygon_mesh_processing { @@ -97,9 +97,6 @@ public: std::map barycenters; std::map n_map; -#ifdef CGAL_PMP_SMOOTHING_DEBUG - non_imporving_min_angle_ = 0; -#endif BOOST_FOREACH(vertex_descriptor v, vrange_) { @@ -140,54 +137,38 @@ public: } // update location + std::size_t moved_points = 0; BOOST_FOREACH(const VP& vp, new_locations) { - // iff movement impoves all angles - if(!does_it_impove(vp.first, vp.second)) + if(does_it_impove(vp.first, vp.second)) { - -#ifdef CGAL_PMP_SMOOTHING_DEBUG - non_imporving_min_angle_++; -#endif - continue; + moved_points++; + put(vpmap_, vp.first, vp.second); } - - put(vpmap_, vp.first, vp.second); } #ifdef CGAL_PMP_SMOOTHING_DEBUG - std::cout<<"moved: "<< vrange_.size() - non_imporving_min_angle_<<" points based on angle."< calc_areas(const vertex_descriptor& v) - { - std::vector areas; - BOOST_FOREACH(halfedge_descriptor h, halfedges_around_source(v, mesh_)) - { - vertex_descriptor pi = source(next(h, mesh_), mesh_); - vertex_descriptor pi1 = target(next(h, mesh_), mesh_); - double S = element_area(v, pi, pi1); - areas.push_back(S); - } - return areas; - } - - // angle bisecting functions // ------------------------- Vector calc_move(const Edges_around_map& he_map, bool use_weights) @@ -397,27 +363,6 @@ private: } - // to be removed - double get_angle(const he_pair& incd_edges, const Vector& vn) - { - Point pt = get(vpmap_, source(incd_edges.first, mesh_)); - Point p1 = get(vpmap_, target(incd_edges.first, mesh_)); - Point p2 = get(vpmap_, source(incd_edges.second, mesh_)); - CGAL_assertion(target(incd_edges.second, mesh_) == source(incd_edges.first, mesh_)); - Vector v1(pt, p1); - Vector v2(pt, p2); - - Vector cp = CGAL::cross_product(v1, v2); - double det = CGAL::scalar_product(vn, cp); - double dot = CGAL::scalar_product(v1, v2); - - // transform to range [0, 2pi] - double res = atan2(-det, -dot) + CGAL_PI; - - return res; - } - - // angle measurement & evaluation // ------------------------------ void measure_angles(const Edges_around_map& he_map) @@ -493,8 +438,6 @@ private: return false; } - - return true; } @@ -551,9 +494,7 @@ private: move_flag = true; } else - { return false; - } relative_energy = CGAL::to_double( (energy - energy_new) / energy ); @@ -711,9 +652,9 @@ private: } +private: // data members // ------------ -private: PolygonMesh& mesh_; VertexPointMap& vpmap_; VertexConstraintMap vcmap_; @@ -724,12 +665,6 @@ private: std::set vrange_; double min_angle_; -#ifdef CGAL_PMP_SMOOTHING_DEBUG - unsigned int count_non_convex_energy_; - unsigned int non_imporving_min_angle_; -#endif - - }; From b4c6f78f97d5b6017b2b002ee81e570d07c766c7 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Wed, 16 Aug 2017 18:18:09 +0300 Subject: [PATCH 082/102] init after removing degenerate faces --- .../internal/Smoothing/smoothing_impl.h | 4 ++- .../CGAL/Polygon_mesh_processing/smoothing.h | 36 +++++++++++++------ 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h index 5df668a00cd..8195baf0683 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h @@ -21,7 +21,7 @@ #include #include -#define CGAL_PMP_SMOOTHING_DEBUG + namespace CGAL { namespace Polygon_mesh_processing { @@ -190,6 +190,7 @@ public: private: // helper functions + // ---------------- Triangle triangle(face_descriptor f) const { halfedge_descriptor h = halfedge(f, mesh_); @@ -653,6 +654,7 @@ private: private: + // data members // ------------ PolygonMesh& mesh_; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h index 8ca3aa764f5..91bbca29cf4 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h @@ -123,7 +123,6 @@ void angle_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const NamedPara internal::Compatible_remesher remesher(pmesh, vpmap, vcmap, ecmap); - remesher.init_remeshing(faces); #ifdef CGAL_PMP_REMESHING_VERBOSE t.stop(); @@ -131,9 +130,17 @@ void angle_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const NamedPara std::cout << "Removing degenerate faces..." << std::endl; t.reset(); t.start(); #endif - remesher.remove_degenerate_faces(); +#ifdef CGAL_PMP_REMESHING_VERBOSE + t.stop(); + std::cout << " done ("<< t.time() <<" sec)." << std::endl; + std::cout << "Initializing..." << std::endl; + t.reset(); t.start(); +#endif + remesher.init_remeshing(faces); + + #ifdef CGAL_PMP_REMESHING_VERBOSE t.stop(); std::cout << " done ("<< t.time() <<" sec)." << std::endl; @@ -282,17 +289,22 @@ void area_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const NamedParam internal::Compatible_remesher remesher(pmesh, vpmap, vcmap, ecmap); - remesher.init_remeshing(faces); - #ifdef CGAL_PMP_REMESHING_VERBOSE t.stop(); std::cout << " done ("<< t.time() <<" sec)." << std::endl; std::cout << "Removing degenerate faces..." << std::endl; t.reset(); t.start(); #endif - remesher.remove_degenerate_faces(); +#ifdef CGAL_PMP_REMESHING_VERBOSE + t.stop(); + std::cout << " done ("<< t.time() <<" sec)." << std::endl; + std::cout << "Initializing..." << std::endl; + t.reset(); t.start(); +#endif + remesher.init_remeshing(faces); + #ifdef CGAL_PMP_REMESHING_VERBOSE t.stop(); std::cout << " done ("<< t.time() <<" sec)." << std::endl; @@ -312,7 +324,6 @@ void area_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const NamedParam remesher.project_to_surface(); } - #ifdef CGAL_PMP_REMESHING_VERBOSE t.stop(); std::cout << "Remeshing done in "; @@ -437,16 +448,21 @@ void curvature_flow(PolygonMesh& pmesh, const FaceRange& faces, const NamedParam internal::Curvature_flow curvature_remesher(pmesh, vpmap, vcmap, ecmap); - curvature_remesher.init_remeshing(faces); +#ifdef CGAL_PMP_REMESHING_VERBOSE + t.stop(); + std::cout << " done ("<< t.time() <<" sec)." << std::endl; + std::cout << "Removing degenerate faces..." << std::endl; + t.reset(); t.start(); +#endif + curvature_remesher.remove_degenerate_faces(); #ifdef CGAL_PMP_REMESHING_VERBOSE t.stop(); std::cout << " done ("<< t.time() <<" sec)." << std::endl; - std::cout << "Removing degenerate edges..." << std::endl; + std::cout << "Initializing..." << std::endl; t.reset(); t.start(); #endif - - curvature_remesher.remove_degenerate_faces(); + curvature_remesher.init_remeshing(faces); #ifdef CGAL_PMP_REMESHING_VERBOSE t.stop(); From 3f7267502a3c40cbfe7dabc6e2a1853df5c1955a Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Wed, 16 Aug 2017 18:39:01 +0300 Subject: [PATCH 083/102] remove trivial example --- .../Polygon_mesh_processing/CMakeLists.txt | 1 - .../curvature_flow_example.cpp | 33 ------------------- 2 files changed, 34 deletions(-) delete mode 100644 Polygon_mesh_processing/examples/Polygon_mesh_processing/curvature_flow_example.cpp diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt index dfe55191d3d..926cedbf8b9 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt @@ -102,7 +102,6 @@ create_single_source_cgal_program( "corefinement_difference_remeshed.cpp" ) create_single_source_cgal_program( "corefinement_mesh_union.cpp" ) create_single_source_cgal_program( "corefinement_polyhedron_union.cpp" ) create_single_source_cgal_program( "smoothing_example.cpp") -create_single_source_cgal_program( "curvature_flow_example.cpp") diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/curvature_flow_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/curvature_flow_example.cpp deleted file mode 100644 index e0f06e5504a..00000000000 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/curvature_flow_example.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include -#include - -#include -#include - -#include - - -typedef CGAL::Exact_predicates_inexact_constructions_kernel K; -typedef CGAL::Surface_mesh Mesh; - -int main(int argc, char* argv[]){ - - const char* filename = "data/mannequin-devil.off"; - std::ifstream input(filename); - std::ofstream output; - - Mesh mesh; - if (!input || !(input >> mesh) || mesh.is_empty()) { - std::cerr << "Not a valid .off file." << std::endl; - return 1; - } - - CGAL::Polygon_mesh_processing::curvature_flow(mesh); - - output.open("data/mannequin-devil_smoothed.off"); - output << mesh; - output.close(); - - - return 0; -} From d3f9ac763608f80429a7f3814530132d264a2052 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Sun, 20 Aug 2017 11:54:15 +0300 Subject: [PATCH 084/102] testing different weight calculation methods for curvature flow --- .../internal/Smoothing/curvature_flow_impl.h | 347 ++++++++++-------- .../CGAL/Polygon_mesh_processing/smoothing.h | 2 +- 2 files changed, 197 insertions(+), 152 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/curvature_flow_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/curvature_flow_impl.h index 9806cc66dd0..1259a2a21fd 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/curvature_flow_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/curvature_flow_impl.h @@ -1,26 +1,24 @@ #ifndef CURVATURE_FLOW_IMPL_H #define CURVATURE_FLOW_IMPL_H +#include +#include + #include #include #include #include -#include -#include -#include -#include - #include #include #include #include #include -#include -#include +#include +#include +#include -#include namespace CGAL { @@ -30,6 +28,38 @@ namespace internal { +template> +class Cotangent_weight : CotangentValue +{ +public: + Cotangent_weight(PolygonMesh& pmesh_, VertexPointMap vpmap_) + : CotangentValue(pmesh_, vpmap_) + {} + + PolygonMesh& pmesh() + { + return CotangentValue::pmesh(); + } + + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef std::pair he_pair; + + double operator()(halfedge_descriptor he, he_pair incd_edges) + { + vertex_descriptor vs = source(he, pmesh()); + vertex_descriptor vt = target(he, pmesh()); + vertex_descriptor v1 = target(incd_edges.first, pmesh()); + vertex_descriptor v2 = source(incd_edges.second, pmesh()); + + return ( CotangentValue::operator()(vs, v1, vt) + CotangentValue::operator()(vs, v2, vt)); + } + +}; + + + template class Curvature_flow { @@ -53,25 +83,53 @@ class Curvature_flow typedef std::pair he_pair; typedef std::map Edges_around_map; - typedef typename CGAL::Monge_via_jet_fitting Monge_via_jet_fitting; - typedef typename Monge_via_jet_fitting::Monge_form Monge_form; + //typedef typename CGAL::Monge_via_jet_fitting Monge_via_jet_fitting; + //typedef typename Monge_via_jet_fitting::Monge_form Monge_form; + /* + typedef CGAL::internal::Cotangent_weight< + PolygonMesh, + VertexPointMap, + CGAL::internal::Cotangent_value_minimum_zero + > + > + Weight_calculator_edge_based; + + +*/ + typedef CGAL::internal::Cotangent_value_Meyer_secure + Weight_calculator_angle_based; + + /* + typedef CGAL::internal::Cotangent_value_clamped_2 + Weight_calculator_clamped2; +*/ + + typedef Cotangent_weight Weight_calculator; public: Curvature_flow(PolygonMesh& pmesh, VertexPointMap& vpmap, VertexConstraintMap& vcmap, EdgeConstraintMap& ecmap) : - mesh_(pmesh), vpmap_(vpmap), vcmap_(vcmap), ecmap_(ecmap), cot_calculator_(pmesh, vpmap) + mesh_(pmesh), vpmap_(vpmap), vcmap_(vcmap), ecmap_(ecmap), + cot_calculator_angle_based_(pmesh, vpmap), + //cot_calculator_edge_based_(pmesh, vpmap), + //my_weight_calculator_(pmesh, vpmap), + //cot_clamped2_(pmesh, vpmap) + weight_calculator_(pmesh, vpmap) + { - /* +/* std::size_t num_points = vertices(mesh_).size(); std::size_t min_num_of_points = 6; // (d+1)(d+2)/2, for d=2 if(num_points < min_num_of_points) { CGAL_error_msg("Find curvature: Not enough points in the mesh."); } - */ +*/ @@ -115,6 +173,7 @@ public: std::map barycenters; std::map n_map; + BOOST_FOREACH(vertex_descriptor v, vrange) { if(!is_border(v, mesh_) && !is_constrained(v)) @@ -127,101 +186,6 @@ public: n_map[v] = vn; - // find incident halfedges - Edges_around_map he_map; - typename Edges_around_map::iterator it; - BOOST_FOREACH(halfedge_descriptor hi, halfedges_around_source(v, mesh_)) - he_map[hi] = he_pair( next(hi, mesh_), prev(opposite(hi, mesh_), mesh_) ); - - - // calculate movement - Vector curvature_normal = CGAL::NULL_VECTOR; - double sum_cot_weights = 0; - for(it = he_map.begin(); it!= he_map.end(); ++it) - { - halfedge_descriptor hi = it->first; - he_pair incd_edges = it->second; - - // weight - double weight = cot_angles(hi, incd_edges); - sum_cot_weights += weight; - - // displacement vector - Point Xi = get(vpmap_, source(hi, mesh_)); - Point Xj = get(vpmap_, target(hi, mesh_)); - //Vector vec(Xj, Xi); - Vector vec(Xi, Xj); - - // add weight - vec *= weight; - - // sum vecs - curvature_normal += vec; - } - - // divide with total weight - if there is actually weight - if(sum_cot_weights != 0) - curvature_normal /= sum_cot_weights; - - //Point weighted_barycenter = get(vpmap_, v) - curvature_normal; - Point weighted_barycenter = get(vpmap_, v) + curvature_normal; - barycenters[v] = weighted_barycenter; - - } // not on border - } // all vertices - - typedef typename std::map::value_type VP; - - /* - // compute locations on tangent plane - typedef typename std::map::value_type VP; - std::map new_locations; - BOOST_FOREACH(const VP& vp, barycenters) - { - Point p = get(vpmap_, vp.first); - Point q = vp.second; - Vector n = n_map[vp.first]; - - new_locations[vp.first] = q + ( n * Vector(q, p) ) * n ; - } - - */ - - // update location - //BOOST_FOREACH(const VP& vp, new_locations) // uncomment for tangent plane - BOOST_FOREACH(const VP& vp, barycenters) - { -#define CGAL_PMP_SMOOTHING_DEBUG -#ifdef CGAL_PMP_SMOOTHING_DEBUG - std::cout << "from: "<< get(vpmap_, vp.first); -#endif - put(vpmap_, vp.first, vp.second); - -#ifdef CGAL_PMP_SMOOTHING_DEBUG - std::cout<<" moved at: "<< vp.second << std::endl; -#endif - } - - } - - // test formula (14) - void good_curvature_smoothing() - { - std::map n_map; - std::map barycenters; - - - BOOST_FOREACH(vertex_descriptor v, vertices(mesh_)) - { - if(!is_border(v, mesh_)) // add && !is_constrained - { - // normals - Vector vn = compute_vertex_normal(v, mesh_, - Polygon_mesh_processing::parameters::vertex_point_map(vpmap_) - .geom_traits(traits_)); - n_map[v] = vn; - - // area around vertex double A = 0; //take one halfedge whose target is v @@ -241,51 +205,86 @@ public: // calculate movement - Vector weighted_move = CGAL::NULL_VECTOR; + Vector curvature_normal = CGAL::NULL_VECTOR; + Vector sum_of_vecs = CGAL::NULL_VECTOR; + double sum_cot_weights = 0; for(it = he_map.begin(); it!= he_map.end(); ++it) { halfedge_descriptor hi = it->first; he_pair incd_edges = it->second; + + //check_degeneracy(hi); + // weight - double weight = cot_angles(hi, incd_edges); + //double weight_angle_based = cot_angles(hi, incd_edges); + double weight_angle = weight_calculator_(hi, incd_edges); + //double weight_edge_based = cot_calculator_edge_based_(hi); + //double weight_my_weight = my_weight_calculator_(hi); + + double weight_angle_based = cot_angles(hi, incd_edges); + //weight_edge_based = cot_calculator_edge_based_(hi); + //weight_my_weight = my_weight_calculator_(hi); + + CGAL_assertion(weight_angle == weight_angle_based); + + double weight = weight_angle; // testing + sum_cot_weights += weight; + + /* + if(weight_edge_based > 1e-10) + { + CGAL_assertion(weight_angle_based > 2 * weight_edge_based - 1e-2 && + weight_angle_based < 2 * weight_edge_based + 1e-2); + } + + if(weight_angle_based > 1e-10) + { + CGAL_assertion(weight_angle_based > 2 * weight_edge_based - 1e-2 && + weight_angle_based < 2 * weight_edge_based + 1e-2); + } +*/ // displacement vector - Point xi = get(vpmap_, source(hi, mesh_)); - Point xj = get(vpmap_, target(hi, mesh_)); - Vector vec(xi, xj); + Point Xi = get(vpmap_, source(hi, mesh_)); + Point Xj = get(vpmap_, target(hi, mesh_)); + Vector vec(Xj, Xi); // towards outside + //Vector vec(Xi, Xj); // towards the inside // add weight - vec *= weight; // comment out for just laplacian + vec *= weight; // sum vecs - weighted_move += vec; + curvature_normal += vec; + + //sum_of_vecs += vec; // just curious + } - Vector curvature_normal = CGAL::NULL_VECTOR; - if (A != 0) - { - curvature_normal = weighted_move / (4 * A); - //curvature_normal = weighted_move / he_map.size(); // just laplacian - } + // divide with total weight - if there is actually weight + if(sum_cot_weights != 0) + curvature_normal /= sum_cot_weights; + //Vector curvature_normal_k = vn * mean_k_ * 0.1; + //curvature_normal = vn * sum_cot_weights; - Point old_point = get(vpmap_, v); - Point new_point = get(vpmap_, v) + curvature_normal; + //if(A != 0) + // curvature_normal /= (4 * A); -#ifdef CGAL_PMP_SMOOTHING_DEBUG - std::cout << "new location before projection: "<< new_point << std::endl; -#endif - barycenters[v] = new_point; + Point weighted_barycenter = get(vpmap_, v) - curvature_normal; + //Point weighted_barycenter = get(vpmap_, v) + curvature_normal; + barycenters[v] = weighted_barycenter; } // not on border - } // all vertices + typedef typename std::map::value_type VP; - // calculate location on tangential plane +/* + // compute locations on tangent plane + typedef typename std::map::value_type VP; std::map new_locations; - BOOST_FOREACH(const auto& vp, barycenters) + BOOST_FOREACH(const VP& vp, barycenters) { Point p = get(vpmap_, vp.first); Point q = vp.second; @@ -293,25 +292,17 @@ public: new_locations[vp.first] = q + ( n * Vector(q, p) ) * n ; } +*/ // update location - //BOOST_FOREACH(const auto& vp, barycenters) - BOOST_FOREACH(const auto& vp, new_locations) - { - -#ifdef CGAL_PMP_SMOOTHING_DEBUG - std::cout << "from: "<< get(vpmap_, vp.first); -#endif + //BOOST_FOREACH(const VP& vp, new_locations) // uncomment for tangent plane + BOOST_FOREACH(const VP& vp, barycenters) put(vpmap_, vp.first, vp.second); -#ifdef CGAL_PMP_SMOOTHING_DEBUG - std::cout<<" moved at: "<< vp.second << std::endl; -#endif - } - } + void project_to_surface() { BOOST_FOREACH(vertex_descriptor v, vertices(mesh_)) @@ -372,6 +363,7 @@ private: Vector edge2(pt, p2); Vector vec_main_he(pt, ps); double tolerance = 1e-3; + /* if ( edge1.squared_length() < tolerance || edge2.squared_length() < tolerance || sqlength(main_he) < tolerance || @@ -381,19 +373,58 @@ private: return 0; // zero means 90 degrees angle (also means no weight) } + */ - CGAL_assertion(vec_main_he.squared_length() > tolerance); + //CGAL_assertion(vec_main_he.squared_length() > tolerance); - double a1 = cot_calculator_(vs, v1, vt); - double a2 = cot_calculator_(vs, v2, vt); + double a1 = cot_calculator_angle_based_(vs, v1, vt); + double a2 = cot_calculator_angle_based_(vs, v2, vt); + + //a1 = cot_clamped2_(vs, v1, vt); + //a2 = cot_clamped2_(vs, v2, vt); return a1 + a2; } + void check_degeneracy(halfedge_descriptor h1) + { + halfedge_descriptor h2 = next(h1, mesh_); + halfedge_descriptor h3 = next(h2, mesh_); + + double a1 = get_angle(h1, h2); + double a2 = get_angle(h2, h3); + double a3 = get_angle(h3, h1); + + if(a1 < 0.05 || a2 < 0.05 || a3 < 0.05) + { + Euler::remove_face(h1, mesh_); + } + + + } + + double get_angle(halfedge_descriptor ha, halfedge_descriptor hb) + { + Vector a(get(vpmap_, source(ha, mesh_)), get(vpmap_, target(ha, mesh_))); + Vector b(get(vpmap_, source(hb, mesh_)), get(vpmap_, target(hb, mesh_))); + + double angle = get_angle(a, b); // to fix + + return angle; + } + + double get_angle(const Vector& e1, const Vector& e2) + { + //double rad_to_deg = 180. / CGAL_PI; + double cos_angle = (e1 * e2) + / std::sqrt(e1.squared_length() * e2.squared_length()); + + return std::acos(cos_angle); //* rad_to_deg; + } + /* double compute_mean_curvature() { - // gather points around v std::vector incident_points = gather_all_points(); Monge_form monge_form; @@ -443,7 +474,7 @@ private: return points; } - */ +*/ bool is_constrained(const edge_descriptor& e) { @@ -475,7 +506,7 @@ private: BOOST_FOREACH(face_descriptor f, face_range) { BOOST_FOREACH(vertex_descriptor v, vertices_around_face(halfedge(f, mesh_), mesh_)) - vrange.push_back(v); + vrange.insert(v); } } @@ -487,16 +518,30 @@ private: Triangle_list input_triangles_; Tree* tree_ptr_; GeomTraits traits_; - std::vector vrange; + std::set vrange; // to fix //double min_sq_edge_len_; - //double mean_k_; + double mean_k_; // from Weights.h - CGAL::internal::Cotangent_value_Meyer_secure cot_calculator_; + //CGAL::internal::Cotangent_value_Meyer_secure cot_calculator_; //CGAL::internal::Cotangent_value_clamped_2 cot_calculator_; //CGAL::internal::Cotangent_value_clamped cot_calculator_; + /* + typedef CGAL::internal::Cotangent_weight< + PolygonMesh, + typename boost::property_map::type, + CGAL::internal::Cotangent_value_minimum_zero::type, + CGAL::internal::Cotangent_value_Meyer_secure > > cot_calculator_; + */ + //Weight_calculator_edge_based cot_calculator_edge_based_; + Weight_calculator_angle_based cot_calculator_angle_based_; + Weight_calculator weight_calculator_; + //Weight_calculator_clamped2 cot_clamped2_; + + }; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h index 91bbca29cf4..09ad81661d3 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h @@ -483,7 +483,7 @@ void curvature_flow(PolygonMesh& pmesh, const FaceRange& faces, const NamedParam //curvature_remesher.good_curvature_smoothing(); // formula 14 //for now - curvature_remesher.project_to_surface(); + //curvature_remesher.project_to_surface(); } From a0e7cf4a7fb9c9d2a9d0b6d0bc8b3e3c3e734e59 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Sun, 20 Aug 2017 19:14:32 +0300 Subject: [PATCH 085/102] cleaning code & use weight calculator which covers better at 0 and Pi making possible many curvature iterations --- .../internal/Smoothing/curvature_flow_impl.h | 328 +++--------------- .../internal/Smoothing/smoothing_impl.h | 9 +- 2 files changed, 43 insertions(+), 294 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/curvature_flow_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/curvature_flow_impl.h index 1259a2a21fd..b5e4d830308 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/curvature_flow_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/curvature_flow_impl.h @@ -15,10 +15,6 @@ #include #include -#include -#include -#include - namespace CGAL { @@ -29,7 +25,7 @@ namespace internal { template> + typename CotangentValue = CGAL::internal::Cotangent_value_Meyer> class Cotangent_weight : CotangentValue { public: @@ -53,17 +49,15 @@ public: vertex_descriptor v1 = target(incd_edges.first, pmesh()); vertex_descriptor v2 = source(incd_edges.second, pmesh()); - return ( CotangentValue::operator()(vs, v1, vt) + CotangentValue::operator()(vs, v2, vt)); + return ( CotangentValue::operator()(vs, v1, vt) + CotangentValue::operator()(vs, v2, vt) ); } }; - template class Curvature_flow { - typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::face_descriptor face_descriptor; @@ -72,68 +66,27 @@ class Curvature_flow typedef typename GeomTraits::Point_3 Point; typedef typename GeomTraits::Vector_3 Vector; typedef typename GeomTraits::Triangle_3 Triangle; - typedef typename GeomTraits::FT FT; typedef std::vector Triangle_list; - typedef CGAL::AABB_triangle_primitive AABB_Primitive; - typedef CGAL::AABB_traits AABB_Traits; - typedef CGAL::AABB_tree Tree; - - // typedef std::pair he_pair; typedef std::map Edges_around_map; - //typedef typename CGAL::Monge_via_jet_fitting Monge_via_jet_fitting; - //typedef typename Monge_via_jet_fitting::Monge_form Monge_form; - - - /* - typedef CGAL::internal::Cotangent_weight< - PolygonMesh, - VertexPointMap, - CGAL::internal::Cotangent_value_minimum_zero - > - > - Weight_calculator_edge_based; - - -*/ - typedef CGAL::internal::Cotangent_value_Meyer_secure - Weight_calculator_angle_based; - - /* - typedef CGAL::internal::Cotangent_value_clamped_2 - Weight_calculator_clamped2; -*/ - typedef Cotangent_weight Weight_calculator; + /* + typedef CGAL::internal::Cotangent_weight > > + Edge_weight_calculator; + */ + public: Curvature_flow(PolygonMesh& pmesh, VertexPointMap& vpmap, VertexConstraintMap& vcmap, EdgeConstraintMap& ecmap) : mesh_(pmesh), vpmap_(vpmap), vcmap_(vcmap), ecmap_(ecmap), - cot_calculator_angle_based_(pmesh, vpmap), - //cot_calculator_edge_based_(pmesh, vpmap), - //my_weight_calculator_(pmesh, vpmap), - //cot_clamped2_(pmesh, vpmap) weight_calculator_(pmesh, vpmap) - - { - -/* - std::size_t num_points = vertices(mesh_).size(); - std::size_t min_num_of_points = 6; // (d+1)(d+2)/2, for d=2 - if(num_points < min_num_of_points) - { - CGAL_error_msg("Find curvature: Not enough points in the mesh."); - } -*/ - - - - } + //edge_weight_calculator_(pmesh, vpmap) + {} template void init_remeshing(const FaceRange& face_range) @@ -143,181 +96,83 @@ public: check_constraints(); BOOST_FOREACH(face_descriptor f, face_range) - { input_triangles_.push_back(triangle(f)); - } - - tree_ptr_ = new Tree(input_triangles_.begin(), input_triangles_.end()); - tree_ptr_->accelerate_distance_queries(); - - //mean_k_ = compute_mean_curvature(); - } std::size_t remove_degenerate_faces() { std::size_t nb_removed_faces = 0; - - // from repair.h nb_removed_faces = CGAL::Polygon_mesh_processing::remove_degenerate_faces(mesh_); -#ifdef CGAL_PMP_SMOOTHING_DEBUG - std::cout<<"nb_collapsed_faces: "< barycenters; - std::map n_map; - BOOST_FOREACH(vertex_descriptor v, vrange) { if(!is_border(v, mesh_) && !is_constrained(v)) { - - // normals - Vector vn = compute_vertex_normal(v, mesh_, - Polygon_mesh_processing::parameters::vertex_point_map(vpmap_) - .geom_traits(traits_)); - n_map[v] = vn; - - - // area around vertex - double A = 0; - //take one halfedge whose target is v - BOOST_FOREACH(halfedge_descriptor ht, halfedges_around_target(v, mesh_)) - { - // is it ok if a face is degenerate? - A = area(faces_around_target(ht, mesh_), mesh_); - continue; - } - - // find incident halfedges Edges_around_map he_map; typename Edges_around_map::iterator it; BOOST_FOREACH(halfedge_descriptor hi, halfedges_around_source(v, mesh_)) he_map[hi] = he_pair( next(hi, mesh_), prev(opposite(hi, mesh_), mesh_) ); - // calculate movement Vector curvature_normal = CGAL::NULL_VECTOR; - Vector sum_of_vecs = CGAL::NULL_VECTOR; double sum_cot_weights = 0; for(it = he_map.begin(); it!= he_map.end(); ++it) { halfedge_descriptor hi = it->first; he_pair incd_edges = it->second; - //check_degeneracy(hi); // weight - //double weight_angle_based = cot_angles(hi, incd_edges); - double weight_angle = weight_calculator_(hi, incd_edges); - //double weight_edge_based = cot_calculator_edge_based_(hi); - //double weight_my_weight = my_weight_calculator_(hi); + //double edge_weight = edge_weight_calculator_(hi); + double angle_weight = weight_calculator_(hi, incd_edges); // to fix - double weight_angle_based = cot_angles(hi, incd_edges); - //weight_edge_based = cot_calculator_edge_based_(hi); - //weight_my_weight = my_weight_calculator_(hi); + double weight = angle_weight; // temp - CGAL_assertion(weight_angle == weight_angle_based); - - double weight = weight_angle; // testing sum_cot_weights += weight; - /* - if(weight_edge_based > 1e-10) - { - CGAL_assertion(weight_angle_based > 2 * weight_edge_based - 1e-2 && - weight_angle_based < 2 * weight_edge_based + 1e-2); - } - - if(weight_angle_based > 1e-10) - { - CGAL_assertion(weight_angle_based > 2 * weight_edge_based - 1e-2 && - weight_angle_based < 2 * weight_edge_based + 1e-2); - } -*/ - // displacement vector - Point Xi = get(vpmap_, source(hi, mesh_)); - Point Xj = get(vpmap_, target(hi, mesh_)); - Vector vec(Xj, Xi); // towards outside - //Vector vec(Xi, Xj); // towards the inside + Point xi = get(vpmap_, source(hi, mesh_)); + Point xj = get(vpmap_, target(hi, mesh_)); + Vector vec(xj, xi); // towards the vertex that is being moved // add weight vec *= weight; // sum vecs curvature_normal += vec; - - //sum_of_vecs += vec; // just curious - } - // divide with total weight - if there is actually weight + // divide with total weight if(sum_cot_weights != 0) curvature_normal /= sum_cot_weights; - //Vector curvature_normal_k = vn * mean_k_ * 0.1; - //curvature_normal = vn * sum_cot_weights; - - //if(A != 0) - // curvature_normal /= (4 * A); - Point weighted_barycenter = get(vpmap_, v) - curvature_normal; - //Point weighted_barycenter = get(vpmap_, v) + curvature_normal; barycenters[v] = weighted_barycenter; } // not on border } // all vertices - typedef typename std::map::value_type VP; - -/* - // compute locations on tangent plane - typedef typename std::map::value_type VP; - std::map new_locations; - BOOST_FOREACH(const VP& vp, barycenters) - { - Point p = get(vpmap_, vp.first); - Point q = vp.second; - Vector n = n_map[vp.first]; - - new_locations[vp.first] = q + ( n * Vector(q, p) ) * n ; - } -*/ - - // update location - //BOOST_FOREACH(const VP& vp, new_locations) // uncomment for tangent plane + typedef typename std::map::value_type VP; BOOST_FOREACH(const VP& vp, barycenters) put(vpmap_, vp.first, vp.second); } - void project_to_surface() - { - BOOST_FOREACH(vertex_descriptor v, vertices(mesh_)) - { - if(!is_border(v, mesh_) ) // todo: && !is_constrained(v) - { - Point p_query = get(vpmap_, v); - Point projected = tree_ptr_->closest_point(p_query); - put(vpmap_, v, projected); - } - } - } - - private: + + // helper functions + // ---------------- Triangle triangle(face_descriptor f) const { halfedge_descriptor h = halfedge(f, mesh_); @@ -344,48 +199,9 @@ private: return sqlength(halfedge(e, mesh_)); } - double cot_angles(const halfedge_descriptor& main_he, const he_pair& incd_edges) - { - vertex_descriptor vs = source(main_he, mesh_); - vertex_descriptor vt = target(main_he, mesh_); - vertex_descriptor v1 = target(incd_edges.first, mesh_); - vertex_descriptor v2 = source(incd_edges.second, mesh_); - - CGAL_assertion(target(incd_edges.second, mesh_) == source(incd_edges.first, mesh_)); - - Point p1 = get(vpmap_, v1); - Point p2 = get(vpmap_, v2); - Point pt = get(vpmap_, vt); - Point ps = get(vpmap_, vs); - - // avoid degenerate cases - Vector edge1(pt, p1); - Vector edge2(pt, p2); - Vector vec_main_he(pt, ps); - double tolerance = 1e-3; - /* - if ( edge1.squared_length() < tolerance || - edge2.squared_length() < tolerance || - sqlength(main_he) < tolerance || - (edge1 - vec_main_he).squared_length() < tolerance || - (edge2 - vec_main_he).squared_length() < tolerance ) - { - return 0; - // zero means 90 degrees angle (also means no weight) - } - */ - - //CGAL_assertion(vec_main_he.squared_length() > tolerance); - - double a1 = cot_calculator_angle_based_(vs, v1, vt); - double a2 = cot_calculator_angle_based_(vs, v2, vt); - - //a1 = cot_clamped2_(vs, v1, vt); - //a2 = cot_clamped2_(vs, v2, vt); - - return a1 + a2; - } + // degeneracy removal + // ------------------ void check_degeneracy(halfedge_descriptor h1) { halfedge_descriptor h2 = next(h1, mesh_); @@ -395,7 +211,16 @@ private: double a2 = get_angle(h2, h3); double a3 = get_angle(h3, h1); - if(a1 < 0.05 || a2 < 0.05 || a3 < 0.05) + double angle_min_threshold = 0.05; // rad + double angle_max_threshold = CGAL_PI - 0.05; + + + if(a1 < angle_min_threshold || a2 < angle_min_threshold || a3 < angle_min_threshold) + { + Euler::remove_face(h1, mesh_); + } + + if(a1 > angle_max_threshold || a2 > angle_max_threshold || a3 > angle_max_threshold) { Euler::remove_face(h1, mesh_); } @@ -408,9 +233,7 @@ private: Vector a(get(vpmap_, source(ha, mesh_)), get(vpmap_, target(ha, mesh_))); Vector b(get(vpmap_, source(hb, mesh_)), get(vpmap_, target(hb, mesh_))); - double angle = get_angle(a, b); // to fix - - return angle; + return get_angle(a, b); } double get_angle(const Vector& e1, const Vector& e2) @@ -422,60 +245,9 @@ private: return std::acos(cos_angle); //* rad_to_deg; } - /* - double compute_mean_curvature() - { - std::vector incident_points = gather_all_points(); - - Monge_form monge_form; - Monge_via_jet_fitting monge_fit; - - std::size_t d_fit = 2; // d_fit >= d_monge - std::size_t d_monge = 2; // need 2 principal coeeficients - std::size_t Nd = (d_fit + 1)*(d_fit + 1) / 2.0; - CGAL_assertion(incident_points.size() >= Nd); - - monge_form = monge_fit(incident_points.begin(), incident_points.end(), d_fit, d_monge); - const double k1 = monge_form.principal_curvatures(0); - const double k2 = monge_form.principal_curvatures(1); - - return (k1 + k2) / 2.0; - } - - - std::vector points_around_vertex(vertex_descriptor v) - { - std::vector incident_vertices; - for(halfedge_descriptor h : halfedges_around_target(v, mesh_)) - { - vertex_descriptor vs = source(h, mesh_); - incident_vertices.push_back(get(vpmap_, vs)); - } - - // temp assertion - std::vector incident_vertices2; - for(vertex_descriptor vi : vertices_around_target(v, mesh_)) - { - incident_vertices2.push_back(get(vpmap_, vi)); - } - CGAL_assertion(incident_vertices.size() == incident_vertices2.size()); - - return incident_vertices; - } - - std::vector gather_all_points() - { - //TODO SEE IF THERE IS SOMTEHTING alREADY FOR POINTS - std::vector points; - for(vertex_descriptor v : vertices(mesh_)) - { - points.push_back(get(vpmap_, v)); // todo: preallocate it and fill it by pointing - } - - return points; - } -*/ + // functions for constrained vertices + // ----------------------------------- bool is_constrained(const edge_descriptor& e) { return get(ecmap_, e); @@ -510,36 +282,20 @@ private: } } + +private: + // data members + // ------------ PolygonMesh& mesh_; VertexPointMap& vpmap_; VertexConstraintMap vcmap_; EdgeConstraintMap ecmap_; Triangle_list input_triangles_; - Tree* tree_ptr_; GeomTraits traits_; std::set vrange; - - // to fix - //double min_sq_edge_len_; - double mean_k_; - // from Weights.h - //CGAL::internal::Cotangent_value_Meyer_secure cot_calculator_; - //CGAL::internal::Cotangent_value_clamped_2 cot_calculator_; - //CGAL::internal::Cotangent_value_clamped cot_calculator_; - - /* - typedef CGAL::internal::Cotangent_weight< - PolygonMesh, - typename boost::property_map::type, - CGAL::internal::Cotangent_value_minimum_zero::type, - CGAL::internal::Cotangent_value_Meyer_secure > > cot_calculator_; - */ - //Weight_calculator_edge_based cot_calculator_edge_based_; - Weight_calculator_angle_based cot_calculator_angle_based_; Weight_calculator weight_calculator_; - //Weight_calculator_clamped2 cot_clamped2_; + //Edge_weight_calculator edge_weight_calculator_; }; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h index 8195baf0683..a84466a9e66 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h @@ -49,7 +49,6 @@ class Compatible_remesher typedef CGAL::AABB_traits AABB_Traits; typedef CGAL::AABB_tree Tree; - // typedef std::pair he_pair; typedef std::map Edges_around_map; @@ -81,14 +80,8 @@ public: std::size_t remove_degenerate_faces() { std::size_t nb_removed_faces = 0; - - // from repair.h nb_removed_faces = CGAL::Polygon_mesh_processing::remove_degenerate_faces(mesh_); -#ifdef CGAL_PMP_SMOOTHING_DEBUG - std::cout<<"nb_collapsed_faces: "< Date: Sun, 20 Aug 2017 23:18:07 +0300 Subject: [PATCH 086/102] compatible remeshing function --- .../internal/parameters_interface.h | 1 + .../CGAL/Polygon_mesh_processing/smoothing.h | 281 +++++++++++++++--- 2 files changed, 237 insertions(+), 45 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/parameters_interface.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/parameters_interface.h index 03bdc7a777c..c3e0f9ebeb6 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/parameters_interface.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/parameters_interface.h @@ -48,6 +48,7 @@ CGAL_add_named_parameter(nb_points_per_distance_unit_t, nb_points_per_distance_u CGAL_add_named_parameter(face_normal_t, face_normal, face_normal_map) CGAL_add_named_parameter(gradient_descent_precision_t, gradient_descent_precision, gradient_descent_precision) CGAL_add_named_parameter(use_weights_t, use_weights, use_weights) +CGAL_add_named_parameter(distance_precision_t, distance_precision, distance_precision) //internal CGAL_add_named_parameter(weight_calculator_t, weight_calculator, weight_calculator) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h index 09ad81661d3..90de3eca586 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h @@ -1,7 +1,6 @@ #ifndef CGAL_POLYGON_MESH_PROCESSING_SMOOTHING_H #define CGAL_POLYGON_MESH_PROCESSING_SMOOTHING_H - #include #include #include @@ -9,10 +8,18 @@ #include #include +#include + #ifdef CGAL_PMP_REMESHING_VERBOSE #include #endif +#if defined(CGAL_LINKED_WITH_TBB) +#define TAG CGAL::Parallel_tag +#else +#define TAG CGAL::Sequential_tag +#endif + namespace CGAL { namespace Polygon_mesh_processing { @@ -51,17 +58,15 @@ namespace Polygon_mesh_processing { * \cgalParamBegin{face_index_map} a property map containing the index of each face of `pmesh`. * \cgalParamEnd * \cgalParamBegin{number_of_iterations} the number of iterations for the -* sequence of atomic operations performed (listed in the above description) +* sequence of the smoothing iterations performed. * \cgalParamEnd * \cgalParamBegin{edge_is_constrained_map} a property map containing the -* constrained-or-not status of each edge of `pmesh`. A constrained edge can be split -* or collapsed, but not flipped, nor its endpoints moved by smoothing. -* Note that patch boundary edges (i.e. incident to only one face in the range) -* are always considered as constrained edges. +* constrained-or-not status of each edge of `pmesh`. Vertices that belong to constrained +* edges are not modified at all during smoothing. * \cgalParamEnd * \cgalParamBegin{vertex_is_constrained_map} a property map containing the * constrained-or-not status of each vertex of `pmesh`. A constrained vertex -* cannot be modified at all during remeshing. +* cannot be modified at all during smoothing. * \cgalParamEnd * \cgalParamBegin{use_weights} If `true`, small angles carry more weight than larger ones. * \cgalParamEnd @@ -121,6 +126,9 @@ void angle_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const NamedPara //use weighted angles bool use_weights = choose_param(get_param(np, internal_np::use_weights), false); + // convergence precision + double precision = choose_param(get_param(np, internal_np::number_of_iterations), 1); + internal::Compatible_remesher remesher(pmesh, vpmap, vcmap, ecmap); @@ -185,8 +193,8 @@ void angle_remeshing(PolygonMesh& pmesh) * \ingroup PMP_meshing_grp * @brief uses triangle area as a criterion for smoothing. * This function imrpoves the overall distribution of points over a mesh area -* by trying to form triangles as uniform as possible. Should be used in combination with angle remeshing -* to avoid creation of long and skiny triangles. Vertices are moved towards equalizing adjacent triangle +* by trying to form triangles as uniform as possible. Use of many iterations of area equalization alone +* for remeshing may result in long and skinny triangles. Vertices are moved towards equalizing adjacent triangle * areas using gradient descent. * * @tparam PolygonMesh model of `MutableFaceGraph`. @@ -214,17 +222,15 @@ void angle_remeshing(PolygonMesh& pmesh) * \cgalParamBegin{face_index_map} a property map containing the index of each face of `pmesh`. * \cgalParamEnd * \cgalParamBegin{number_of_iterations} the number of iterations for the -* sequence of atomic operations performed (listed in the above description) +* sequence of the smoothing iterations performed. * \cgalParamEnd * \cgalParamBegin{edge_is_constrained_map} a property map containing the -* constrained-or-not status of each edge of `pmesh`. A constrained edge can be split -* or collapsed, but not flipped, nor its endpoints moved by smoothing. -* Note that patch boundary edges (i.e. incident to only one face in the range) -* are always considered as constrained edges. +* constrained-or-not status of each edge of `pmesh`. Vertices that belong to constrained +* edges are not modified at all during smoothing. * \cgalParamEnd * \cgalParamBegin{vertex_is_constrained_map} a property map containing the * constrained-or-not status of each vertex of `pmesh`. A constrained vertex -* cannot be modified at all during remeshing. +* cannot be modified at all during smoothing. * \cgalParamEnd * \cgalParamBegin{gradient_descent_precision} The precision which is met during gradient descent refers to * the relative energy between iterations of each triangle element which is minimized @@ -344,6 +350,208 @@ void area_remeshing(PolygonMesh& pmesh) area_remeshing(pmesh, faces(pmesh), parameters::all_default()); } +/*! +* \ingroup PMP_meshing_grp +* @brief smoothes a triangulated region of a polygon mesh. +* This function imrpoves the overall mesh quality by using sequentially angle, +* area, and again angle criteria for each iteration until convergence. Convergence is realized based on +* the hausdorff distance of the mesh between previous and current iteration or until +* a specified maximum number of iterations. +* +* @tparam PolygonMesh model of `MutableFaceGraph`. +* The descriptor types `boost::graph_traits::%face_descriptor` +* and `boost::graph_traits::%halfedge_descriptor` must be +* models of `Hashable`. +* If `PolygonMesh` has an internal property map for `CGAL::face_index_t`, +* and no `face_index_map` is given +* as a named parameter, then the internal one should be initialized +* @tparam FaceRange range of `boost::graph_traits::%face_descriptor`, + model of `Range`. Its iterator type is `ForwardIterator`. +* @tparam NamedParameters a sequence of \ref namedparameters +* +* @param pmesh a polygon mesh with triangulated surface patches to be remeshed +* @param faces the range of triangular faces defining one or several surface patches to be remeshed +* @param np optional sequence of \ref namedparameters among the ones listed below +* +* \cgalNamedParamsBegin +* \cgalParamBegin{geom_traits} a geometric traits class instance, model of `Kernel`. +* Exact constructions kernels are not supported by this function. +* \cgalParamEnd +* \cgalParamBegin{vertex_point_map} the property map with the points associated +* to the vertices of `pmesh`. Instance of a class model of `ReadWritePropertyMap`. +* \cgalParamEnd +* \cgalParamBegin{face_index_map} a property map containing the index of each face of `pmesh`. +* \cgalParamEnd +* \cgalParamBegin{number_of_iterations} the maximum number of iterations for the +* sequence of smoothing iterations performed. +* \cgalParamEnd +* \cgalParamBegin{edge_is_constrained_map} a property map containing the +* constrained-or-not status of each edge of `pmesh`. Vertices that belong to constrained +* edges are not modified at all during smoothing. +* \cgalParamEnd +* \cgalParamBegin{vertex_is_constrained_map} a property map containing the +* constrained-or-not status of each vertex of `pmesh`. A constrained vertex +* cannot be modified at all during smoothing. +* \cgalParamEnd +* \cgalParamBegin{use_weights} If `true`, small angles carry more weight than larger ones. +* \cgalParamEnd +* \cgalParamBegin{distance_precision} The Hausdorff distance between the mesh of the previous and the curent iteration. +* Defaults to 0.01. +* \cgalParamEnd +* \cgalNamedParamsEnd +*/ +template +void compatible_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const NamedParameters& np) +{ + using boost::choose_param; + using boost::get_param; + +#ifdef CGAL_PMP_REMESHING_VERBOSE + CGAL::Timer t; + std::cout << "Remeshing parameters..."; + std::cout.flush(); + t.start(); +#endif + + // geom traits + typedef typename GetGeomTraits::type GeomTraits; + + // vpmap + typedef typename GetVertexPointMap::type VertexPointMap; + VertexPointMap vpmap = choose_param(get_param(np, internal_np::vertex_point), + get_property_map(CGAL::vertex_point, pmesh)); + + // fimap + typedef typename GetFaceIndexMap::type FIMap; + FIMap fimap = choose_param(get_param(np, internal_np::face_index), + get_property_map(face_index, pmesh)); + + // vcmap + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::lookup_named_param_def < + internal_np::vertex_is_constrained_t, + NamedParameters, + internal::No_constraint_pmap//default + > ::type VCMap; + VCMap vcmap = choose_param(get_param(np, internal_np::vertex_is_constrained), + internal::No_constraint_pmap()); + + // ecmap + typedef typename boost::lookup_named_param_def < + internal_np::edge_is_constrained_t, + NamedParameters, + internal::Border_constraint_pmap + > ::type ECMap; + ECMap ecmap = (boost::is_same >::value) + ? choose_param(get_param(np, internal_np::edge_is_constrained), + internal::Border_constraint_pmap(pmesh, faces, fimap)) + : choose_param(get_param(np, internal_np::edge_is_constrained), + internal::Border_constraint_pmap()); + + //nb_iterations + unsigned int nb_iterations = choose_param(get_param(np, internal_np::number_of_iterations), 20); + + //use weighted angles + bool use_weights = choose_param(get_param(np, internal_np::use_weights), false); + + //gradient descent precision + double gd_precision = choose_param(get_param(np, internal_np::gradient_descent_precision), 0.001); + + // convergence precision + double dist_precision = choose_param(get_param(np, internal_np::distance_precision), 1); + + internal::Compatible_remesher + remesher(pmesh, vpmap, vcmap, ecmap); + +#ifdef CGAL_PMP_REMESHING_VERBOSE + t.stop(); + std::cout << " done ("<< t.time() <<" sec)." << std::endl; + std::cout << "Removing degenerate faces..." << std::endl; + t.reset(); t.start(); +#endif + remesher.remove_degenerate_faces(); + +#ifdef CGAL_PMP_REMESHING_VERBOSE + t.stop(); + std::cout << " done ("<< t.time() <<" sec)." << std::endl; + std::cout << "Initializing..." << std::endl; + t.reset(); t.start(); +#endif + remesher.init_remeshing(faces); + + +#ifdef CGAL_PMP_REMESHING_VERBOSE + t.stop(); + std::cout << " done ("<< t.time() <<" sec)." << std::endl; + std::cout << "#iter = " << nb_iterations << std::endl; + std::cout << "Remeshing ..." << std::endl; + t.reset(); t.start(); +#endif + + unsigned int count_iterations = 0; + PolygonMesh previous_mesh; + + while(true) + { + previous_mesh = pmesh; + remesher.angle_relaxation(use_weights); + remesher.area_relaxation(gd_precision); + remesher.angle_relaxation(use_weights); + remesher.project_to_surface(); + + double dist = approximate_Hausdorff_distance + (previous_mesh, pmesh, parameters::number_of_points_per_area_unit(1000)); + + count_iterations++; + + if(dist < dist_precision) + { + +#ifdef CGAL_PMP_REMESHING_VERBOSE + t.stop(); + std::cout << "Remeshing done in "; + std::cout << t.time() << " sec." << std::endl; + std::cout << "Convergence to relative hausdorff distance has been achieved." << std::endl; +#endif + break; + } + + if(count_iterations == nb_iterations) + { + +#ifdef CGAL_PMP_REMESHING_VERBOSE + t.stop(); + std::cout << "Remeshing done in "; + std::cout << t.time() << " sec." << std::endl; + std::cout << "Maximum number of iterations has been achieved." << std::endl; +#endif + break; + } + } + + + +#ifdef CGAL_PMP_REMESHING_VERBOSE + t.stop(); + std::cout << "Remeshing done in "; + std::cout << t.time() << " sec." << std::endl; +#endif + +} + +template +void compatible_remeshing(PolygonMesh& pmesh, const NamedParameters& np) +{ + compatible_remeshing(pmesh, faces(pmesh), np); +} + +template +void compatible_remeshing(PolygonMesh& pmesh) +{ + compatible_remeshing(pmesh, faces(pmesh), parameters::all_default()); +} + + /*! * \ingroup PMP_meshing_grp * @brief todo @@ -372,18 +580,13 @@ void area_remeshing(PolygonMesh& pmesh) * \cgalParamEnd * \cgalParamBegin{face_index_map} a property map containing the index of each face of `pmesh`. * \cgalParamEnd -* \cgalParamBegin{number_of_iterations} the number of iterations for the -* sequence of atomic operations performed (listed in the above description) -* \cgalParamEnd * \cgalParamBegin{edge_is_constrained_map} a property map containing the -* constrained-or-not status of each edge of `pmesh`. A constrained edge can be split -* or collapsed, but not flipped, nor its endpoints moved by smoothing. -* Note that patch boundary edges (i.e. incident to only one face in the range) -* are always considered as constrained edges. +* constrained-or-not status of each edge of `pmesh`. Vertices that belong to constrained +* edges are not modified at all during smoothing. * \cgalParamEnd * \cgalParamBegin{vertex_is_constrained_map} a property map containing the * constrained-or-not status of each vertex of `pmesh`. A constrained vertex -* cannot be modified at all during remeshing. +* cannot be modified at all during smoothing. * \cgalParamEnd * \cgalNamedParamsEnd */ @@ -403,17 +606,17 @@ void curvature_flow(PolygonMesh& pmesh, const FaceRange& faces, const NamedParam // GeomTraits typedef typename GetGeomTraits::type GeomTraits; - //vpmap + // vpmap typedef typename GetVertexPointMap::type VertexPointMap; VertexPointMap vpmap = choose_param(get_param(np, internal_np::vertex_point), get_property_map(CGAL::vertex_point, pmesh)); - //fimap + // fimap typedef typename GetFaceIndexMap::type FIMap; FIMap fimap = choose_param(get_param(np, internal_np::face_index), get_property_map(face_index, pmesh)); - //vcmap + // vcmap typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::lookup_named_param_def < internal_np::vertex_is_constrained_t, @@ -423,7 +626,7 @@ void curvature_flow(PolygonMesh& pmesh, const FaceRange& faces, const NamedParam VCMap vcmap = choose_param(get_param(np, internal_np::vertex_is_constrained), internal::No_constraint_pmap()); - //ecmap + // ecmap typedef typename boost::lookup_named_param_def < internal_np::edge_is_constrained_t, NamedParameters, @@ -435,7 +638,7 @@ void curvature_flow(PolygonMesh& pmesh, const FaceRange& faces, const NamedParam : choose_param(get_param(np, internal_np::edge_is_constrained), internal::Border_constraint_pmap()); - //nb_iterations + // nb_iterations unsigned int nb_iterations = choose_param(get_param(np, internal_np::number_of_iterations), 1); #ifdef CGAL_PMP_REMESHING_VERBOSE @@ -454,6 +657,7 @@ void curvature_flow(PolygonMesh& pmesh, const FaceRange& faces, const NamedParam std::cout << "Removing degenerate faces..." << std::endl; t.reset(); t.start(); #endif + curvature_remesher.remove_degenerate_faces(); #ifdef CGAL_PMP_REMESHING_VERBOSE @@ -462,34 +666,21 @@ void curvature_flow(PolygonMesh& pmesh, const FaceRange& faces, const NamedParam std::cout << "Initializing..." << std::endl; t.reset(); t.start(); #endif + curvature_remesher.init_remeshing(faces); #ifdef CGAL_PMP_REMESHING_VERBOSE t.stop(); std::cout << " done ("<< t.time() <<" sec)." << std::endl; - std::cout << "#iter = " << nb_iterations << std::endl; - std::cout << "Remeshing ..." << std::endl; + std::cout << "Shape smoothing..." << std::endl; t.reset(); t.start(); #endif - for(unsigned int i=0; i Date: Sun, 20 Aug 2017 23:22:25 +0300 Subject: [PATCH 087/102] improved doc --- .../NamedParameters.txt | 9 ++++++ .../PackageDescription.txt | 1 + .../Polygon_mesh_processing.txt | 28 +++++++++++-------- 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/NamedParameters.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/NamedParameters.txt index cf95b12a4ef..2a967f963cd 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/NamedParameters.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/NamedParameters.txt @@ -356,6 +356,15 @@ average area of all triagnles adjacent to the vertex that is being moved. \b Default is `0.001` \cgalNPEnd +\cgalNPBegin{distance_precision} \anchor PMP_distance_precision +Parameter used in `compatible_remeshing()` to set precision for the Hausdorff distance +of the mesh between the previous and the current iteration that has to be achieved for a mesh to converge +during smoothing. +\n +\b Type : `double` \n +\b Default is `0.01` +\cgalNPEnd + \cgalNPTableEnd */ diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt index 59da5265c0d..9e560bd4c2e 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt @@ -88,6 +88,7 @@ and provides a list of the parameters that are used in this package. - `CGAL::Polygon_mesh_processing::refine()` - `CGAL::Polygon_mesh_processing::angle_remeshing()` - `CGAL::Polygon_mesh_processing::area_remeshing()` +- `CGAL::Polygon_mesh_processing::compatible_remeshing()` - `CGAL::Polygon_mesh_processing::curvature_flow()` - `CGAL::Polygon_mesh_processing::triangulate_face()` - `CGAL::Polygon_mesh_processing::triangulate_faces()` diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt index e9b291eeb12..1d2960e8880 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt @@ -123,25 +123,31 @@ Isotropic remeshing. (a) Triangulated input surface mesh. \subsection Smoothing -Smoothing of a triangulated mesh area can be achieved with three algorithms. `CGAL::Polygon_mesh_processing::angle_remeshing()` -moves vertices so that the angles of its incident edges equalize, `CGAL::Polygon_mesh_processing::area_remeshing()` -moves vertices so that the areas of adjacent triangles equalize and `CGAL::Polygon_mesh_processing::curvature_flow()` +Smoothing of a triangulated mesh area can be achieved with algorithms that aim at either mesh smoothing or shape smoothing. +While mesh smoothing is achieved by improving the quality of the triangulated elements based on criteria such as angle and area, +shape smoothing is designed to be "intrinsic", depending as little as possible to the discretization +and smoothing the shape only without optimizing the mesh elements. + +For mesh smoothing, `CGAL::Polygon_mesh_processing::angle_remeshing()` may be used to +move vertices so that the angles of its incident edges equalize and `CGAL::Polygon_mesh_processing::area_remeshing()` may be used to +move vertices so that the areas of adjacent triangles equalize. Angle and area remeshing are used in combination in +`CGAL::Polygon_mesh_processing::compatible_remeshing()` which smooths the mesh until convergence is achieved. +For shape smoothing, `CGAL::Polygon_mesh_processing::curvature_flow()` takes into account the mean curvature to calculate a weighted barycenter towards which vertices move incrementally. -In all cases border vertices are considered constrained and do not move at any step of the algorithms. -Also, all three smoothing algorithms as they are implemented they do no insert new vertices nor remove existing ones. -Selected existing vertices move based only on geometric mesh criteria. +In all cases border vertices are considered constrained and do not move at any step of the procedure. +Also, new vertices are not inserted while mesh or shape smoothing, although degenerate faces are removed as a first step +before the remeshing. Angle and area remeshing algorithms are based on Surazhsky and Gotsman \cgalCite{cgal:sg-hqct-04}. When mesh connectivity is highly irregular, `angle remeshing` may be used with angle weights so that small angles carry more weight and with almost the same computational cost per iteration convergence may be achieved faster. `Area remeshing`, since it considers only triangle areas as a smoothing criterion, may result in long and skinny triangles, especially for meshes with highly irregular connectivity. As such, area remeshing is guaranteed to improve the spatial -distribution of the vertices over the area that is being remeshed. It should be used in combination with angle remeshing -for optimal result. Ideally, an area remeshing step between two angle remeshing steps will offer better result. +distribution of the vertices over the area that is being remeshed. -The curvature flow algorithm for smoothing is based on Desbrun et al \cgalCite{cgal:dmsb-ifamdcf-99}. Curvature flow -smoothes the surface by moving along the surface normal with a speed equal to the mean curvature of the area that is being -smoothed. This means that if the surface is flat around a vertex, this vertex will not move (zero curvature). +The curvature flow algorithm for shape smoothing is based on Desbrun et al \cgalCite{cgal:dmsb-ifamdcf-99}. +Curvature flow smoothes the surface by moving along the surface normal with a speed equal to the mean curvature of the +area that is being smoothed. This means that if the surface is flat around a vertex, this vertex will not move (zero curvature). Curvature flow smoothing offers best results in closed surface meshes, where vertices slide according to the curvature and smooth the shape while the overall volume is being kept constant. From 300897c358454e2e0628822f378ea78f2abdd3b1 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Tue, 22 Aug 2017 19:31:55 +0300 Subject: [PATCH 088/102] corrections in verbose output --- .../CGAL/Polygon_mesh_processing/smoothing.h | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h index 90de3eca586..2c80a67c03e 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h @@ -9,6 +9,7 @@ #include #include +#define CGAL_PMP_REMESHING_VERBOSE #ifdef CGAL_PMP_REMESHING_VERBOSE #include @@ -148,7 +149,6 @@ void angle_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const NamedPara #endif remesher.init_remeshing(faces); - #ifdef CGAL_PMP_REMESHING_VERBOSE t.stop(); std::cout << " done ("<< t.time() <<" sec)." << std::endl; @@ -295,6 +295,7 @@ void area_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const NamedParam internal::Compatible_remesher remesher(pmesh, vpmap, vcmap, ecmap); + #ifdef CGAL_PMP_REMESHING_VERBOSE t.stop(); std::cout << " done ("<< t.time() <<" sec)." << std::endl; @@ -448,17 +449,17 @@ void compatible_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const Name : choose_param(get_param(np, internal_np::edge_is_constrained), internal::Border_constraint_pmap()); - //nb_iterations + // nb_iterations unsigned int nb_iterations = choose_param(get_param(np, internal_np::number_of_iterations), 20); - //use weighted angles + // use weighted angles bool use_weights = choose_param(get_param(np, internal_np::use_weights), false); - //gradient descent precision + // gradient descent precision double gd_precision = choose_param(get_param(np, internal_np::gradient_descent_precision), 0.001); // convergence precision - double dist_precision = choose_param(get_param(np, internal_np::distance_precision), 1); + double dist_precision = choose_param(get_param(np, internal_np::distance_precision), 0.01); internal::Compatible_remesher remesher(pmesh, vpmap, vcmap, ecmap); @@ -504,6 +505,10 @@ void compatible_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const Name count_iterations++; +#ifdef CGAL_PMP_REMESHING_VERBOSE + std::cout<<"iteration:"< From 83beaa300aed028baf38617ced7c9ef9cd86aa0c Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Tue, 22 Aug 2017 19:33:00 +0300 Subject: [PATCH 089/102] plugin improvement --- .../Plugins/PMP/Smoothing_plugin.cpp | 95 +++++- .../Plugins/PMP/Smoothing_plugin.ui | 317 ++++++++++++++---- 2 files changed, 327 insertions(+), 85 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.cpp index 7a1bde0557e..d0b083c0ad7 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.cpp @@ -29,6 +29,7 @@ #include "ui_Smoothing_plugin.h" +using namespace CGAL::Polygon_mesh_processing; using namespace CGAL::Three; class Polyhedron_demo_smothing_plugin : public QObject, @@ -39,6 +40,7 @@ class Polyhedron_demo_smothing_plugin : Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.PluginInterface/1.0") + public: void init(QMainWindow* mainWindow, Scene_interface* scene_interface, Messages_interface*) { @@ -48,7 +50,6 @@ public: actionSmoothing_ = new QAction(tr("Smoothing"), mw); actionSmoothing_->setProperty("subMenuName", "Polygon Mesh Processing"); - connect(actionSmoothing_, SIGNAL(triggered()), this, SLOT(smoothing_action())); dock_widget = new QDockWidget("Smoothing", mw); @@ -57,9 +58,9 @@ public: ui_widget.setupUi(dock_widget); addDockWidget(dock_widget); - //set initial values here - - connect(ui_widget.Apply_button, SIGNAL(clicked()), this, SLOT(on_Apply_clicked())); + connect(ui_widget.Apply_button, SIGNAL(clicked()), this, SLOT(on_Apply_by_type_clicked())); + connect(ui_widget.Curvature_Button, SIGNAL(clicked()), this, SLOT(on_Apply_curvature_clicked())); + connect(ui_widget.Run_convergence_button, SIGNAL(clicked()), this, SLOT(on_Run_convergence_clicked())); } @@ -87,8 +88,31 @@ public: void init_ui() { ui_widget.Angle_spinBox->setValue(1); + ui_widget.Angle_spinBox->setSingleStep(1); + ui_widget.Angle_spinBox->setMinimum(1); + ui_widget.Area_spinBox->setValue(1); - ui_widget.Curvature_spinBox->setValue(1); + ui_widget.Area_spinBox->setSingleStep(1); + ui_widget.Area_spinBox->setMinimum(1); + + ui_widget.gd_dSpinBox->setSingleStep(0.0001); + ui_widget.gd_dSpinBox->setDecimals(4); + ui_widget.gd_dSpinBox->setMinimum(0.0001); + ui_widget.gd_dSpinBox->setValue(0.001); + + ui_widget.use_weights_checkBox->setChecked(true); + + ui_widget.dist_dSpinBox->setValue(0.01); + ui_widget.dist_dSpinBox->setSingleStep(0.0001); + ui_widget.dist_dSpinBox->setDecimals(4); + ui_widget.dist_dSpinBox->setMinimum(0.0001); + + ui_widget.gd_precision_label->setToolTip("Tradeoff between precision and speed. Less is more precise."); + ui_widget.distance_label->setToolTip("Tradeoff between precision and speed. Less is more precise."); + + ui_widget.iterations_spinBox->setValue(20); + ui_widget.iterations_spinBox->setSingleStep(1); + ui_widget.iterations_spinBox->setMinimum(1); } public Q_SLOTS: @@ -106,7 +130,7 @@ public Q_SLOTS: } } - void on_Apply_clicked() + void on_Apply_by_type_clicked() { const Scene_interface::Item_id index = scene->mainSelectionIndex(); Scene_polyhedron_item* poly_item = qobject_cast(scene->item(index)); @@ -117,8 +141,10 @@ public Q_SLOTS: if(ui_widget.Angle_checkBox->isChecked()) { unsigned int nb_iter = ui_widget.Angle_spinBox->value(); - CGAL::Polygon_mesh_processing::angle_remeshing(pmesh, - CGAL::Polygon_mesh_processing::parameters::number_of_iterations(nb_iter)); + bool use_weights = ui_widget.use_weights_checkBox->isChecked(); + angle_remeshing(pmesh, + parameters::number_of_iterations(nb_iter). + use_weights(use_weights)); poly_item->invalidateOpenGLBuffers(); Q_EMIT poly_item->itemChanged(); @@ -127,22 +153,55 @@ public Q_SLOTS: if(ui_widget.Area_checkBox->isChecked()) { unsigned int nb_iter = ui_widget.Area_spinBox->value(); - CGAL::Polygon_mesh_processing::area_remeshing(pmesh, - CGAL::Polygon_mesh_processing::parameters::number_of_iterations(nb_iter)); + double gd_precision = ui_widget.gd_dSpinBox->value(); + area_remeshing(pmesh, + parameters::number_of_iterations(nb_iter). + gradient_descent_precision(gd_precision)); poly_item->invalidateOpenGLBuffers(); Q_EMIT poly_item->itemChanged(); } - if(ui_widget.Curvature_checkBox->isChecked()) - { - unsigned int nb_iter = ui_widget.Curvature_spinBox->value(); - CGAL::Polygon_mesh_processing::curvature_flow(pmesh, - CGAL::Polygon_mesh_processing::parameters::number_of_iterations(nb_iter)); + QApplication::restoreOverrideCursor(); + } - poly_item->invalidateOpenGLBuffers(); - Q_EMIT poly_item->itemChanged(); - } + void on_Apply_curvature_clicked() + { + const Scene_interface::Item_id index = scene->mainSelectionIndex(); + Scene_polyhedron_item* poly_item = qobject_cast(scene->item(index)); + Polyhedron& pmesh = *poly_item->polyhedron(); + + QApplication::setOverrideCursor(Qt::WaitCursor); + + curvature_flow(pmesh); + + poly_item->invalidateOpenGLBuffers(); + Q_EMIT poly_item->itemChanged(); + + QApplication::restoreOverrideCursor(); + } + + void on_Run_convergence_clicked() + { + const Scene_interface::Item_id index = scene->mainSelectionIndex(); + Scene_polyhedron_item* poly_item = qobject_cast(scene->item(index)); + Polyhedron& pmesh = *poly_item->polyhedron(); + + QApplication::setOverrideCursor(Qt::WaitCursor); + + unsigned int nb_iter = ui_widget.iterations_spinBox->value(); + double dist = ui_widget.dist_dSpinBox->value(); + double gd_precision = ui_widget.gd_dSpinBox->value(); + bool use_weights = ui_widget.use_weights_checkBox->isChecked(); + + compatible_remeshing(pmesh, + parameters::number_of_iterations(nb_iter). + distance_precision(dist). + gradient_descent_precision(gd_precision). + use_weights(use_weights)); + + poly_item->invalidateOpenGLBuffers(); + Q_EMIT poly_item->itemChanged(); QApplication::restoreOverrideCursor(); } diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.ui b/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.ui index e42aa033381..afb10372f0c 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.ui +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.ui @@ -6,88 +6,271 @@ 0 0 - 346 - 245 + 451 + 401 - Smoothing options + - + - 60 - 160 - 221 - 51 + 10 + 0 + 431 + 291 - - Apply + + Mesh smoothing + + + + 10 + 30 + 411 + 71 + + + + + 0 + 0 + + + + Qt::LeftToRight + + + Parameters + + + + + 10 + 30 + 386 + 33 + + + + + + + + + Gradient descent precision: + + + + + + + 4 + + + + + + + + + Qt::RightToLeft + + + use weights + + + + + + + + + + 10 + 110 + 411 + 173 + + + + Qt::Horizontal + + + + true + + + Qt::LeftToRight + + + Remeshing by type + + + false + + + false + + + + + + + + area + + + + + + + + + + Type + + + Qt::AlignCenter + + + + + + + Iterations + + + Qt::AlignCenter + + + + + + + + + + + 0 + 0 + + + + angle + + + + + + + + + Apply + + + + + + + + Compatible remeshing algorithm + + + + + + + + Qt::RightToLeft + + + Hausdorff distance: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + 4 + + + + + + + Qt::RightToLeft + + + max iterations: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + + + + + Convergence criteria + + + + + + + + + Run to convergence + + + + + + - + - 20 - 20 - 311 - 131 + 10 + 290 + 431 + 81 - - - - - - - - Curvature flow - - - - - - - angle remeshing - - - - - - - area remeshing - - - - - - - - - - - - - type - - - Qt::AlignCenter - - - - - - - iterations - - - Qt::AlignCenter - - - - + + Shape smoothing + + + + + 90 + 40 + 251 + 28 + + + + Apply curvature flow algorithm + + From 2a7e9e81fdbbbb90c464a4a97cdec9c72e06e7dd Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Wed, 23 Aug 2017 16:37:11 +0300 Subject: [PATCH 090/102] clean curvature flow impl --- .../internal/Smoothing/curvature_flow_impl.h | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/curvature_flow_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/curvature_flow_impl.h index b5e4d830308..0272fa6a826 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/curvature_flow_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/curvature_flow_impl.h @@ -73,19 +73,11 @@ class Curvature_flow typedef Cotangent_weight Weight_calculator; - /* - typedef CGAL::internal::Cotangent_weight > > - Edge_weight_calculator; - */ - public: Curvature_flow(PolygonMesh& pmesh, VertexPointMap& vpmap, VertexConstraintMap& vcmap, EdgeConstraintMap& ecmap) : mesh_(pmesh), vpmap_(vpmap), vcmap_(vcmap), ecmap_(ecmap), weight_calculator_(pmesh, vpmap) - //edge_weight_calculator_(pmesh, vpmap) {} template @@ -132,11 +124,7 @@ public: //check_degeneracy(hi); // weight - //double edge_weight = edge_weight_calculator_(hi); - double angle_weight = weight_calculator_(hi, incd_edges); // to fix - - double weight = angle_weight; // temp - + double weight = weight_calculator_(hi, incd_edges);; sum_cot_weights += weight; // displacement vector @@ -295,7 +283,6 @@ private: GeomTraits traits_; std::set vrange; Weight_calculator weight_calculator_; - //Edge_weight_calculator edge_weight_calculator_; }; From 3fa3d5a4f09893214d1f3e9d87afc725e8520ab4 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Wed, 23 Aug 2017 16:39:16 +0300 Subject: [PATCH 091/102] images in user manual --- .../Polygon_mesh_processing.txt | 17 +++++++++++------ .../doc/Polygon_mesh_processing/examples.txt | 1 - 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt index 1d2960e8880..d964f6e0e9d 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt @@ -121,16 +121,16 @@ Isotropic remeshing. (a) Triangulated input surface mesh. (d) Surface mesh with the selection uniformly remeshed. \cgalFigureEnd -\subsection Smoothing +\subsubsection Smoothing Smoothing of a triangulated mesh area can be achieved with algorithms that aim at either mesh smoothing or shape smoothing. While mesh smoothing is achieved by improving the quality of the triangulated elements based on criteria such as angle and area, shape smoothing is designed to be "intrinsic", depending as little as possible to the discretization -and smoothing the shape only without optimizing the mesh elements. +and smoothing the shape alone without optimizing the mesh elements. For mesh smoothing, `CGAL::Polygon_mesh_processing::angle_remeshing()` may be used to move vertices so that the angles of its incident edges equalize and `CGAL::Polygon_mesh_processing::area_remeshing()` may be used to -move vertices so that the areas of adjacent triangles equalize. Angle and area remeshing are used in combination in +move vertices so that the areas of adjacent triangles equalize. Angle and area remeshing are used combined in `CGAL::Polygon_mesh_processing::compatible_remeshing()` which smooths the mesh until convergence is achieved. For shape smoothing, `CGAL::Polygon_mesh_processing::curvature_flow()` takes into account the mean curvature to calculate a weighted barycenter towards which vertices move incrementally. @@ -139,9 +139,9 @@ Also, new vertices are not inserted while mesh or shape smoothing, although dege before the remeshing. Angle and area remeshing algorithms are based on Surazhsky and Gotsman \cgalCite{cgal:sg-hqct-04}. When mesh connectivity -is highly irregular, `angle remeshing` may be used with angle weights so that small angles carry +is highly irregular, angle remeshing may be used with angle weights so that small angles carry more weight and with almost the same computational cost per iteration convergence may be achieved faster. -`Area remeshing`, since it considers only triangle areas as a smoothing criterion, may result in long and skinny triangles, +Area remeshing, since it considers only triangle areas as a smoothing criterion, may result in long and skinny triangles, especially for meshes with highly irregular connectivity. As such, area remeshing is guaranteed to improve the spatial distribution of the vertices over the area that is being remeshed. @@ -151,7 +151,12 @@ area that is being smoothed. This means that if the surface is flat around a ver Curvature flow smoothing offers best results in closed surface meshes, where vertices slide according to the curvature and smooth the shape while the overall volume is being kept constant. -[[[---to include images---]]] +\cgalFigureBegin{smoothing, smoothing.png} +Mesh and shape smoothing. (a) Elephant before mesh smoothing. +(b) Elephant after applying compatible remeshing for 20 iterations. +(c) Devil before shape smoothing. +(d) Resuted devil after application of curvature flow algorithm. +\cgalFigureEnd \subsection MeshingExamples Meshing Examples diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/examples.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/examples.txt index 8d0ababbfdb..9a2aff0b470 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/examples.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/examples.txt @@ -19,5 +19,4 @@ \example Polygon_mesh_processing/corefinement_mesh_union.cpp \example Polygon_mesh_processing/corefinement_consecutive_bool_op.cpp \example Polygon_mesh_processing/smoothing_example.cpp -\example Polygon_mesh_processing/curvature_flow_example.cpp */ From 1a4e91d095412a37430d7187ab5f790e49705321 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Thu, 24 Aug 2017 22:00:27 +0300 Subject: [PATCH 092/102] fix and clean test files --- .../test_curvature_flow.cpp | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_curvature_flow.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_curvature_flow.cpp index 9c39d9359a9..a67058fdc11 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_curvature_flow.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_curvature_flow.cpp @@ -51,7 +51,9 @@ int main(int argc, char* argv[]){ Mesh mesh; Mesh originalMesh; std::ifstream input; - /*std::ofstream output;*/ +#ifdef CGAL_PMP_REMESHING_VERBOSE + std::ofstream output; +#endif // flat test input.open("data/polygon.off"); @@ -82,17 +84,22 @@ int main(int argc, char* argv[]){ // select half sphere +#ifdef CGAL_PMP_REMESHING_VERBOSE std::cout<<"all faces: "< selected_faces = select(mesh, 0); - std::cout<<"selected faces: "< selected_faces = select(mesh, 0); + +#ifdef CGAL_PMP_REMESHING_VERBOSE + std::cout<<"selected faces: "<(originalMesh, mesh, CGAL::Polygon_mesh_processing::parameters::number_of_points_per_area_unit(1000)); - if(dist > 1e-3) + if(dist > 1e-1) { return EXIT_FAILURE; } - /* +#ifdef CGAL_PMP_REMESHING_VERBOSE output.open("data/half-sphere_smoothed.off"); output << mesh; output.close(); - */ +#endif return 0; } From a9cc924001fda51023c2f5f9254a74f0bb426e4a Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Thu, 24 Aug 2017 22:56:34 +0300 Subject: [PATCH 093/102] renaming functions in API --- .../smoothing_example.cpp | 4 +- .../internal/Smoothing/curvature_flow_impl.h | 5 +- .../internal/Smoothing/smoothing_impl.h | 2 +- .../CGAL/Polygon_mesh_processing/smoothing.h | 158 +++++++++--------- .../Plugins/PMP/Smoothing_plugin.cpp | 8 +- 5 files changed, 85 insertions(+), 92 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/smoothing_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/smoothing_example.cpp index ff5bd0b7c7e..470ba2f9a35 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/smoothing_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/smoothing_example.cpp @@ -21,9 +21,7 @@ int main(int argc, char* argv[]){ return 1; } - CGAL::Polygon_mesh_processing::angle_remeshing(mesh); - CGAL::Polygon_mesh_processing::area_remeshing(mesh); - CGAL::Polygon_mesh_processing::angle_remeshing(mesh); + CGAL::Polygon_mesh_processing::compatible_smoothing(mesh); std::ofstream output("data/eight_smoothed.off"); output << mesh; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/curvature_flow_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/curvature_flow_impl.h index 0272fa6a826..21e51162e43 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/curvature_flow_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/curvature_flow_impl.h @@ -81,7 +81,7 @@ public: {} template - void init_remeshing(const FaceRange& face_range) + void init_smoothing(const FaceRange& face_range) { check_vertex_range(face_range); @@ -202,7 +202,6 @@ private: double angle_min_threshold = 0.05; // rad double angle_max_threshold = CGAL_PI - 0.05; - if(a1 < angle_min_threshold || a2 < angle_min_threshold || a3 < angle_min_threshold) { Euler::remove_face(h1, mesh_); @@ -212,8 +211,6 @@ private: { Euler::remove_face(h1, mesh_); } - - } double get_angle(halfedge_descriptor ha, halfedge_descriptor hb) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h index a84466a9e66..46728661c14 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h @@ -64,7 +64,7 @@ public: } template - void init_remeshing(const FaceRange& face_range) + void init_smoothing(const FaceRange& face_range) { check_vertex_range(face_range); diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h index 2c80a67c03e..17a7a9ba3a4 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h @@ -9,9 +9,8 @@ #include #include -#define CGAL_PMP_REMESHING_VERBOSE -#ifdef CGAL_PMP_REMESHING_VERBOSE +#ifdef CGAL_PMP_SMOOTHING_VERBOSE #include #endif @@ -32,7 +31,6 @@ namespace Polygon_mesh_processing { * constrained vertices so that each pair of adjacent angles becomes equal. * Optionally, small angles may carry more weight than larger ones. Projection * to the initial surface is performed as a last step. -* for better result. * * @tparam PolygonMesh model of `MutableFaceGraph`. * The descriptor types `boost::graph_traits::%face_descriptor` @@ -40,14 +38,14 @@ namespace Polygon_mesh_processing { * models of `Hashable`. * If `PolygonMesh` has an internal property map for `CGAL::face_index_t`, * and no `face_index_map` is given -* as a named parameter, then the internal one should be initialized +* as a named parameter, then the internal one should be initialized. * @tparam FaceRange range of `boost::graph_traits::%face_descriptor`, model of `Range`. Its iterator type is `ForwardIterator`. -* @tparam NamedParameters a sequence of \ref namedparameters +* @tparam NamedParameters a sequence of \ref namedparameters. * -* @param pmesh a polygon mesh with triangulated surface patches to be remeshed -* @param faces the range of triangular faces defining one or several surface patches to be remeshed -* @param np optional sequence of \ref namedparameters among the ones listed below +* @param pmesh a polygon mesh with triangulated surface patches to be smoothed. +* @param faces the range of triangular faces defining one or several surface patches to be smoothed. +* @param np optional sequence of \ref namedparameters among the ones listed below. * * \cgalNamedParamsBegin * \cgalParamBegin{geom_traits} a geometric traits class instance, model of `Kernel`. @@ -74,14 +72,14 @@ namespace Polygon_mesh_processing { * \cgalNamedParamsEnd */ template -void angle_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const NamedParameters& np) +void angle_smoothing(PolygonMesh& pmesh, const FaceRange& faces, const NamedParameters& np) { using boost::choose_param; using boost::get_param; -#ifdef CGAL_PMP_REMESHING_VERBOSE +#ifdef CGAL_PMP_SMOOTHING_VERBOSE CGAL::Timer t; - std::cout << "Remeshing parameters..."; + std::cout << "Smoothing parameters..."; std::cout.flush(); t.start(); #endif @@ -133,7 +131,7 @@ void angle_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const NamedPara internal::Compatible_remesher remesher(pmesh, vpmap, vcmap, ecmap); -#ifdef CGAL_PMP_REMESHING_VERBOSE +#ifdef CGAL_PMP_SMOOTHING_VERBOSE t.stop(); std::cout << " done ("<< t.time() <<" sec)." << std::endl; std::cout << "Removing degenerate faces..." << std::endl; @@ -141,26 +139,26 @@ void angle_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const NamedPara #endif remesher.remove_degenerate_faces(); -#ifdef CGAL_PMP_REMESHING_VERBOSE +#ifdef CGAL_PMP_SMOOTHING_VERBOSE t.stop(); std::cout << " done ("<< t.time() <<" sec)." << std::endl; std::cout << "Initializing..." << std::endl; t.reset(); t.start(); #endif - remesher.init_remeshing(faces); + remesher.init_smoothing(faces); -#ifdef CGAL_PMP_REMESHING_VERBOSE +#ifdef CGAL_PMP_SMOOTHING_VERBOSE t.stop(); std::cout << " done ("<< t.time() <<" sec)." << std::endl; std::cout << "#iter = " << nb_iterations << std::endl; - std::cout << "Remeshing ..." << std::endl; + std::cout << "Smoothing ..." << std::endl; t.reset(); t.start(); #endif for(unsigned int i=0; i -void angle_remeshing(PolygonMesh& pmesh, const NamedParameters& np) +void angle_smoothing(PolygonMesh& pmesh, const NamedParameters& np) { - angle_remeshing(pmesh, faces(pmesh), np); + angle_smoothing(pmesh, faces(pmesh), np); } template -void angle_remeshing(PolygonMesh& pmesh) +void angle_smoothing(PolygonMesh& pmesh) { - angle_remeshing(pmesh, faces(pmesh), parameters::all_default()); + angle_smoothing(pmesh, faces(pmesh), parameters::all_default()); } /*! @@ -203,14 +201,14 @@ void angle_remeshing(PolygonMesh& pmesh) * models of `Hashable`. * If `PolygonMesh` has an internal property map for `CGAL::face_index_t`, * and no `face_index_map` is given -* as a named parameter, then the internal one should be initialized +* as a named parameter, then the internal one should be initialized. * @tparam FaceRange range of `boost::graph_traits::%face_descriptor`, model of `Range`. Its iterator type is `ForwardIterator`. * @tparam NamedParameters a sequence of \ref namedparameters * -* @param pmesh a polygon mesh with triangulated surface patches to be remeshed -* @param faces the range of triangular faces defining one or several surface patches to be remeshed -* @param np optional sequence of \ref namedparameters among the ones listed below +* @param pmesh a polygon mesh with triangulated surface patches to be smoothed. +* @param faces the range of triangular faces defining one or several surface patches to be smoothed. +* @param np optional sequence of \ref namedparameters among the ones listed below. * * \cgalNamedParamsBegin * \cgalParamBegin{geom_traits} a geometric traits class instance, model of `Kernel`. @@ -240,14 +238,14 @@ void angle_remeshing(PolygonMesh& pmesh) * \cgalNamedParamsEnd */ template -void area_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const NamedParameters& np) +void area_smoothing(PolygonMesh& pmesh, const FaceRange& faces, const NamedParameters& np) { using boost::choose_param; using boost::get_param; -#ifdef CGAL_PMP_REMESHING_VERBOSE +#ifdef CGAL_PMP_SMOOTHING_VERBOSE CGAL::Timer t; - std::cout << "Remeshing parameters..."; + std::cout << "Smoothing parameters..."; std::cout.flush(); t.start(); #endif @@ -296,7 +294,7 @@ void area_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const NamedParam internal::Compatible_remesher remesher(pmesh, vpmap, vcmap, ecmap); -#ifdef CGAL_PMP_REMESHING_VERBOSE +#ifdef CGAL_PMP_SMOOTHING_VERBOSE t.stop(); std::cout << " done ("<< t.time() <<" sec)." << std::endl; std::cout << "Removing degenerate faces..." << std::endl; @@ -304,26 +302,26 @@ void area_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const NamedParam #endif remesher.remove_degenerate_faces(); -#ifdef CGAL_PMP_REMESHING_VERBOSE +#ifdef CGAL_PMP_SMOOTHING_VERBOSE t.stop(); std::cout << " done ("<< t.time() <<" sec)." << std::endl; std::cout << "Initializing..." << std::endl; t.reset(); t.start(); #endif - remesher.init_remeshing(faces); + remesher.init_smoothing(faces); -#ifdef CGAL_PMP_REMESHING_VERBOSE +#ifdef CGAL_PMP_SMOOTHING_VERBOSE t.stop(); std::cout << " done ("<< t.time() <<" sec)." << std::endl; std::cout << "#iter = " << nb_iterations << std::endl; - std::cout << "Remeshing ..." << std::endl; + std::cout << "Smoothing ..." << std::endl; t.reset(); t.start(); #endif for(unsigned int i=0; i -void area_remeshing(PolygonMesh& pmesh, const NamedParameters& np) +void area_smoothing(PolygonMesh& pmesh, const NamedParameters& np) { - area_remeshing(pmesh, faces(pmesh), np); + area_smoothing(pmesh, faces(pmesh), np); } template -void area_remeshing(PolygonMesh& pmesh) +void area_smoothing(PolygonMesh& pmesh) { - area_remeshing(pmesh, faces(pmesh), parameters::all_default()); + area_smoothing(pmesh, faces(pmesh), parameters::all_default()); } /*! @@ -365,14 +363,14 @@ void area_remeshing(PolygonMesh& pmesh) * models of `Hashable`. * If `PolygonMesh` has an internal property map for `CGAL::face_index_t`, * and no `face_index_map` is given -* as a named parameter, then the internal one should be initialized +* as a named parameter, then the internal one should be initialized. * @tparam FaceRange range of `boost::graph_traits::%face_descriptor`, model of `Range`. Its iterator type is `ForwardIterator`. * @tparam NamedParameters a sequence of \ref namedparameters * -* @param pmesh a polygon mesh with triangulated surface patches to be remeshed -* @param faces the range of triangular faces defining one or several surface patches to be remeshed -* @param np optional sequence of \ref namedparameters among the ones listed below +* @param pmesh a polygon mesh with triangulated surface patches to be smoothed. +* @param faces the range of triangular faces defining one or several surface patches to be smoothed. +* @param np optional sequence of \ref namedparameters among the ones listed below. * * \cgalNamedParamsBegin * \cgalParamBegin{geom_traits} a geometric traits class instance, model of `Kernel`. @@ -402,14 +400,14 @@ void area_remeshing(PolygonMesh& pmesh) * \cgalNamedParamsEnd */ template -void compatible_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const NamedParameters& np) +void compatible_smoothing(PolygonMesh& pmesh, const FaceRange& faces, const NamedParameters& np) { using boost::choose_param; using boost::get_param; -#ifdef CGAL_PMP_REMESHING_VERBOSE +#ifdef CGAL_PMP_SMOOTHING_VERBOSE CGAL::Timer t; - std::cout << "Remeshing parameters..."; + std::cout << "Smoothing parameters..."; std::cout.flush(); t.start(); #endif @@ -464,7 +462,7 @@ void compatible_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const Name internal::Compatible_remesher remesher(pmesh, vpmap, vcmap, ecmap); -#ifdef CGAL_PMP_REMESHING_VERBOSE +#ifdef CGAL_PMP_SMOOTHING_VERBOSE t.stop(); std::cout << " done ("<< t.time() <<" sec)." << std::endl; std::cout << "Removing degenerate faces..." << std::endl; @@ -472,20 +470,20 @@ void compatible_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const Name #endif remesher.remove_degenerate_faces(); -#ifdef CGAL_PMP_REMESHING_VERBOSE +#ifdef CGAL_PMP_SMOOTHING_VERBOSE t.stop(); std::cout << " done ("<< t.time() <<" sec)." << std::endl; std::cout << "Initializing..." << std::endl; t.reset(); t.start(); #endif - remesher.init_remeshing(faces); + remesher.init_smoothing(faces); -#ifdef CGAL_PMP_REMESHING_VERBOSE +#ifdef CGAL_PMP_SMOOTHING_VERBOSE t.stop(); std::cout << " done ("<< t.time() <<" sec)." << std::endl; std::cout << "#iter = " << nb_iterations << std::endl; - std::cout << "Remeshing ..." << std::endl; + std::cout << "Smoothing ..." << std::endl; t.reset(); t.start(); #endif @@ -505,16 +503,16 @@ void compatible_remeshing(PolygonMesh& pmesh, const FaceRange& faces, const Name count_iterations++; -#ifdef CGAL_PMP_REMESHING_VERBOSE +#ifdef CGAL_PMP_SMOOTHING_VERBOSE std::cout<<"iteration:"< -void compatible_remeshing(PolygonMesh& pmesh, const NamedParameters& np) +void compatible_smoothing(PolygonMesh& pmesh, const NamedParameters& np) { - compatible_remeshing(pmesh, faces(pmesh), np); + compatible_smoothing(pmesh, faces(pmesh), np); } template -void compatible_remeshing(PolygonMesh& pmesh) +void compatible_smoothing(PolygonMesh& pmesh) { - compatible_remeshing(pmesh, faces(pmesh), parameters::all_default()); + compatible_smoothing(pmesh, faces(pmesh), parameters::all_default()); } @@ -564,9 +562,9 @@ void compatible_remeshing(PolygonMesh& pmesh) model of `Range`. Its iterator type is `ForwardIterator`. * @tparam NamedParameters a sequence of \ref namedparameters * -* @param pmesh a polygon mesh with triangulated surface patches to be remeshed -* @param faces the range of triangular faces defining one or several surface patches to be remeshed -* @param np optional sequence of \ref namedparameters among the ones listed below +* @param pmesh a polygon mesh with triangulated surface patches to be smoothed. +* @param faces the range of triangular faces defining one or several surface patches to be smoothed. +* @param np optional sequence of \ref namedparameters among the ones listed below. * * \cgalNamedParamsBegin * \cgalParamBegin{geom_traits} a geometric traits class instance, model of `Kernel`. @@ -588,14 +586,14 @@ void compatible_remeshing(PolygonMesh& pmesh) * \cgalNamedParamsEnd */ template -void curvature_flow(PolygonMesh& pmesh, const FaceRange& faces, const NamedParameters& np) +void curvature_flow_smoothing(PolygonMesh& pmesh, const FaceRange& faces, const NamedParameters& np) { using boost::choose_param; using boost::get_param; -#ifdef CGAL_PMP_REMESHING_VERBOSE +#ifdef CGAL_PMP_SMOOTHING_VERBOSE CGAL::Timer t; - std::cout << "Remeshing parameters..."; + std::cout << "Smoothing parameters..."; std::cout.flush(); t.start(); #endif @@ -638,9 +636,9 @@ void curvature_flow(PolygonMesh& pmesh, const FaceRange& faces, const NamedParam // nb_iterations unsigned int nb_iterations = choose_param(get_param(np, internal_np::number_of_iterations), 1); -#ifdef CGAL_PMP_REMESHING_VERBOSE +#ifdef CGAL_PMP_SMOOTHING_VERBOSE t.stop(); - std::cout << "\rRemeshing parameters done ("<< t.time() <<" sec)" << std::endl; + std::cout << "\rSmoothing parameters done ("<< t.time() <<" sec)" << std::endl; std::cout << "Remesher construction..."; std::cout.flush(); t.reset(); t.start(); @@ -648,7 +646,7 @@ void curvature_flow(PolygonMesh& pmesh, const FaceRange& faces, const NamedParam internal::Curvature_flow curvature_remesher(pmesh, vpmap, vcmap, ecmap); -#ifdef CGAL_PMP_REMESHING_VERBOSE +#ifdef CGAL_PMP_SMOOTHING_VERBOSE t.stop(); std::cout << " done ("<< t.time() <<" sec)." << std::endl; std::cout << "Removing degenerate faces..." << std::endl; @@ -657,16 +655,16 @@ void curvature_flow(PolygonMesh& pmesh, const FaceRange& faces, const NamedParam curvature_remesher.remove_degenerate_faces(); -#ifdef CGAL_PMP_REMESHING_VERBOSE +#ifdef CGAL_PMP_SMOOTHING_VERBOSE t.stop(); std::cout << " done ("<< t.time() <<" sec)." << std::endl; std::cout << "Initializing..." << std::endl; t.reset(); t.start(); #endif - curvature_remesher.init_remeshing(faces); + curvature_remesher.init_smoothing(faces); -#ifdef CGAL_PMP_REMESHING_VERBOSE +#ifdef CGAL_PMP_SMOOTHING_VERBOSE t.stop(); std::cout << " done ("<< t.time() <<" sec)." << std::endl; std::cout << "Shape smoothing..." << std::endl; @@ -675,7 +673,7 @@ void curvature_flow(PolygonMesh& pmesh, const FaceRange& faces, const NamedParam curvature_remesher.curvature_smoothing(); -#ifdef CGAL_PMP_REMESHING_VERBOSE +#ifdef CGAL_PMP_SMOOTHING_VERBOSE t.stop(); std::cout << "Shape smoothing done in "; std::cout << t.time() << " sec." << std::endl; @@ -685,15 +683,15 @@ void curvature_flow(PolygonMesh& pmesh, const FaceRange& faces, const NamedParam } template -void curvature_flow(PolygonMesh& pmesh, const NamedParameters& np) +void curvature_flow_smoothing(PolygonMesh& pmesh, const NamedParameters& np) { - curvature_flow(pmesh, faces(pmesh), np); + curvature_flow_smoothing(pmesh, faces(pmesh), np); } template -void curvature_flow(PolygonMesh& pmesh) +void curvature_flow_smoothing(PolygonMesh& pmesh) { - curvature_flow(pmesh, parameters::all_default()); + curvature_flow_smoothing(pmesh, parameters::all_default()); } diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.cpp index d0b083c0ad7..4ab12445cf9 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.cpp @@ -142,7 +142,7 @@ public Q_SLOTS: { unsigned int nb_iter = ui_widget.Angle_spinBox->value(); bool use_weights = ui_widget.use_weights_checkBox->isChecked(); - angle_remeshing(pmesh, + angle_smoothing(pmesh, parameters::number_of_iterations(nb_iter). use_weights(use_weights)); @@ -154,7 +154,7 @@ public Q_SLOTS: { unsigned int nb_iter = ui_widget.Area_spinBox->value(); double gd_precision = ui_widget.gd_dSpinBox->value(); - area_remeshing(pmesh, + area_smoothing(pmesh, parameters::number_of_iterations(nb_iter). gradient_descent_precision(gd_precision)); @@ -173,7 +173,7 @@ public Q_SLOTS: QApplication::setOverrideCursor(Qt::WaitCursor); - curvature_flow(pmesh); + curvature_flow_smoothing(pmesh); poly_item->invalidateOpenGLBuffers(); Q_EMIT poly_item->itemChanged(); @@ -194,7 +194,7 @@ public Q_SLOTS: double gd_precision = ui_widget.gd_dSpinBox->value(); bool use_weights = ui_widget.use_weights_checkBox->isChecked(); - compatible_remeshing(pmesh, + compatible_smoothing(pmesh, parameters::number_of_iterations(nb_iter). distance_precision(dist). gradient_descent_precision(gd_precision). From 897692bc1634e496631d07fbe1e75fff9773eccf Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Thu, 24 Aug 2017 23:38:25 +0300 Subject: [PATCH 094/102] document overloads --- .../CGAL/Polygon_mesh_processing/smoothing.h | 239 +++++++++++++++++- .../test_curvature_flow.cpp | 4 +- .../test_smoothing.cpp | 4 +- 3 files changed, 242 insertions(+), 5 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h index 17a7a9ba3a4..aa4dab9f8a2 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h @@ -175,12 +175,66 @@ void angle_smoothing(PolygonMesh& pmesh, const FaceRange& faces, const NamedPara } +/*! +* \ingroup PMP_meshing_grp +* @brief angle smoothing on all faces of the mesh. +* +* @tparam PolygonMesh model of `MutableFaceGraph`. +* The descriptor types `boost::graph_traits::%face_descriptor` +* and `boost::graph_traits::%halfedge_descriptor` must be +* models of `Hashable`. +* If `PolygonMesh` has an internal property map for `CGAL::face_index_t`, +* and no `face_index_map` is given +* as a named parameter, then the internal one should be initialized. +* @tparam NamedParameters a sequence of \ref namedparameters. +* +* @param pmesh a polygon mesh with triangulated surface patches to be smoothed. +* @param np optional sequence of \ref namedparameters among the ones listed below. +* +* \cgalNamedParamsBegin +* \cgalParamBegin{geom_traits} a geometric traits class instance, model of `Kernel`. +* Exact constructions kernels are not supported by this function. +* \cgalParamEnd +* \cgalParamBegin{vertex_point_map} the property map with the points associated +* to the vertices of `pmesh`. Instance of a class model of `ReadWritePropertyMap`. +* \cgalParamEnd +* \cgalParamBegin{face_index_map} a property map containing the index of each face of `pmesh`. +* \cgalParamEnd +* \cgalParamBegin{number_of_iterations} the number of iterations for the +* sequence of the smoothing iterations performed. +* \cgalParamEnd +* \cgalParamBegin{edge_is_constrained_map} a property map containing the +* constrained-or-not status of each edge of `pmesh`. Vertices that belong to constrained +* edges are not modified at all during smoothing. +* \cgalParamEnd +* \cgalParamBegin{vertex_is_constrained_map} a property map containing the +* constrained-or-not status of each vertex of `pmesh`. A constrained vertex +* cannot be modified at all during smoothing. +* \cgalParamEnd +* \cgalParamBegin{use_weights} If `true`, small angles carry more weight than larger ones. +* \cgalParamEnd +* \cgalNamedParamsEnd +*/ template void angle_smoothing(PolygonMesh& pmesh, const NamedParameters& np) { angle_smoothing(pmesh, faces(pmesh), np); } +/*! +* \ingroup PMP_meshing_grp +* @brief angle smoothing on all faces of the mesh. +* +* @tparam PolygonMesh model of `MutableFaceGraph`. +* The descriptor types `boost::graph_traits::%face_descriptor` +* and `boost::graph_traits::%halfedge_descriptor` must be +* models of `Hashable`. +* If `PolygonMesh` has an internal property map for `CGAL::face_index_t`, +* and no `face_index_map` is given +* as a named parameter, then the internal one should be initialized. +* +* @param pmesh a polygon mesh with triangulated surface patches to be smoothed. +*/ template void angle_smoothing(PolygonMesh& pmesh) { @@ -337,12 +391,70 @@ void area_smoothing(PolygonMesh& pmesh, const FaceRange& faces, const NamedParam } +/*! +* \ingroup PMP_meshing_grp +* @brief area smoothing on all faces of the mesh. +* +* @tparam PolygonMesh model of `MutableFaceGraph`. +* The descriptor types `boost::graph_traits::%face_descriptor` +* and `boost::graph_traits::%halfedge_descriptor` must be +* models of `Hashable`. +* If `PolygonMesh` has an internal property map for `CGAL::face_index_t`, +* and no `face_index_map` is given +* as a named parameter, then the internal one should be initialized. +* @tparam NamedParameters a sequence of \ref namedparameters +* +* @param pmesh a polygon mesh with triangulated surface patches to be smoothed. +* @param np optional sequence of \ref namedparameters among the ones listed below. +* +* \cgalNamedParamsBegin +* \cgalParamBegin{geom_traits} a geometric traits class instance, model of `Kernel`. +* Exact constructions kernels are not supported by this function. +* \cgalParamEnd +* \cgalParamBegin{vertex_point_map} the property map with the points associated +* to the vertices of `pmesh`. Instance of a class model of `ReadWritePropertyMap`. +* \cgalParamEnd +* \cgalParamBegin{face_index_map} a property map containing the index of each face of `pmesh`. +* \cgalParamEnd +* \cgalParamBegin{number_of_iterations} the number of iterations for the +* sequence of the smoothing iterations performed. +* \cgalParamEnd +* \cgalParamBegin{edge_is_constrained_map} a property map containing the +* constrained-or-not status of each edge of `pmesh`. Vertices that belong to constrained +* edges are not modified at all during smoothing. +* \cgalParamEnd +* \cgalParamBegin{vertex_is_constrained_map} a property map containing the +* constrained-or-not status of each vertex of `pmesh`. A constrained vertex +* cannot be modified at all during smoothing. +* \cgalParamEnd +* \cgalParamBegin{gradient_descent_precision} The precision which is met during gradient descent refers to +* the relative energy between iterations of each triangle element which is minimized +* while one of its vertices is being moved. Triangle energy is defined based on its area compared to +* the average area of all triangles adjacent to the vertex that is being moved. Defaults to 0.001. +* \cgalParamEnd +* \cgalNamedParamsEnd +*/ template void area_smoothing(PolygonMesh& pmesh, const NamedParameters& np) { area_smoothing(pmesh, faces(pmesh), np); } +/*! +* \ingroup PMP_meshing_grp +* @brief area smoothing on all faces of the mesh. +* +* @tparam PolygonMesh model of `MutableFaceGraph`. +* The descriptor types `boost::graph_traits::%face_descriptor` +* and `boost::graph_traits::%halfedge_descriptor` must be +* models of `Hashable`. +* If `PolygonMesh` has an internal property map for `CGAL::face_index_t`, +* and no `face_index_map` is given +* as a named parameter, then the internal one should be initialized. +* +* @param pmesh a polygon mesh with triangulated surface patches to be smoothed. +* +*/ template void area_smoothing(PolygonMesh& pmesh) { @@ -534,12 +646,70 @@ void compatible_smoothing(PolygonMesh& pmesh, const FaceRange& faces, const Name } + +/*! +* \ingroup PMP_meshing_grp +* @brief compatible smoothing on all faces of the mesh. +* +* @tparam PolygonMesh model of `MutableFaceGraph`. +* The descriptor types `boost::graph_traits::%face_descriptor` +* and `boost::graph_traits::%halfedge_descriptor` must be +* models of `Hashable`. +* If `PolygonMesh` has an internal property map for `CGAL::face_index_t`, +* and no `face_index_map` is given +* as a named parameter, then the internal one should be initialized. +* @tparam NamedParameters a sequence of \ref namedparameters +* +* @param pmesh a polygon mesh with triangulated surface patches to be smoothed. +* @param np optional sequence of \ref namedparameters among the ones listed below. +* +* \cgalNamedParamsBegin +* \cgalParamBegin{geom_traits} a geometric traits class instance, model of `Kernel`. +* Exact constructions kernels are not supported by this function. +* \cgalParamEnd +* \cgalParamBegin{vertex_point_map} the property map with the points associated +* to the vertices of `pmesh`. Instance of a class model of `ReadWritePropertyMap`. +* \cgalParamEnd +* \cgalParamBegin{face_index_map} a property map containing the index of each face of `pmesh`. +* \cgalParamEnd +* \cgalParamBegin{number_of_iterations} the maximum number of iterations for the +* sequence of smoothing iterations performed. +* \cgalParamEnd +* \cgalParamBegin{edge_is_constrained_map} a property map containing the +* constrained-or-not status of each edge of `pmesh`. Vertices that belong to constrained +* edges are not modified at all during smoothing. +* \cgalParamEnd +* \cgalParamBegin{vertex_is_constrained_map} a property map containing the +* constrained-or-not status of each vertex of `pmesh`. A constrained vertex +* cannot be modified at all during smoothing. +* \cgalParamEnd +* \cgalParamBegin{use_weights} If `true`, small angles carry more weight than larger ones. +* \cgalParamEnd +* \cgalParamBegin{distance_precision} The Hausdorff distance between the mesh of the previous and the curent iteration. +* Defaults to 0.01. +* \cgalParamEnd +* \cgalNamedParamsEnd +*/ template void compatible_smoothing(PolygonMesh& pmesh, const NamedParameters& np) { compatible_smoothing(pmesh, faces(pmesh), np); } +/*! +* \ingroup PMP_meshing_grp +* @brief compatible smoothing on all faces of the mesh. +* +* @tparam PolygonMesh model of `MutableFaceGraph`. +* The descriptor types `boost::graph_traits::%face_descriptor` +* and `boost::graph_traits::%halfedge_descriptor` must be +* models of `Hashable`. +* If `PolygonMesh` has an internal property map for `CGAL::face_index_t`, +* and no `face_index_map` is given +* as a named parameter, then the internal one should be initialized. +* +* @param pmesh a polygon mesh with triangulated surface patches to be smoothed. +*/ template void compatible_smoothing(PolygonMesh& pmesh) { @@ -549,7 +719,9 @@ void compatible_smoothing(PolygonMesh& pmesh) /*! * \ingroup PMP_meshing_grp -* @brief todo +* @brief smooths the overall shape of the mesh by using +* the mean curvature flow to calculate and apply an operator to mesh vertices. +* The effect depends only on the curvature of each area. * * @tparam PolygonMesh model of `MutableFaceGraph`. * The descriptor types `boost::graph_traits::%face_descriptor` @@ -573,6 +745,9 @@ void compatible_smoothing(PolygonMesh& pmesh) * \cgalParamBegin{vertex_point_map} the property map with the points associated * to the vertices of `pmesh`. Instance of a class model of `ReadWritePropertyMap`. * \cgalParamEnd +* \cgalParamBegin{number_of_iterations} the number of iterations for the +* sequence of the smoothing iterations performed. +* \cgalParamEnd * \cgalParamBegin{face_index_map} a property map containing the index of each face of `pmesh`. * \cgalParamEnd * \cgalParamBegin{edge_is_constrained_map} a property map containing the @@ -667,12 +842,22 @@ void curvature_flow_smoothing(PolygonMesh& pmesh, const FaceRange& faces, const #ifdef CGAL_PMP_SMOOTHING_VERBOSE t.stop(); std::cout << " done ("<< t.time() <<" sec)." << std::endl; + std::cout << "#iter = " << nb_iterations << std::endl; std::cout << "Shape smoothing..." << std::endl; t.reset(); t.start(); #endif + for(unsigned int i=0; i::%face_descriptor` +* and `boost::graph_traits::%halfedge_descriptor` must be +* models of `Hashable`. +* If `PolygonMesh` has an internal property map for `CGAL::face_index_t`, +* and no `face_index_map` is given +* as a named parameter, then the internal one should be initialized +* @tparam NamedParameters a sequence of \ref namedparameters +* +* @param pmesh a polygon mesh with triangulated surface patches to be smoothed. +* @param np optional sequence of \ref namedparameters among the ones listed below. +* +* \cgalNamedParamsBegin +* \cgalParamBegin{geom_traits} a geometric traits class instance, model of `Kernel`. +* Exact constructions kernels are not supported by this function. +* \cgalParamEnd +* \cgalParamBegin{vertex_point_map} the property map with the points associated +* to the vertices of `pmesh`. Instance of a class model of `ReadWritePropertyMap`. +* \cgalParamEnd +* \cgalParamBegin{number_of_iterations} the number of iterations for the +* sequence of the smoothing iterations performed. +* \cgalParamEnd +* \cgalParamBegin{face_index_map} a property map containing the index of each face of `pmesh`. +* \cgalParamEnd +* \cgalParamBegin{edge_is_constrained_map} a property map containing the +* constrained-or-not status of each edge of `pmesh`. Vertices that belong to constrained +* edges are not modified at all during smoothing. +* \cgalParamEnd +* \cgalParamBegin{vertex_is_constrained_map} a property map containing the +* constrained-or-not status of each vertex of `pmesh`. A constrained vertex +* cannot be modified at all during smoothing. +* \cgalParamEnd +* \cgalNamedParamsEnd +*/ template void curvature_flow_smoothing(PolygonMesh& pmesh, const NamedParameters& np) { curvature_flow_smoothing(pmesh, faces(pmesh), np); } +/*! +* \ingroup PMP_meshing_grp +* @brief curvature flow smoothing on all faces of the mesh. +* +* @tparam PolygonMesh model of `MutableFaceGraph`. +* The descriptor types `boost::graph_traits::%face_descriptor` +* and `boost::graph_traits::%halfedge_descriptor` must be +* models of `Hashable`. +* If `PolygonMesh` has an internal property map for `CGAL::face_index_t`, +* and no `face_index_map` is given +* as a named parameter, then the internal one should be initialized +* +* @param pmesh a polygon mesh with triangulated surface patches to be smoothed. +*/ template void curvature_flow_smoothing(PolygonMesh& pmesh) { diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_curvature_flow.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_curvature_flow.cpp index a67058fdc11..7334f228ca8 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_curvature_flow.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_curvature_flow.cpp @@ -64,7 +64,7 @@ int main(int argc, char* argv[]){ input.close(); originalMesh = mesh; - CGAL::Polygon_mesh_processing::curvature_flow(mesh); + CGAL::Polygon_mesh_processing::curvature_flow_smoothing(mesh); double dist = CGAL::Polygon_mesh_processing::approximate_Hausdorff_distance (originalMesh, mesh, CGAL::Polygon_mesh_processing::parameters::number_of_points_per_area_unit(1000)); @@ -102,7 +102,7 @@ int main(int argc, char* argv[]){ #endif originalMesh = mesh; - CGAL::Polygon_mesh_processing::curvature_flow(mesh); + CGAL::Polygon_mesh_processing::curvature_flow_smoothing(mesh); dist = CGAL::Polygon_mesh_processing::approximate_Hausdorff_distance (originalMesh, mesh, CGAL::Polygon_mesh_processing::parameters::number_of_points_per_area_unit(1000)); diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_smoothing.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_smoothing.cpp index 846fb9a1e9a..7cb6e7ed43c 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_smoothing.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_smoothing.cpp @@ -107,7 +107,7 @@ int main(int argc, char* argv[]){ calc_angles(mesh, min_a, max_a, mean_a); - CGAL::Polygon_mesh_processing::angle_remeshing(mesh); + CGAL::Polygon_mesh_processing::angle_smoothing(mesh); calc_angles(mesh, min_a, max_a, mean_a); if(!check_value_equal(min_a, 24.980)) @@ -123,7 +123,7 @@ int main(int argc, char* argv[]){ input>>mesh; input.close(); - CGAL::Polygon_mesh_processing::area_remeshing(mesh); + CGAL::Polygon_mesh_processing::area_smoothing(mesh); calc_areas(mesh, min_a, max_a, mean_a); if(!check_value_equal(min_a, 0.476)) From dee4c4d86486dd6104b33e065922a59b28d84747 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Thu, 24 Aug 2017 23:59:41 +0300 Subject: [PATCH 095/102] demo plugin: add iterations spinbox for curvature flow --- .../Plugins/PMP/Smoothing_plugin.cpp | 8 ++++- .../Plugins/PMP/Smoothing_plugin.ui | 36 +++++++++++++++---- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.cpp index 4ab12445cf9..0bfbde35fcf 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.cpp @@ -113,6 +113,10 @@ public: ui_widget.iterations_spinBox->setValue(20); ui_widget.iterations_spinBox->setSingleStep(1); ui_widget.iterations_spinBox->setMinimum(1); + + ui_widget.curv_iterations_spinBox->setValue(1); + ui_widget.curv_iterations_spinBox->setSingleStep(1); + ui_widget.curv_iterations_spinBox->setMinimum(1); } public Q_SLOTS: @@ -173,7 +177,9 @@ public Q_SLOTS: QApplication::setOverrideCursor(Qt::WaitCursor); - curvature_flow_smoothing(pmesh); + unsigned int nb_iter = ui_widget.curv_iterations_spinBox->value(); + curvature_flow_smoothing(pmesh, + parameters::number_of_iterations(nb_iter)); poly_item->invalidateOpenGLBuffers(); Q_EMIT poly_item->itemChanged(); diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.ui b/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.ui index afb10372f0c..d0afa00d790 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.ui +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Smoothing_plugin.ui @@ -7,7 +7,7 @@ 0 0 451 - 401 + 392 @@ -47,7 +47,7 @@ Parameters - + 10 @@ -252,7 +252,7 @@ 10 290 431 - 81 + 71 @@ -261,16 +261,38 @@ - 90 - 40 - 251 - 28 + 20 + 30 + 241 + 31 Apply curvature flow algorithm + + + + 282 + 30 + 121 + 31 + + + + + + + Iterations: + + + + + + + + From c840481b8c4875de8d0a2e68dd681a5763697f53 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Sat, 26 Aug 2017 10:12:37 +0300 Subject: [PATCH 096/102] License --- .../internal/Smoothing/curvature_flow_impl.h | 20 +++++++++++ .../internal/Smoothing/smoothing_impl.h | 22 ++++++++++-- .../CGAL/Polygon_mesh_processing/smoothing.h | 36 ++++++++++++++----- 3 files changed, 68 insertions(+), 10 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/curvature_flow_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/curvature_flow_impl.h index 21e51162e43..8099a3e71d8 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/curvature_flow_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/curvature_flow_impl.h @@ -1,3 +1,23 @@ +// Copyright (c) 2015 GeometryFactory (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// +// Author(s) : Konstantinos Katrioplas (konst.katrioplas@gmail.com) + #ifndef CURVATURE_FLOW_IMPL_H #define CURVATURE_FLOW_IMPL_H diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h index 46728661c14..0fd7fb480a4 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/smoothing_impl.h @@ -1,8 +1,26 @@ +// Copyright (c) 2015 GeometryFactory (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// +// Author(s) : Konstantinos Katrioplas (konst.katrioplas@gmail.com) + #ifndef CGAL_POLYGON_MESH_PROCESSING_SMOOTHING_IMPL_H #define CGAL_POLYGON_MESH_PROCESSING_SMOOTHING_IMPL_H - -#include #include #include #include diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h index aa4dab9f8a2..9a6ff0a7a6b 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/smoothing.h @@ -1,3 +1,23 @@ +// Copyright (c) 2015 GeometryFactory (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// You can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any later version. +// +// Licensees holding a valid commercial license may use this file in +// accordance with the commercial license agreement provided with the software. +// +// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// $URL$ +// $Id$ +// +// +// Author(s) : Konstantinos Katrioplas (konst.katrioplas@gmail.com) + #ifndef CGAL_POLYGON_MESH_PROCESSING_SMOOTHING_H #define CGAL_POLYGON_MESH_PROCESSING_SMOOTHING_H @@ -623,10 +643,10 @@ void compatible_smoothing(PolygonMesh& pmesh, const FaceRange& faces, const Name { #ifdef CGAL_PMP_SMOOTHING_VERBOSE - t.stop(); - std::cout << "Smoothing done in "; - std::cout << t.time() << " sec." << std::endl; - std::cout << "Convergence to relative hausdorff distance has been achieved." << std::endl; + t.stop(); + std::cout << "Smoothing done in "; + std::cout << t.time() << " sec." << std::endl; + std::cout << "Convergence to relative hausdorff distance has been achieved." << std::endl; #endif break; } @@ -635,10 +655,10 @@ void compatible_smoothing(PolygonMesh& pmesh, const FaceRange& faces, const Name { #ifdef CGAL_PMP_SMOOTHING_VERBOSE - t.stop(); - std::cout << "Smoothing done in "; - std::cout << t.time() << " sec." << std::endl; - std::cout << "Maximum number of iterations has been achieved." << std::endl; + t.stop(); + std::cout << "Smoothing done in "; + std::cout << t.time() << " sec." << std::endl; + std::cout << "Maximum number of iterations has been achieved." << std::endl; #endif break; } From 329b017c764843dc197436077462e4a1daa60c71 Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Sun, 27 Aug 2017 21:02:27 +0300 Subject: [PATCH 098/102] results & images in docs --- .../Polygon_mesh_processing.txt | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt index d964f6e0e9d..306d27438b6 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt @@ -128,21 +128,21 @@ While mesh smoothing is achieved by improving the quality of the triangulated el shape smoothing is designed to be "intrinsic", depending as little as possible to the discretization and smoothing the shape alone without optimizing the mesh elements. -For mesh smoothing, `CGAL::Polygon_mesh_processing::angle_remeshing()` may be used to -move vertices so that the angles of its incident edges equalize and `CGAL::Polygon_mesh_processing::area_remeshing()` may be used to -move vertices so that the areas of adjacent triangles equalize. Angle and area remeshing are used combined in -`CGAL::Polygon_mesh_processing::compatible_remeshing()` which smooths the mesh until convergence is achieved. +For mesh smoothing, `CGAL::Polygon_mesh_processing::angle_smoothing()` may be used to +move vertices so that the angles of its incident edges equalize and `CGAL::Polygon_mesh_processing::area_smoothing()` may be used to +move vertices so that the areas of adjacent triangles equalize. Angle and area smoothing are used combined in +`CGAL::Polygon_mesh_processing::compatible_smoothing()` which smooths the mesh until convergence is achieved. For shape smoothing, `CGAL::Polygon_mesh_processing::curvature_flow()` takes into account the mean curvature to calculate a weighted barycenter towards which vertices move incrementally. In all cases border vertices are considered constrained and do not move at any step of the procedure. Also, new vertices are not inserted while mesh or shape smoothing, although degenerate faces are removed as a first step -before the remeshing. +before the smoothing. -Angle and area remeshing algorithms are based on Surazhsky and Gotsman \cgalCite{cgal:sg-hqct-04}. When mesh connectivity -is highly irregular, angle remeshing may be used with angle weights so that small angles carry +Angle and area smoothing algorithms are based on Surazhsky and Gotsman \cgalCite{cgal:sg-hqct-04}. When mesh connectivity +is highly irregular, angle smoothing may be used with angle weights so that small angles carry more weight and with almost the same computational cost per iteration convergence may be achieved faster. -Area remeshing, since it considers only triangle areas as a smoothing criterion, may result in long and skinny triangles, -especially for meshes with highly irregular connectivity. As such, area remeshing is guaranteed to improve the spatial +Area smoothing, since it considers only triangle areas as a smoothing criterion, may result in long and skinny triangles, +especially for meshes with highly irregular connectivity. As such, area smoothing is guaranteed to improve the spatial distribution of the vertices over the area that is being remeshed. The curvature flow algorithm for shape smoothing is based on Desbrun et al \cgalCite{cgal:dmsb-ifamdcf-99}. @@ -151,11 +151,16 @@ area that is being smoothed. This means that if the surface is flat around a ver Curvature flow smoothing offers best results in closed surface meshes, where vertices slide according to the curvature and smooth the shape while the overall volume is being kept constant. -\cgalFigureBegin{smoothing, smoothing.png} -Mesh and shape smoothing. (a) Elephant before mesh smoothing. -(b) Elephant after applying compatible remeshing for 20 iterations. -(c) Devil before shape smoothing. -(d) Resuted devil after application of curvature flow algorithm. +\cgalFigureBegin{elephants_and_histograms, elephants_and_histograms.png} +Mesh smoothing. (a) Elephant before mesh smoothing and +(b) elephant after applying compatible smoothing for 20 iterations. +and histograms of their aspect ratios beneath them. Aspect ratio is defined as the ratio +of the largest altidute of a triangle to the length of its shortest edge. +\cgalFigureEnd + +\cgalFigureBegin{mannequins, mannequins.png} +Shape smoothing. (a) Devil before shape smoothing and +(b) the devil after applying the curvature flow algorithm. \cgalFigureEnd \subsection MeshingExamples Meshing Examples From b39fe7803dfa81497deccc13fb56ddbebfa76d1c Mon Sep 17 00:00:00 2001 From: konstantinos katrioplas Date: Sun, 27 Aug 2017 21:08:51 +0300 Subject: [PATCH 099/102] mesh quality evaluation class --- .../internal/Smoothing/evaluation.h | 168 ++++++++++++++++++ .../CGAL/Polygon_mesh_processing/smoothing.h | 33 +++- 2 files changed, 199 insertions(+), 2 deletions(-) create mode 100644 Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/evaluation.h diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/evaluation.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/evaluation.h new file mode 100644 index 00000000000..72fca66ef5e --- /dev/null +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Smoothing/evaluation.h @@ -0,0 +1,168 @@ +#ifndef EVALUATION_H +#define EVALUATION_H + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; + + +namespace CGAL { + +namespace Polygon_mesh_processing { + +namespace internal { + + + +template +class Quality_evaluator +{ + + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename boost::graph_traits::face_descriptor face_descriptor; + + typedef typename boost::property_map::type VertexPointMap; + + +public: + Quality_evaluator(PolygonMesh& pmesh) : mesh_(pmesh) + { + std::size_t number_of_triangles = faces(mesh_).size(); + + // todo: move reserving to each function + angles_.reserve(number_of_triangles * 3); + areas_.reserve(number_of_triangles); + aspect_ratios_.reserve(number_of_triangles); + + vpmap_ = get(CGAL::vertex_point, mesh_); + } + + void gather_angles() + { + double rad_to_deg = 180. / CGAL_PI; + + /* + typename boost::property_map::type + vpmap = get(CGAL::vertex_point, mesh_); + */ + + for(halfedge_descriptor hi : halfedges(mesh_)) + { + + typename Kernel::Point_3 a = get(vpmap_, source(hi, mesh_)); + typename Kernel::Point_3 b = get(vpmap_, target(hi, mesh_)); + typename Kernel::Point_3 c = get(vpmap_, target(next(hi, mesh_), mesh_)); + + typename Kernel::Vector_3 ba(b, a); + typename Kernel::Vector_3 bc(b, c); + + double cos_angle = (ba * bc) + / std::sqrt(ba.squared_length() * bc.squared_length()); + + angles_.push_back(std::acos(cos_angle) * rad_to_deg); + } + + std::cout<<"angles_ size= "< - - - - 10 - 0 - 431 - 291 - - - - Mesh smoothing - - - - - 10 - 30 - 411 - 71 - - - - - 0 - 0 - - - - Qt::LeftToRight - - - Parameters - - - - - 10 - 30 - 386 - 33 - + + + + + Mesh smoothing - + - - - - - Gradient descent precision: - - - - - - - 4 - - - - - - - + + + + 0 + 0 + + - Qt::RightToLeft + Qt::LeftToRight - - use weights + + Parameters + + + + 10 + 30 + 718 + 56 + + + + + + + + + Gradient descent precision: + + + + + + + 4 + + + + + + + + + Qt::RightToLeft + + + use weights + + + + + + + + + + + Qt::Horizontal + + + + true + + + Qt::LeftToRight + + + Remeshing by type + + + false + + + false + + + + + + + + area + + + + + + + + + + Type + + + Qt::AlignCenter + + + + + + + Iterations + + + Qt::AlignCenter + + + + + + + + + + + 0 + 0 + + + + angle + + + + + + + + + Apply + + + + + + + + Compatible remeshing algorithm + + + + + + + + Qt::RightToLeft + + + Hausdorff distance: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + 4 + + + + + + + Qt::RightToLeft + + + max iterations: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + + + + + Convergence criteria + + + + + + + + + Run to convergence + + + + + - - - - - 10 - 110 - 411 - 173 - - - - Qt::Horizontal - - - - true - - - Qt::LeftToRight - + + + - Remeshing by type + Shape smoothing - - false - - - false - - + - - - + + + Apply curvature flow algorithm + + + + + + + - area + Iterations: - - - - - - - Type - - - Qt::AlignCenter - - - - - - - Iterations - - - Qt::AlignCenter - - - - - - - - - - - 0 - 0 - - - - angle - - + + - - - - Apply - - - - - - Compatible remeshing algorithm - - - - - - - - Qt::RightToLeft - - - Hausdorff distance: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - 4 - - - - - - - Qt::RightToLeft - - - max iterations: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - - - - Convergence criteria - - - - - - - - - Run to convergence - - - - - - - - - - - 10 - 290 - 431 - 71 - - - - Shape smoothing - - - - - 20 - 30 - 241 - 31 - - - - Apply curvature flow algorithm - - - - - - 282 - 30 - 121 - 31 - - - - - - - Iterations: - - - - - - - - - + +