From 598472d2103a0e71135dce91f6763b433eef5428 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Mon, 13 Apr 2015 15:44:22 +0200 Subject: [PATCH 001/217] add framework for remeshing --- .../internal/remesh_impl.h | 46 +++++++++++++++ .../CGAL/Polygon_mesh_processing/remesh.h | 56 +++++++++++++++++++ .../Polygon_mesh_processing/CMakeLists.txt | 2 +- .../remeshing_test.cpp | 26 +++++++++ 4 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h create mode 100644 Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h create mode 100644 Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h new file mode 100644 index 00000000000..6aeeda79d65 --- /dev/null +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -0,0 +1,46 @@ + +#ifndef CGAL_POLYGON_MESH_PROCESSING_REMESH_IMPL_H +#define CGAL_POLYGON_MESH_PROCESSING_REMESH_IMPL_H + +namespace CGAL { +namespace Polygon_mesh_processing { +namespace internal { + + template + class Incremental_remesher + { + public: + Incremental_remesher(PolygonMesh& pmesh) + : mesh_(pmesh) + {} + + void split_long_edges(const double& high) + { + ; + } + void collapse_short_edges(const double& low, const double& high) + { + ; + } + void equalize_valences() + { + ; + } + void tangential_relaxation() + { + ; + } + void project_to_surface() + { + ; + } + + private: + PolygonMesh& mesh_; + + };//end class Incremenal_remesher +}//end namespace internal +}//end namesapce Polygon_mesh_processing +}//end namesapce CGAL + +#endif //CGAL_POLYGON_MESH_PROCESSING_REMESH_IMPL_H diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h new file mode 100644 index 00000000000..a42a70cfe4e --- /dev/null +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h @@ -0,0 +1,56 @@ +// 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) : Jane Tournois + +#ifndef CGAL_POLYGON_MESH_PROCESSING_REMESH_H +#define CGAL_POLYGON_MESH_PROCESSING_REMESH_H + +#include + +namespace CGAL { + +namespace Polygon_mesh_processing { + +/** +* \ingroup PkgPolygonMeshProcessing +* implements section 6.5.3 "Incremental remeshing" from the PMP book +*/ +template +void incremental_triangle_based_remeshing(PolygonMesh& pmesh, + const double& target_edge_length, + const unsigned int& nb_iterations = 10) +{ + double low = 4./5. * target_edge_length; + double high = 4./3. * target_edge_length; + + typename internal::Incremental_remesher remesher(pmesh); + for (unsigned int i = 0; i < nb_iterations; ++i) + { + remesher.split_long_edges(high); + remesher.collapse_short_edges(low, high); + remesher.equalize_valences(); + remesher.tangential_relaxation(); + remesher.project_to_surface(); + } +} + +} //end namespace Polygon_mesh_processing +} //end namespace CGAL + +#endif diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt index 2d4cb88aa78..a1418c5fe19 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt @@ -80,7 +80,7 @@ if (EIGEN3_FOUND) create_single_source_cgal_program("triangulate_hole_polyline_test.cpp") create_single_source_cgal_program("remove_degeneracies_test.cpp") create_single_source_cgal_program("polyhedron_prog_inside_test.cpp") - + create_single_source_cgal_program("remeshing_test.cpp" ) else(EIGEN3_FOUND) message(STATUS "NOTICE: Some examples require Eigen 3.1 (or greater) and will not be compiled.") endif(EIGEN3_FOUND) diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp new file mode 100644 index 00000000000..8b904008cf9 --- /dev/null +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp @@ -0,0 +1,26 @@ + + +#include +#include + +#include + +#include + +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; +typedef CGAL::Surface_mesh Mesh; + +int main() +{ + std::ifstream input("data/U.off"); + Mesh m; + + if (!input || !(input >> m)){ + std::cerr << "Error: can not read file.\n"; + return 1; + } + + CGAL::Polygon_mesh_processing::incremental_triangle_based_remeshing(m, 0.1, 10); + + return 0; +} \ No newline at end of file From 79b5ba85534d525674237226d7d59f46c03e4fd9 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 14 Apr 2015 14:27:38 +0200 Subject: [PATCH 002/217] first step : split_long_edges --- .../internal/named_function_params.h | 17 +++ .../internal/remesh_impl.h | 102 +++++++++++++++++- .../CGAL/Polygon_mesh_processing/remesh.h | 36 +++++-- .../remeshing_test.cpp | 36 ++++++- 4 files changed, 180 insertions(+), 11 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/named_function_params.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/named_function_params.h index b7d3864271c..c2a018f96c3 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/named_function_params.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/named_function_params.h @@ -34,6 +34,7 @@ namespace CGAL{ enum sparse_linear_solver_t { sparse_linear_solver }; enum less_halfedge_t { less_halfedge }; enum geom_traits_t { geom_traits }; + enum number_of_iterations_t { number_of_iterations }; //internal enum weight_calculator_t { weight_calculator }; @@ -121,6 +122,14 @@ namespace CGAL{ return Params(k, *this); } + template + pmp_bgl_named_params + number_of_iterations(const NT& n) const + { + typedef pmp_bgl_named_params Params; + return Params(n, *this); + } + //overload template pmp_bgl_named_params @@ -235,6 +244,14 @@ namespace parameters{ return Params(k); } + template + pmp_bgl_named_params + number_of_iterations(const NT& n) + { + typedef pmp_bgl_named_params Params; + return Params(n); + } + //overload template pmp_bgl_named_params diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 6aeeda79d65..83f580237b8 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -2,21 +2,97 @@ #ifndef CGAL_POLYGON_MESH_PROCESSING_REMESH_IMPL_H #define CGAL_POLYGON_MESH_PROCESSING_REMESH_IMPL_H +#include + +#include +#include +#include + namespace CGAL { namespace Polygon_mesh_processing { namespace internal { - template + template class Incremental_remesher { + typedef PolygonMesh PM; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename boost::graph_traits::edge_descriptor edge_descriptor; + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + + typedef typename GeomTraits::Point_3 Point; + public: - Incremental_remesher(PolygonMesh& pmesh) + Incremental_remesher(PolygonMesh& pmesh + , VertexPointMap& vpmap) : mesh_(pmesh) + , vpmap_(vpmap) {} void split_long_edges(const double& high) { - ; + //collect long edges + double sq_high = high*high; + std::map long_edges; + BOOST_FOREACH(edge_descriptor e, edges(mesh_)) + { + double sqlen = sqlength(e); + if(sqlen > sq_high) + long_edges[halfedge(e, mesh_)] = sqlen; + } + + //split long edges + while (!long_edges.empty()) + { + typename std::map::iterator eit = long_edges.begin(); + edge_descriptor e = eit->first; + double sqlen = eit->second; + long_edges.erase(eit); + Point refinement_point = this->midpoint(e); + + //split edge + bool is_border = (face(halfedge(e, mesh_), mesh_) == boost::graph_traits::null_face()); + halfedge_descriptor hnew = (!is_border) + ? CGAL::Euler::split_edge(halfedge(e, mesh_), mesh_) + : CGAL::Euler::split_edge(opposite(halfedge(e, mesh_), mesh_), mesh_); + + vertex_descriptor vnew = target(hnew, mesh_); + vpmap_[vnew] = refinement_point; + + //check sub-edges + double sqlen_new = 0.25 * sqlen; + if (sqlen_new > sq_high) + { + //if it was more than twice the "long" threshold, insert them + long_edges[hnew] = sqlen_new; + long_edges[next(hnew, mesh_)] = sqlen_new; + } + + //insert new edges to keep triangular faces, and update long_edges + if (face(hnew, mesh_) != boost::graph_traits::null_face()) + { + halfedge_descriptor hnew2 = CGAL::Euler::split_face(hnew, + next(next(hnew, mesh_), mesh_), + mesh_); + double sql = sqlength(hnew2); + if (sql > sq_high) + long_edges[hnew2] = sql; + } + //do it again on the other side if we're not on boundary + halfedge_descriptor hnew_opp = opposite(hnew, mesh_); + if (face(hnew_opp, mesh_) != boost::graph_traits::null_face()) + { + halfedge_descriptor hnew2 = CGAL::Euler::split_face(prev(hnew_opp, mesh_), + next(hnew_opp, mesh_), + mesh_); + double sql = sqlength(hnew2); + if (sql > sq_high) + long_edges[hnew2] = sql; + } + } } void collapse_short_edges(const double& low, const double& high) { @@ -35,8 +111,28 @@ namespace internal { ; } + private: + double sqlength(const halfedge_descriptor& h) const + { + vertex_descriptor v1 = target(h, mesh_); + vertex_descriptor v2 = source(h, mesh_); + return CGAL::squared_distance(vpmap_[v1], vpmap_[v2]); + } + double sqlength(const edge_descriptor& e) const + { + return sqlength(halfedge(e, mesh_)); + } + + Point midpoint(const edge_descriptor& e) const + { + Point p1 = vpmap_[target(halfedge(e, mesh_), mesh_)]; + Point p2 = vpmap_[source(halfedge(e, mesh_), mesh_)]; + return CGAL::midpoint(p1, p2); + } + private: PolygonMesh& mesh_; + VertexPointMap& vpmap_; };//end class Incremenal_remesher }//end namespace internal diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h index a42a70cfe4e..578d714d123 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h @@ -23,6 +23,9 @@ #include +#include +#include + namespace CGAL { namespace Polygon_mesh_processing { @@ -30,16 +33,35 @@ namespace Polygon_mesh_processing { /** * \ingroup PkgPolygonMeshProcessing * implements section 6.5.3 "Incremental remeshing" from the PMP book +* named parameters : +* vertex_point_map +* nb_iterations +* geom_traits, that needs Point_3 */ -template -void incremental_triangle_based_remeshing(PolygonMesh& pmesh, - const double& target_edge_length, - const unsigned int& nb_iterations = 10) +template +void incremental_triangle_based_remeshing(PolygonMesh& pmesh + , const double& target_edge_length + , const NamedParameters& np) { - double low = 4./5. * target_edge_length; - double high = 4./3. * target_edge_length; + typedef PolygonMesh PM; + using boost::choose_pmap; + using boost::get_param; + using boost::choose_param; + + typedef typename GetGeomTraits::type GeomTraits; + + typedef typename GetVertexPointMap::type VPMap; + VPMap vpmap = choose_pmap(get_param(np, boost::vertex_point), + pmesh, + boost::vertex_point); + typename internal::Incremental_remesher + remesher(pmesh, vpmap); + + unsigned int nb_iterations = choose_param(get_param(np, number_of_iterations), 10); + + double low = 4. / 5. * target_edge_length; + double high = 4. / 3. * target_edge_length; - typename internal::Incremental_remesher remesher(pmesh); for (unsigned int i = 0; i < nb_iterations; ++i) { remesher.split_long_edges(high); diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp index 8b904008cf9..d2c0139340c 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp @@ -5,11 +5,30 @@ #include +#include #include typedef CGAL::Exact_predicates_inexact_constructions_kernel K; typedef CGAL::Surface_mesh Mesh; +typedef boost::graph_traits::edge_descriptor edge_descriptor; +typedef boost::graph_traits::vertex_descriptor vertex_descriptor; + +template +void test_edge_lengths(const Mesh& pmesh, + const double& high, + const VPmap& vpmap) +{ + double sqhigh = high * high; + BOOST_FOREACH(edge_descriptor e, edges(pmesh)) + { + vertex_descriptor v1 = target(halfedge(e, pmesh), pmesh); + vertex_descriptor v2 = source(halfedge(e, pmesh), pmesh); + double sql = CGAL::squared_distance(vpmap[v1], vpmap[v2]); + CGAL_assertion(sqhigh >= sql); + } +} + int main() { std::ifstream input("data/U.off"); @@ -20,7 +39,22 @@ int main() return 1; } - CGAL::Polygon_mesh_processing::incremental_triangle_based_remeshing(m, 0.1, 10); + double target_edge_length = 0.03; + double low = 4. / 5. * target_edge_length; + double high = 4. / 3. * target_edge_length; + + CGAL::Polygon_mesh_processing::incremental_triangle_based_remeshing(m, + target_edge_length, + CGAL::Polygon_mesh_processing::parameters::number_of_iterations(10)); + + boost::property_map::const_type vpmap + = boost::get(CGAL::vertex_point, m); + + test_edge_lengths(m, high, vpmap); + + std::ofstream out("U_remeshed.off"); + out << m; + out.close(); return 0; } \ No newline at end of file From fc0b9bd51a1182a02ce41b7e75cf076252a046d7 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Thu, 16 Apr 2015 17:37:07 +0200 Subject: [PATCH 003/217] add collapse short edges to remeshing longest edges are split first and shortest edges are collapsed first todo : allow edges incident to boundary to be collapsed --- .../internal/remesh_impl.h | 174 +++++++++++++++--- .../CGAL/Polygon_mesh_processing/remesh.h | 4 +- .../remeshing_test.cpp | 8 +- 3 files changed, 161 insertions(+), 25 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 83f580237b8..df404a2f9ba 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -6,7 +6,10 @@ #include #include -#include + +#include +#include +#include namespace CGAL { namespace Polygon_mesh_processing { @@ -34,30 +37,36 @@ namespace internal { void split_long_edges(const double& high) { - //collect long edges + typedef boost::bimap< + boost::bimaps::set_of, + boost::bimaps::multiset_of > > Boost_bimap; + typedef typename Boost_bimap::value_type long_edge; + + std::cout << "Split long edges (" << high << ")..."; double sq_high = high*high; - std::map long_edges; + + //collect long edges + Boost_bimap long_edges; BOOST_FOREACH(edge_descriptor e, edges(mesh_)) { double sqlen = sqlength(e); if(sqlen > sq_high) - long_edges[halfedge(e, mesh_)] = sqlen; + long_edges.insert(long_edge(halfedge(e, mesh_), sqlen)); } //split long edges while (!long_edges.empty()) { - typename std::map::iterator eit = long_edges.begin(); - edge_descriptor e = eit->first; - double sqlen = eit->second; - long_edges.erase(eit); - Point refinement_point = this->midpoint(e); + typename Boost_bimap::right_map::iterator eit = long_edges.right.begin(); + halfedge_descriptor he = eit->second; + double sqlen = eit->first; + long_edges.right.erase(eit); + Point refinement_point = this->midpoint(he); //split edge - bool is_border = (face(halfedge(e, mesh_), mesh_) == boost::graph_traits::null_face()); - halfedge_descriptor hnew = (!is_border) - ? CGAL::Euler::split_edge(halfedge(e, mesh_), mesh_) - : CGAL::Euler::split_edge(opposite(halfedge(e, mesh_), mesh_), mesh_); + halfedge_descriptor hnew = (!is_border(he, mesh_)) + ? CGAL::Euler::split_edge(he, mesh_) + : CGAL::Euler::split_edge(opposite(he, mesh_), mesh_); vertex_descriptor vnew = target(hnew, mesh_); vpmap_[vnew] = refinement_point; @@ -67,37 +76,146 @@ namespace internal { if (sqlen_new > sq_high) { //if it was more than twice the "long" threshold, insert them - long_edges[hnew] = sqlen_new; - long_edges[next(hnew, mesh_)] = sqlen_new; + long_edges.insert(long_edge(hnew, sqlen_new)); + long_edges.insert(long_edge(next(hnew, mesh_), sqlen_new)); } //insert new edges to keep triangular faces, and update long_edges - if (face(hnew, mesh_) != boost::graph_traits::null_face()) + if (!is_border(hnew, mesh_)) { halfedge_descriptor hnew2 = CGAL::Euler::split_face(hnew, next(next(hnew, mesh_), mesh_), mesh_); double sql = sqlength(hnew2); if (sql > sq_high) - long_edges[hnew2] = sql; + long_edges.insert(long_edge(hnew2, sql)); } //do it again on the other side if we're not on boundary halfedge_descriptor hnew_opp = opposite(hnew, mesh_); - if (face(hnew_opp, mesh_) != boost::graph_traits::null_face()) + if (!is_border(hnew_opp, mesh_)) { halfedge_descriptor hnew2 = CGAL::Euler::split_face(prev(hnew_opp, mesh_), next(hnew_opp, mesh_), mesh_); double sql = sqlength(hnew2); if (sql > sq_high) - long_edges[hnew2] = sql; + long_edges.insert(long_edge(hnew2, sql)); } } + std::cout << " done." << std::endl; +#ifdef CGAL_DUMP_REMESHING_STEPS + dump("1-edge_split.off"); +#endif } + void collapse_short_edges(const double& low, const double& high) { - ; + typedef boost::bimap< + boost::bimaps::set_of, + boost::bimaps::multiset_of > > Boost_bimap; + typedef typename Boost_bimap::value_type short_edge; + + std::cout << "Collapse short edges (" << low << ", " << high << ")..."; + double sq_low = low*low; + double sq_high = high*high; + + Boost_bimap short_edges; + BOOST_FOREACH(edge_descriptor e, edges(mesh_)) + { + double sqlen = sqlength(e); + if (sqlen < sq_low) + short_edges.insert(short_edge(halfedge(e, mesh_), sqlen)); + } + + unsigned int nb_collapses = 0; + while (!short_edges.empty()) + { + typename Boost_bimap::right_map::iterator eit = short_edges.right.begin(); + halfedge_descriptor he = eit->second; + double sqlen = eit->first; + short_edges.right.erase(eit); + + vertex_descriptor va = target(he, mesh_); + vertex_descriptor vb = source(he, mesh_); + + //avoid collapsing away from boundary a halfedge incident to boundary + if (is_border(vb, mesh_) || is_border(va, mesh_)) + continue; //temporary + + if (is_border(vb, mesh_)) + { + if (is_border(va, mesh_)) + continue; //happens when he crosses the surface + he = opposite(he, mesh_); + std::swap(va, vb); + } + + if (degree(va, mesh_) < 3 + || degree(vb, mesh_) < 3 + || is_border_edge(he, mesh_) //other collapses could have changed that + || !CGAL::Euler::satisfies_link_condition(he, mesh_))//necessary to collapse + continue; + + //check that collapse would not create an edge with length > high + //iterate on vertices va_i of the one-ring of va + bool collapse_ok = true; + BOOST_FOREACH(halfedge_descriptor ha, halfedges_around_target(va, mesh_)) + { + vertex_descriptor va_i = source(ha, mesh_); + if (sqlength(vb, va_i) > sq_high) + { + collapse_ok = false; + break; + } + } + //if it is allowed, perform the collapse + if (collapse_ok) + { + //"collapse va into vb along e" + // remove edges incident to va and vb, because their lengths will change + BOOST_FOREACH(halfedge_descriptor ha, halfedges_around_target(va, mesh_)) + { + short_edges.left.erase(ha); + short_edges.left.erase(opposite(ha, mesh_)); + } + BOOST_FOREACH(halfedge_descriptor hb, halfedges_around_target(vb, mesh_)) + { + short_edges.left.erase(hb); + short_edges.left.erase(opposite(hb, mesh_)); + } + + CGAL_assertion_code( + halfedge_descriptor en = next(he, mesh_); + halfedge_descriptor enp = next(opposite(he, mesh_), mesh_); + ); + + //perform collapse + Point target_point = vpmap_[vb]; + vertex_descriptor vkept = CGAL::Euler::collapse_edge(edge(he, mesh_), mesh_); + vpmap_[vkept] = target_point; + ++nb_collapses; + + CGAL_assertion(source(en, mesh_) == source(enp, mesh_)); + CGAL_expensive_assertion(is_triangle_mesh(mesh_)); + + //insert new/remaining short edges + BOOST_FOREACH(halfedge_descriptor ht, halfedges_around_target(vkept, mesh_)) + { + double sqlen = sqlength(ht); + if (sqlen < sq_low) + short_edges.insert(short_edge(ht, sqlen)); + } + + std::cout << "."; + std::cout.flush(); + } + } + std::cout << " done (" << nb_collapses << " collapses)." << std::endl; +#ifdef CGAL_DUMP_REMESHING_STEPS + dump("2-edge_collapse.off"); +#endif } + void equalize_valences() { ; @@ -112,12 +230,19 @@ namespace internal { } private: + double sqlength(const vertex_descriptor& v1, + const vertex_descriptor& v2) const + { + return CGAL::squared_distance(vpmap_[v1], vpmap_[v2]); + } + double sqlength(const halfedge_descriptor& h) const { vertex_descriptor v1 = target(h, mesh_); vertex_descriptor v2 = source(h, mesh_); - return CGAL::squared_distance(vpmap_[v1], vpmap_[v2]); + return sqlength(v1, v2); } + double sqlength(const edge_descriptor& e) const { return sqlength(halfedge(e, mesh_)); @@ -130,6 +255,13 @@ namespace internal { return CGAL::midpoint(p1, p2); } + void dump(const char* filename) const + { + std::ofstream out(filename); + out << mesh_; + out.close(); + } + private: PolygonMesh& mesh_; VertexPointMap& vpmap_; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h index 578d714d123..c1414d28c92 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h @@ -21,6 +21,8 @@ #ifndef CGAL_POLYGON_MESH_PROCESSING_REMESH_H #define CGAL_POLYGON_MESH_PROCESSING_REMESH_H +#define CGAL_DUMP_REMESHING_STEPS + #include #include @@ -57,7 +59,7 @@ void incremental_triangle_based_remeshing(PolygonMesh& pmesh typename internal::Incremental_remesher remesher(pmesh, vpmap); - unsigned int nb_iterations = choose_param(get_param(np, number_of_iterations), 10); + unsigned int nb_iterations = choose_param(get_param(np, number_of_iterations), 1); double low = 4. / 5. * target_edge_length; double high = 4. / 3. * target_edge_length; diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp index d2c0139340c..4fa01cf653f 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp @@ -25,6 +25,8 @@ void test_edge_lengths(const Mesh& pmesh, vertex_descriptor v1 = target(halfedge(e, pmesh), pmesh); vertex_descriptor v2 = source(halfedge(e, pmesh), pmesh); double sql = CGAL::squared_distance(vpmap[v1], vpmap[v2]); + if (sqhigh < sql) + std::cout << "sqhigh = " << sqhigh << "\t sql = " << sql << std::endl; CGAL_assertion(sqhigh >= sql); } } @@ -39,18 +41,18 @@ int main() return 1; } - double target_edge_length = 0.03; + double target_edge_length = 0.01; double low = 4. / 5. * target_edge_length; double high = 4. / 3. * target_edge_length; CGAL::Polygon_mesh_processing::incremental_triangle_based_remeshing(m, target_edge_length, - CGAL::Polygon_mesh_processing::parameters::number_of_iterations(10)); + CGAL::Polygon_mesh_processing::parameters::number_of_iterations(1)); boost::property_map::const_type vpmap = boost::get(CGAL::vertex_point, m); - test_edge_lengths(m, high, vpmap); +// test_edge_lengths(m, high, vpmap); std::ofstream out("U_remeshed.off"); out << m; From d1b5737bd4de3376407b6df0ac6f095916f5a2c8 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 17 Apr 2015 10:37:30 +0200 Subject: [PATCH 004/217] allow collapsing edges incident to boundary --- .../internal/remesh_impl.h | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index df404a2f9ba..8a5ea00bc6a 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -130,29 +130,28 @@ namespace internal { unsigned int nb_collapses = 0; while (!short_edges.empty()) { + //the edge with shortest length typename Boost_bimap::right_map::iterator eit = short_edges.right.begin(); halfedge_descriptor he = eit->second; double sqlen = eit->first; short_edges.right.erase(eit); + //let's try to collapse he into vb vertex_descriptor va = target(he, mesh_); vertex_descriptor vb = source(he, mesh_); - //avoid collapsing away from boundary a halfedge incident to boundary - if (is_border(vb, mesh_) || is_border(va, mesh_)) - continue; //temporary - - if (is_border(vb, mesh_)) + //handle the boundary case : an edge incident to boundary can be collapsed, + //but only if the boundary vertex is kept, so re-insert opposite(he) + //to collapse it + if (is_border(va, mesh_)) { - if (is_border(va, mesh_)) - continue; //happens when he crosses the surface - he = opposite(he, mesh_); - std::swap(va, vb); + if (!is_border(vb, mesh_)) + short_edges.insert(short_edge(opposite(he, mesh_), sqlen)); + continue; } if (degree(va, mesh_) < 3 || degree(vb, mesh_) < 3 - || is_border_edge(he, mesh_) //other collapses could have changed that || !CGAL::Euler::satisfies_link_condition(he, mesh_))//necessary to collapse continue; From 544a133b5e9a7a7a3da822be77ff11179738d495 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 17 Apr 2015 10:45:16 +0200 Subject: [PATCH 005/217] add comment --- .../include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 8a5ea00bc6a..cc1e42fc749 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -57,6 +57,7 @@ namespace internal { //split long edges while (!long_edges.empty()) { + //the edge with longest length typename Boost_bimap::right_map::iterator eit = long_edges.right.begin(); halfedge_descriptor he = eit->second; double sqlen = eit->first; From 9a2213082e11b11ad3dec715532bb4a5cd0dc339 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 17 Apr 2015 10:56:11 +0200 Subject: [PATCH 006/217] add comments from PMP book, and output debug info (cout) --- .../internal/remesh_impl.h | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index cc1e42fc749..24d82e8399c 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -35,6 +35,10 @@ namespace internal { , vpmap_(vpmap) {} + // PMP book : + // "visits all edges of the mesh + //if an edge is longer than the given threshold `high`, the edge + //is split at its midpoint and the two adjacent triangles are bisected (2-4 split)" void split_long_edges(const double& high) { typedef boost::bimap< @@ -55,6 +59,7 @@ namespace internal { } //split long edges + unsigned int nb_splits = 0; while (!long_edges.empty()) { //the edge with longest length @@ -102,13 +107,20 @@ namespace internal { if (sql > sq_high) long_edges.insert(long_edge(hnew2, sql)); } + + ++nb_splits; } - std::cout << " done." << std::endl; + std::cout << " done ("<< nb_splits << " splits)." << std::endl; + #ifdef CGAL_DUMP_REMESHING_STEPS dump("1-edge_split.off"); #endif } + // PMP book : + // "collapses and thus removes all edges that are shorter than a + // threshold `low`. [...] testing before each collapse whether the collapse + // would produce an edge that is longer than `high`" void collapse_short_edges(const double& low, const double& high) { typedef boost::bimap< @@ -205,12 +217,10 @@ namespace internal { if (sqlen < sq_low) short_edges.insert(short_edge(ht, sqlen)); } - - std::cout << "."; - std::cout.flush(); } } std::cout << " done (" << nb_collapses << " collapses)." << std::endl; + #ifdef CGAL_DUMP_REMESHING_STEPS dump("2-edge_collapse.off"); #endif From 0c84e31f0b1b7f35d3488bb82023de56957e223b Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 17 Apr 2015 11:59:25 +0200 Subject: [PATCH 007/217] equalize_valences, by performing edge flips where it's allowed --- .../internal/remesh_impl.h | 92 ++++++++++++++++++- .../CGAL/Polygon_mesh_processing/remesh.h | 3 +- 2 files changed, 92 insertions(+), 3 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 24d82e8399c..e53e33e3d2c 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -26,7 +26,9 @@ namespace internal { typedef typename boost::graph_traits::edge_descriptor edge_descriptor; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - typedef typename GeomTraits::Point_3 Point; + typedef typename GeomTraits::Point_3 Point; + typedef typename GeomTraits::Vector_3 Vector_3; + typedef typename GeomTraits::Plane_3 Plane_3; public: Incremental_remesher(PolygonMesh& pmesh @@ -226,10 +228,59 @@ namespace internal { #endif } + // PMP book : + // "equalizes the vertex valences by flipping edges. + // The target valence is 6 and 4 for interior and boundary vertices, resp. + // The algo. tentatively flips each edge `e` and checks whether the deviation + // to the target valences decreases. If not, the edge is flipped back" void equalize_valences() { - ; + std::cout << "Equalize valences..."; + unsigned int nb_flips = 0; + BOOST_FOREACH(edge_descriptor e, edges(mesh_)) + { + if (!is_flip_allowed(e)) + continue; + + halfedge_descriptor he = halfedge(e, mesh_); + vertex_descriptor va = source(he, mesh_); + vertex_descriptor vb = target(he, mesh_); + vertex_descriptor vc = target(next(he, mesh_), mesh_); + vertex_descriptor vd = target(next(opposite(he, mesh_), mesh_), mesh_); + + int deviation_pre = CGAL::abs(valence(va) - target_valence(va)) + + CGAL::abs(valence(vb) - target_valence(vb)) + + CGAL::abs(valence(vc) - target_valence(vc)) + + CGAL::abs(valence(vd) - target_valence(vd)); + + CGAL::Euler::flip_edge(he, mesh_); + ++nb_flips; + + CGAL_assertion( + (vc == target(he, mesh_) && vd == source(he, mesh_)) + || (vd == target(he, mesh_) && vc == source(he, mesh_))); + + int deviation_post = CGAL::abs(valence(va) - target_valence(va)) + + CGAL::abs(valence(vb) - target_valence(vb)) + + CGAL::abs(valence(vc) - target_valence(vc)) + + CGAL::abs(valence(vd) - target_valence(vd)); + + if (deviation_pre < deviation_post) + { + CGAL::Euler::flip_edge(he, mesh_); + --nb_flips; + CGAL_assertion( + (va == source(he, mesh_) && vb == target(he, mesh_)) + || (vb == source(he, mesh_) && va == target(he, mesh_))); + } + } + std::cout << "done. ("<< nb_flips << " flips)" << std::endl; + +#ifdef CGAL_DUMP_REMESHING_STEPS + dump("3-edge_flips.off"); +#endif } + void tangential_relaxation() { ; @@ -272,6 +323,43 @@ namespace internal { out.close(); } + int valence(const vertex_descriptor& v) const + { + return degree(v, mesh_); + } + + int target_valence(const vertex_descriptor& v) const + { + return (is_border(v, mesh_)) ? 4 : 6; + } + + bool is_flip_allowed(const edge_descriptor& e) const + { + if (is_border(e, mesh_)) + return false;//we can't flip border edges + + halfedge_descriptor he = halfedge(e, mesh_); + Point p1 = vpmap_[target(he, mesh_)]; + Point p2 = vpmap_[source(he, mesh_)]; + Vector_3 normal(p1, p2); + + //construct planes passing through p1 and p2, + // and orthogonal to e + Plane_3 plane1(p1, normal); + Plane_3 plane2(p2, normal); + + CGAL_assertion(//check orientation is consistent + plane1.orthogonal_vector() * plane2.orthogonal_vector() > 0.); + + //get third points of triangles shared by e + Point p3 = vpmap_[target(next(he, mesh_), mesh_)]; + Point p4 = vpmap_[target(next(opposite(he, mesh_), mesh_), mesh_)]; + + //check whether p3 and p4 are between plane1 and plane2 + return (plane1.oriented_side(p3) != plane2.oriented_side(p3)) + && (plane1.oriented_side(p4) != plane2.oriented_side(p4)); + } + private: PolygonMesh& mesh_; VertexPointMap& vpmap_; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h index c1414d28c92..639bac64364 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h @@ -38,7 +38,7 @@ namespace Polygon_mesh_processing { * named parameters : * vertex_point_map * nb_iterations -* geom_traits, that needs Point_3 +* geom_traits, that needs Point_3, Vector_3, Plane_3 */ template void incremental_triangle_based_remeshing(PolygonMesh& pmesh @@ -71,6 +71,7 @@ void incremental_triangle_based_remeshing(PolygonMesh& pmesh remesher.equalize_valences(); remesher.tangential_relaxation(); remesher.project_to_surface(); + std::cout << std::endl; } } From e80a4adfaa7164ae39014ede507d703081cb507f Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 17 Apr 2015 11:59:46 +0200 Subject: [PATCH 008/217] increase the number of iterations in test --- .../test/Polygon_mesh_processing/remeshing_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp index 4fa01cf653f..7e18f2157e6 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp @@ -47,7 +47,7 @@ int main() CGAL::Polygon_mesh_processing::incremental_triangle_based_remeshing(m, target_edge_length, - CGAL::Polygon_mesh_processing::parameters::number_of_iterations(1)); + CGAL::Polygon_mesh_processing::parameters::number_of_iterations(5)); boost::property_map::const_type vpmap = boost::get(CGAL::vertex_point, m); From 1eb75ac3f2f94086f25f71d71616fcd61a7f8eed Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 17 Apr 2015 12:31:27 +0200 Subject: [PATCH 009/217] perform tangential_relaxation --- .../internal/remesh_impl.h | 56 ++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index e53e33e3d2c..710491bc646 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -3,6 +3,7 @@ #define CGAL_POLYGON_MESH_PROCESSING_REMESH_IMPL_H #include +#include #include #include @@ -11,6 +12,8 @@ #include #include +#include + namespace CGAL { namespace Polygon_mesh_processing { namespace internal { @@ -281,10 +284,61 @@ namespace internal { #endif } + // PMP book : + // "applies an iterative smoothing filter to the mesh. + // The vertex movement has to be constrained to the vertex tangent plane [...] + // smoothing algorithm with uniform Laplacian weights" void tangential_relaxation() { - ; + //todo : move border vertices along 1-dimensional features + //todo : use compute_normals + namespace PMP = CGAL::Polygon_mesh_processing; + + std::cout << "Tangential relaxation..."; + + // at each vertex, compute barycenter of neighbors + std::map barycenters; + BOOST_FOREACH(vertex_descriptor v, vertices(mesh_)) + { + if (is_border(v, mesh_)) + continue; + Vector_3 move = CGAL::NULL_VECTOR; + unsigned int star_size = 0; + BOOST_FOREACH(halfedge_descriptor h, halfedges_around_target(v, mesh_)) + { + move = move + Vector_3(vpmap_[v], vpmap_[source(h, mesh_)]); + ++star_size; + } + move = (1. / (double)star_size) * move; + barycenters[v] = vpmap_[v] + move; + } + + // compute and perform moves + BOOST_FOREACH(vertex_descriptor v, vertices(mesh_)) + { + if (is_border(v, mesh_)) + continue; + Vector_3 nv = PMP::compute_vertex_normal(v + , mesh_ + , PMP::parameters::vertex_point_map(vpmap_) + .geom_traits(GeomTraits())); + + Point qv = barycenters[v]; + Point newp = qv + (nv * Vector_3(qv, vpmap_[v])) * nv; + //move v + vpmap_[v] = newp; + } + + CGAL_assertion(is_valid(mesh_)); + CGAL_assertion(is_triangle_mesh(mesh_)); + + std::cout << "done." << std::endl; + +#ifdef CGAL_DUMP_REMESHING_STEPS + dump("4-relaxation.off"); +#endif } + void project_to_surface() { ; From 8432018c76fb2760ca136707574d91220ef77f1c Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 17 Apr 2015 12:32:11 +0200 Subject: [PATCH 010/217] add todo --- .../include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 710491bc646..35baeea4e0e 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -128,6 +128,8 @@ namespace internal { // would produce an edge that is longer than `high`" void collapse_short_edges(const double& low, const double& high) { + //todo : allow boundary edges to be collapsed under some conditions + typedef boost::bimap< boost::bimaps::set_of, boost::bimaps::multiset_of > > Boost_bimap; From d2b3146fec137858a4d6c600703944eb3195b1fb Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 17 Apr 2015 15:32:26 +0200 Subject: [PATCH 011/217] project_to_surface at the end of remeshing algorithm --- .../internal/remesh_impl.h | 65 ++++++++++++++++++- 1 file changed, 62 insertions(+), 3 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 35baeea4e0e..69af05752ac 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -2,9 +2,13 @@ #ifndef CGAL_POLYGON_MESH_PROCESSING_REMESH_IMPL_H #define CGAL_POLYGON_MESH_PROCESSING_REMESH_IMPL_H -#include #include +#include +#include +#include + +#include #include #include @@ -13,6 +17,7 @@ #include #include +#include namespace CGAL { namespace Polygon_mesh_processing { @@ -28,18 +33,49 @@ namespace internal { typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::edge_descriptor edge_descriptor; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::face_descriptor face_descriptor; typedef typename GeomTraits::Point_3 Point; typedef typename GeomTraits::Vector_3 Vector_3; typedef typename GeomTraits::Plane_3 Plane_3; + typedef typename GeomTraits::Triangle_3 Triangle_3; + + typedef std::list Triangle_list; + typedef typename Triangle_list::iterator Tr_iterator; + typedef CGAL::AABB_triangle_primitive Primitive; + typedef CGAL::AABB_traits Traits; + typedef CGAL::AABB_tree AABB_tree; public: Incremental_remesher(PolygonMesh& pmesh , VertexPointMap& vpmap) : mesh_(pmesh) , vpmap_(vpmap) - {} + , own_tree_(true) + , input_triangles_() + { + CGAL_assertion(CGAL::is_triangle_mesh(pmesh)); + BOOST_FOREACH(face_descriptor f, faces(pmesh)) + { + 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_); + + input_triangles_.push_back(Triangle_3(vpmap[v1], vpmap[v2], vpmap[v3])); + } + tree_ptr_ = new AABB_tree(input_triangles_.begin(), input_triangles_.end()); + //todo : add a constructor with aabb_tree as parameter + //todo : do we really need to keep this copy of the input surface? + } + + ~Incremental_remesher() + { + if (own_tree_) + delete tree_ptr_; + } + // PMP book : // "visits all edges of the mesh //if an edge is longer than the given threshold `high`, the edge @@ -341,9 +377,29 @@ namespace internal { #endif } + + // PMP book : + // "maps the vertices back to the surface" void project_to_surface() { - ; + //todo : handle the case of boundary vertices + std::cout << "Project to surface..."; + + BOOST_FOREACH(vertex_descriptor v, vertices(mesh_)) + { + if (is_border(v, mesh_)) + continue; + vpmap_[v] = tree_ptr_->closest_point(vpmap_[v]); + } + + CGAL_assertion(is_valid(mesh_)); + CGAL_assertion(is_triangle_mesh(mesh_)); + + std::cout << "done." << std::endl; + +#ifdef CGAL_DUMP_REMESHING_STEPS + dump("5-project.off"); +#endif } private: @@ -419,6 +475,9 @@ namespace internal { private: PolygonMesh& mesh_; VertexPointMap& vpmap_; + const AABB_tree* tree_ptr_; + bool own_tree_; + Triangle_list input_triangles_; };//end class Incremenal_remesher }//end namespace internal From 5c9891ed53987438fda5d0fdd3bb0b1f151a89e9 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 17 Apr 2015 15:33:24 +0200 Subject: [PATCH 012/217] fix typos in comments --- .../CGAL/Polygon_mesh_processing/internal/remesh_impl.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 69af05752ac..d3e320f2028 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -481,7 +481,7 @@ namespace internal { };//end class Incremenal_remesher }//end namespace internal -}//end namesapce Polygon_mesh_processing -}//end namesapce CGAL +}//end namespace Polygon_mesh_processing +}//end namespace CGAL #endif //CGAL_POLYGON_MESH_PROCESSING_REMESH_IMPL_H From ebb5daa890a2584236f12bdb7405ff2576a1e61e Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 17 Apr 2015 15:43:18 +0200 Subject: [PATCH 013/217] allow boundary edges to be collapsed --- .../internal/remesh_impl.h | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index d3e320f2028..8d1f1927d8f 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -164,8 +164,6 @@ namespace internal { // would produce an edge that is longer than `high`" void collapse_short_edges(const double& low, const double& high) { - //todo : allow boundary edges to be collapsed under some conditions - typedef boost::bimap< boost::bimaps::set_of, boost::bimaps::multiset_of > > Boost_bimap; @@ -196,14 +194,19 @@ namespace internal { vertex_descriptor va = target(he, mesh_); vertex_descriptor vb = source(he, mesh_); - //handle the boundary case : an edge incident to boundary can be collapsed, + //handle the boundary case : + //a boundary edge can be collapsed, + //and an edge incident to boundary can be collapsed, //but only if the boundary vertex is kept, so re-insert opposite(he) //to collapse it - if (is_border(va, mesh_)) + if (!is_border_edge(he, mesh_)) { - if (!is_border(vb, mesh_)) - short_edges.insert(short_edge(opposite(he, mesh_), sqlen)); - continue; + if (is_border(va, mesh_)) + { + if (!is_border(vb, mesh_)) + short_edges.insert(short_edge(opposite(he, mesh_), sqlen)); + continue; + } } if (degree(va, mesh_) < 3 From 0f1097c9882d64d8bd98965da240122aad3210a3 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 17 Apr 2015 17:14:56 +0200 Subject: [PATCH 014/217] use compute_vertex_normals to compute normals only once per face to keep deterministic and not depend on the order in which vertex locations are relaxed, we compute all new locations first, and relocate them all afterwise --- .../internal/remesh_impl.h | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 8d1f1927d8f..dae9c274a85 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -332,11 +333,20 @@ namespace internal { void tangential_relaxation() { //todo : move border vertices along 1-dimensional features - //todo : use compute_normals namespace PMP = CGAL::Polygon_mesh_processing; std::cout << "Tangential relaxation..."; + //todo : use boost::vector_property_map to improve computing time + typedef std::map VNormalsMap; + VNormalsMap vnormals; + boost::associative_property_map propmap_normals(vnormals); + + PMP::compute_vertex_normals(mesh_, + propmap_normals, + PMP::parameters::vertex_point_map(vpmap_). + geom_traits(GeomTraits())); + // at each vertex, compute barycenter of neighbors std::map barycenters; BOOST_FOREACH(vertex_descriptor v, vertices(mesh_)) @@ -354,20 +364,22 @@ namespace internal { barycenters[v] = vpmap_[v] + move; } - // compute and perform moves + // compute moves + std::map new_locations; BOOST_FOREACH(vertex_descriptor v, vertices(mesh_)) { if (is_border(v, mesh_)) continue; - Vector_3 nv = PMP::compute_vertex_normal(v - , mesh_ - , PMP::parameters::vertex_point_map(vpmap_) - .geom_traits(GeomTraits())); - + Vector_3 nv = boost::get(propmap_normals, v); Point qv = barycenters[v]; - Point newp = qv + (nv * Vector_3(qv, vpmap_[v])) * nv; - //move v - vpmap_[v] = newp; + new_locations[v] = qv + (nv * Vector_3(qv, vpmap_[v])) * nv; + } + + // perform moves + typedef typename std::map::value_type VP_pair; + BOOST_FOREACH(const VP_pair& vp, new_locations) + { + vpmap_[vp.first] = new_locations[vp.first]; } CGAL_assertion(is_valid(mesh_)); From f7820a651752daf792488ab30a9bd2d8af7a135c Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Mon, 20 Apr 2015 13:40:11 +0200 Subject: [PATCH 015/217] introduce API to mesh only a patch (does not implement anything yet) --- .../CGAL/Polygon_mesh_processing/get_border.h | 81 +++++++++++++++ .../internal/remesh_impl.h | 99 +++++++++++++++++-- .../CGAL/Polygon_mesh_processing/remesh.h | 18 +++- .../remeshing_test.cpp | 1 + 4 files changed, 188 insertions(+), 11 deletions(-) create mode 100644 Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/get_border.h diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/get_border.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/get_border.h new file mode 100644 index 00000000000..f6eedccd736 --- /dev/null +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/get_border.h @@ -0,0 +1,81 @@ +// 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) : Jane Tournois + +#ifndef CGAL_POLYGON_MESH_PROCESSING_GET_BORDER_H +#define CGAL_POLYGON_MESH_PROCESSING_GET_BORDER_H + +#include + +#include +#include + +namespace CGAL{ +namespace Polygon_mesh_processing { + + /** + * collects the border of a face range + * @param faces the range of face descriptors around which the + * border is computed + * @param out the output iterator that collects edges that form the border + * of `faces`, seen from inside the surface patch + * + * @todo code : what shall we do for more than one connected components + */ + template + void get_border(const PolygonMesh& pmesh + , const FaceRange& faces + , HalfedgeOutputIterator out) + { + typedef PolygonMesh PM; + typedef typename boost::graph_traits::edge_descriptor edge_descriptor; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + + typedef typename boost::graph_traits::face_descriptor face_descriptor; + + //collect halfedges that appear only once + std::set border; + BOOST_FOREACH(face_descriptor f, faces) + { + BOOST_FOREACH(halfedge_descriptor h, + halfedges_around_face(halfedge(f, pmesh), pmesh)) + { + //halfedge_descriptor is model of `LessThanComparable` + halfedge_descriptor he = (h < opposite(h, pmesh)) + ? h + : opposite(h, pmesh); + if (border.find(he) != border.end()) + border.erase(he); //even number of appearances + else + border.insert(he);//odd number of appearances + } + } + //copy them in out + BOOST_FOREACH(halfedge_descriptor h, border) + { + *out++ = h; + } + } + +} } // end of namespace CGAL::Polygon_mesh_processing + + +#endif //CGAL_POLYGON_MESH_PROCESSING_GET_BORDER_H diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index dae9c274a85..464a6cbf511 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -3,6 +3,7 @@ #define CGAL_POLYGON_MESH_PROCESSING_REMESH_IMPL_H #include +#include #include #include @@ -16,15 +17,29 @@ #include #include #include +#include #include #include +#include +#include + +namespace PMP = CGAL::Polygon_mesh_processing; + namespace CGAL { namespace Polygon_mesh_processing { namespace internal { + enum Halfedge_status { + PATCH, //h and hopp belong to the patch to be remeshed + PATCH_BORDER,//h belongs to the patch, hopp is MESH + MESH, //h and hopp belong to the mesh, not the patch + MESH_BORDER //h belongs to the mesh, face(hopp, pmesh) == null_face() + }; + template @@ -49,26 +64,31 @@ namespace internal { public: Incremental_remesher(PolygonMesh& pmesh + , FaceRange face_range , VertexPointMap& vpmap) : mesh_(pmesh) , vpmap_(vpmap) , own_tree_(true) , input_triangles_() + , patch_(boost::begin(face_range), boost::end(face_range)) + , halfedge_status_map_() { - CGAL_assertion(CGAL::is_triangle_mesh(pmesh)); + CGAL_assertion(CGAL::is_triangle_mesh(mesh_)); - BOOST_FOREACH(face_descriptor f, faces(pmesh)) + //build AABB tree of input surface + //todo : add a constructor with aabb_tree as parameter + //todo : do we really need to keep this copy of the input surface? + BOOST_FOREACH(face_descriptor f, faces(mesh_)) { 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_); - input_triangles_.push_back(Triangle_3(vpmap[v1], vpmap[v2], vpmap[v3])); } tree_ptr_ = new AABB_tree(input_triangles_.begin(), input_triangles_.end()); - //todo : add a constructor with aabb_tree as parameter - //todo : do we really need to keep this copy of the input surface? + + tag_halfedges_status(face_range); } ~Incremental_remesher() @@ -333,8 +353,6 @@ namespace internal { void tangential_relaxation() { //todo : move border vertices along 1-dimensional features - namespace PMP = CGAL::Polygon_mesh_processing; - std::cout << "Tangential relaxation..."; //todo : use boost::vector_property_map to improve computing time @@ -487,14 +505,79 @@ namespace internal { && (plane1.oriented_side(p4) != plane2.oriented_side(p4)); } + template + void tag_halfedges_status(FaceRange face_range) + { + //tag PATCH, //h and hopp belong to the patch to be remeshed + BOOST_FOREACH(face_descriptor f, face_range) + { + BOOST_FOREACH(halfedge_descriptor h, + halfedges_around_face(halfedge(f, mesh_), mesh_)) + { + halfedge_status_map_[h] = PATCH; + } + } + + //tag PATCH_BORDER,//h belongs to the patch, hopp doesn't + std::vector border_halfedges; + PMP::get_border(mesh_, face_range, std::back_inserter(border_halfedges)); + BOOST_FOREACH(halfedge_descriptor h, border_halfedges) + { + halfedge_status_map_[h] = PATCH_BORDER; + } + + //tag MESH, //h and hopp belong to the mesh, not the patch + //tag MESH_BORDER //h belongs to the mesh, face(hopp, pmesh) == null_face() + BOOST_FOREACH(halfedge_descriptor h, halfedges(mesh_)) + { + //being part of the border of the mesh is predominant + if (is_border(h, mesh_)) + halfedge_status_map_[h] = MESH_BORDER; //erase previous value if exists + else + { + //h is not border, does not belong to patch, nor to patch border + if (halfedge_status_map_.find(h) == halfedge_status_map_.end()) + halfedge_status_map_[h] = MESH; + } + } + } + + bool is_on_patch(const halfedge_descriptor& h) const + { + return halfedge_status_map_[h] == PATCH; + } + + bool is_on_patch_border(const halfedge_descriptor& h) const + { + return halfedge_status_map_[h] == PATCH_BORDER; + } + bool is_on_patch_border(const edge_descriptor& e) const + { + return is_on_patch_border(halfedge(e,mesh_)) + || is_on_patch_border(opposite(halfedge(e, mesh_), mesh_)); + } + + bool is_on_border(const halfedge_descriptor& h) const + { + CGAL_assertion(is_border(h, mesh_) == halfedge_status_map_[h]); + return halfedge_status_map_[h] == MESH_BORDER; + } + bool is_on_border(const edge_descriptor& e) const + { + return is_on_border(halfedge(e, mesh_)) + || is_on_border(opposite(halfedge(e, mesh_), mesh_)); + } + private: PolygonMesh& mesh_; VertexPointMap& vpmap_; const AABB_tree* tree_ptr_; bool own_tree_; Triangle_list input_triangles_; + std::vector patch_; + std::map halfedge_status_map_; - };//end class Incremenal_remesher + };//end class Incremental_remesher }//end namespace internal }//end namespace Polygon_mesh_processing }//end namespace CGAL diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h index 639bac64364..d60df4ece7a 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h @@ -35,13 +35,25 @@ namespace Polygon_mesh_processing { /** * \ingroup PkgPolygonMeshProcessing * implements section 6.5.3 "Incremental remeshing" from the PMP book +* @tparam PolygonMesh model of `MutableFaceGraph` that +* has an internal property map for `CGAL::vertex_point_t` +* @tparam FaceRange range of face descriptors, model of `SinglePassRange` +* +* @param pmesh polygon mesh with patches to be refined +* @param faces the range of faces defining one patch to remesh +* * named parameters : * vertex_point_map * nb_iterations * geom_traits, that needs Point_3, Vector_3, Plane_3 +* +*@todo we suppose `faces` describe only one patch. Handle several patches */ -template +template void incremental_triangle_based_remeshing(PolygonMesh& pmesh + , FaceRange faces , const double& target_edge_length , const NamedParameters& np) { @@ -56,8 +68,8 @@ void incremental_triangle_based_remeshing(PolygonMesh& pmesh VPMap vpmap = choose_pmap(get_param(np, boost::vertex_point), pmesh, boost::vertex_point); - typename internal::Incremental_remesher - remesher(pmesh, vpmap); + typename internal::Incremental_remesher + remesher(pmesh, faces, vpmap); unsigned int nb_iterations = choose_param(get_param(np, number_of_iterations), 1); diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp index 7e18f2157e6..baf496d817c 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp @@ -46,6 +46,7 @@ int main() double high = 4. / 3. * target_edge_length; CGAL::Polygon_mesh_processing::incremental_triangle_based_remeshing(m, + faces(m), target_edge_length, CGAL::Polygon_mesh_processing::parameters::number_of_iterations(5)); From 14979947a02805e8428c953c370e751106d16d37 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Mon, 20 Apr 2015 17:39:56 +0200 Subject: [PATCH 016/217] add isotropic remeshing plugin note it does not compile yet because the remeshing code is not fully compatible with Polyhedron_3 --- .../CGAL/Polygon_mesh_processing/remesh.h | 12 ++ Polyhedron/demo/Polyhedron/CMakeLists.txt | 4 + ...hedron_demo_isotropic_remeshing_plugin.cpp | 118 ++++++++++++++++++ 3 files changed, 134 insertions(+) create mode 100644 Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h index d60df4ece7a..fed8e9addb8 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h @@ -87,6 +87,18 @@ void incremental_triangle_based_remeshing(PolygonMesh& pmesh } } +template +void incremental_triangle_based_remeshing(PolygonMesh& pmesh + , FaceRange faces + , const double& target_edge_length) +{ + incremental_triangle_based_remeshing(pmesh, + faces, + target_edge_length, + parameters::all_default()); +} + } //end namespace Polygon_mesh_processing } //end namespace CGAL diff --git a/Polyhedron/demo/Polyhedron/CMakeLists.txt b/Polyhedron/demo/Polyhedron/CMakeLists.txt index b30f37230d6..c41592a91b7 100644 --- a/Polyhedron/demo/Polyhedron/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/CMakeLists.txt @@ -500,6 +500,10 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND) polyhedron_demo_plugin(shortest_path_plugin Polyhedron_demo_shortest_path_plugin ${shortestPathUI_FILES}) target_link_libraries(shortest_path_plugin scene_polyhedron_item scene_polylines_item scene_polyhedron_selection_item scene_polyhedron_shortest_path_item scene_basic_objects) + + polyhedron_demo_plugin(isotropic_remeshing_plugin Polyhedron_demo_isotropic_remeshing_plugin) + target_link_libraries(isotropic_remeshing_plugin scene_polyhedron_item scene_polyhedron_selection_item) + # # Exporting # diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp new file mode 100644 index 00000000000..efcd7616586 --- /dev/null +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp @@ -0,0 +1,118 @@ +#include + +#include "Scene_polyhedron_item.h" +#include "Scene_polyhedron_selection_item.h" +#include "Polyhedron_demo_plugin_helper.h" +#include "Polyhedron_type.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + + +class Polyhedron_demo_isotropic_remeshing_plugin : + public QObject, + public Polyhedron_demo_plugin_helper +{ + Q_OBJECT + Q_INTERFACES(Polyhedron_demo_plugin_interface) + +public: + void init(QMainWindow* mainWindow, Scene_interface* scene_interface) + { + this->scene = scene_interface; + this->mw = mainWindow; + actionIsotropicRemeshing_ = new QAction("Isotropic remeshing", mw); + if (actionIsotropicRemeshing_) { + connect(actionIsotropicRemeshing_, SIGNAL(triggered()), + this, SLOT(isotropic_remeshing())); + } + } + + QList actions() const { + return QList() << actionIsotropicRemeshing_; + } + + bool applicable(QAction*) const + { + return qobject_cast(scene->item(scene->mainSelectionIndex())) + || qobject_cast(scene->item(scene->mainSelectionIndex())); + } + +public Q_SLOTS: + void isotropic_remeshing() + { + 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)); + + if (poly_item || selection_item) + { + // wait cursor + QApplication::setOverrideCursor(Qt::WaitCursor); + + QTime time; + time.start(); + + bool ok; + double target_length = QInputDialog::getDouble(this->mw, + QString("Isotropic remeshing : Edge length"), + QString("Target edge length : "), + 0.1, //value + 0.0001,//min + 2147483647,//max + 3, //decimals + &ok); //Qt::WindowFlags flags = 0); + if (!ok) + std::cout << "Remeshing aborted" << std::endl; + + Polyhedron *pRemeshed = new Polyhedron; + if (selection_item) { + std::cout << "TODO : Remesh selection item" << std::endl; + //use poly_item->selected_facets() + } + else if (poly_item){ + Polyhedron* pMesh = poly_item->polyhedron(); + CGAL::Polygon_mesh_processing::incremental_triangle_based_remeshing(*pMesh, + faces(*pMesh), + target_length); + } + else{ + std::cout << "Can't remesh that type of thing" << std::endl; + } + std::cout << "ok (" << time.elapsed() << " ms)" << std::endl; + + Scene_polyhedron_item* new_item = new Scene_polyhedron_item(pRemeshed); + new_item->setName(tr("%1 (iso remeshing)").arg(scene->item(index)->name())); + new_item->setColor(Qt::magenta); + new_item->setRenderingMode(FlatPlusEdges); + scene->addItem(new_item); + + // default cursor + QApplication::restoreOverrideCursor(); + } + } + +private: + QAction* actionIsotropicRemeshing_; + +}; // end Polyhedron_demo_isotropic_remeshing_plugin + +Q_EXPORT_PLUGIN2(Polyhedron_demo_isotropic_remeshing_plugin, + Polyhedron_demo_isotropic_remeshing_plugin) + +#include "Polyhedron_demo_isotropic_remeshing_plugin.moc" From d2f18f8a3e3ad02b3abe804c77863053c39c2eec Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Mon, 20 Apr 2015 17:44:01 +0200 Subject: [PATCH 017/217] fix compilation for Polyhedron_3 --- .../Polygon_mesh_processing/internal/remesh_impl.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 464a6cbf511..05b9d0aaf46 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -232,7 +232,7 @@ namespace internal { if (degree(va, mesh_) < 3 || degree(vb, mesh_) < 3 - || !CGAL::Euler::satisfies_link_condition(he, mesh_))//necessary to collapse + || !CGAL::Euler::satisfies_link_condition(edge(he, mesh_), mesh_))//necessary to collapse continue; //check that collapse would not create an edge with length > high @@ -454,17 +454,17 @@ namespace internal { return sqlength(halfedge(e, mesh_)); } - Point midpoint(const edge_descriptor& e) const + Point midpoint(const halfedge_descriptor& he) const { - Point p1 = vpmap_[target(halfedge(e, mesh_), mesh_)]; - Point p2 = vpmap_[source(halfedge(e, mesh_), mesh_)]; + Point p1 = vpmap_[target(he, mesh_)]; + Point p2 = vpmap_[source(he, mesh_)]; return CGAL::midpoint(p1, p2); } void dump(const char* filename) const { std::ofstream out(filename); - out << mesh_; +// out << mesh_; out.close(); } From c067ffcbc634b0987bfa4d9c41279058e0271f54 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 21 Apr 2015 11:29:59 +0200 Subject: [PATCH 018/217] remesh only a selection made available in Polyhedron demo (remeshing code still not able to handle it) --- ...hedron_demo_isotropic_remeshing_plugin.cpp | 35 +++++++++++++------ .../Scene_polyhedron_selection_item.h | 5 +++ 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp index efcd7616586..38f5eb03aed 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp @@ -14,11 +14,12 @@ #include #include #include +#include #include #include #include - +#include class Polyhedron_demo_isotropic_remeshing_plugin : public QObject, @@ -68,28 +69,40 @@ public Q_SLOTS: QTime time; time.start(); + double diago_length = (poly_item != NULL) + ? poly_item->bbox().diagonal_length() + : selection_item->bbox().diagonal_length(); + + std::ostringstream oss; + oss << "Target edge length?" << std::endl; + oss << " Diagonal length of the Bbox of the selection to remesh is "; + oss << diago_length << std::endl; + oss << " (default is 5% of it)" << std::endl; + bool ok; double target_length = QInputDialog::getDouble(this->mw, QString("Isotropic remeshing : Edge length"), - QString("Target edge length : "), - 0.1, //value - 0.0001,//min - 2147483647,//max - 3, //decimals + QString::fromStdString(oss.str()),//question + 0.05 * diago_length, //value + 1e-6 * diago_length, //min + 2. * diago_length, //max + 3, //decimals &ok); //Qt::WindowFlags flags = 0); if (!ok) std::cout << "Remeshing aborted" << std::endl; Polyhedron *pRemeshed = new Polyhedron; if (selection_item) { - std::cout << "TODO : Remesh selection item" << std::endl; - //use poly_item->selected_facets() + Polyhedron* pMesh = selection_item->polyhedron(); + CGAL::Polygon_mesh_processing::incremental_triangle_based_remeshing(*pMesh + , selection_item->selected_facets + , target_length); } else if (poly_item){ Polyhedron* pMesh = poly_item->polyhedron(); - CGAL::Polygon_mesh_processing::incremental_triangle_based_remeshing(*pMesh, - faces(*pMesh), - target_length); + CGAL::Polygon_mesh_processing::incremental_triangle_based_remeshing(*pMesh + , faces(*pMesh) + , target_length); } else{ std::cout << "Can't remesh that type of thing" << std::endl; diff --git a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h index 9cc4f97dc0b..e4a68907fa2 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h +++ b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h @@ -217,6 +217,11 @@ public: typedef boost::unordered_set Selection_set_facet; typedef boost::unordered_set Selection_set_edge; + Polyhedron* polyhedron() + { + return this->poly_item->polyhedron(); + } + // drawing void draw() const { draw_selected_vertices(); From 9cf0f55b9d94c0b13152b081437083787c216e81 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 21 Apr 2015 17:05:30 +0200 Subject: [PATCH 019/217] demo ready for remeshing of selection item --- ...hedron_demo_isotropic_remeshing_plugin.cpp | 41 +++++++++---------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp index 38f5eb03aed..a45a4e5696e 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp @@ -63,12 +63,6 @@ public Q_SLOTS: if (poly_item || selection_item) { - // wait cursor - QApplication::setOverrideCursor(Qt::WaitCursor); - - QTime time; - time.start(); - double diago_length = (poly_item != NULL) ? poly_item->bbox().diagonal_length() : selection_item->bbox().diagonal_length(); @@ -89,32 +83,37 @@ public Q_SLOTS: 3, //decimals &ok); //Qt::WindowFlags flags = 0); if (!ok) + { std::cout << "Remeshing aborted" << std::endl; + return; + } + // wait cursor + QApplication::setOverrideCursor(Qt::WaitCursor); + + QTime time; + time.start(); - Polyhedron *pRemeshed = new Polyhedron; if (selection_item) { - Polyhedron* pMesh = selection_item->polyhedron(); - CGAL::Polygon_mesh_processing::incremental_triangle_based_remeshing(*pMesh - , selection_item->selected_facets - , target_length); + CGAL::Polygon_mesh_processing::incremental_triangle_based_remeshing( + *selection_item->polyhedron() + , selection_item->selected_facets + , target_length); + + selection_item->changed_with_poly_item(); } else if (poly_item){ - Polyhedron* pMesh = poly_item->polyhedron(); - CGAL::Polygon_mesh_processing::incremental_triangle_based_remeshing(*pMesh - , faces(*pMesh) - , target_length); + CGAL::Polygon_mesh_processing::incremental_triangle_based_remeshing( + *poly_item->polyhedron() + , faces(*poly_item->polyhedron()) + , target_length); + + poly_item->changed(); } else{ std::cout << "Can't remesh that type of thing" << std::endl; } std::cout << "ok (" << time.elapsed() << " ms)" << std::endl; - Scene_polyhedron_item* new_item = new Scene_polyhedron_item(pRemeshed); - new_item->setName(tr("%1 (iso remeshing)").arg(scene->item(index)->name())); - new_item->setColor(Qt::magenta); - new_item->setRenderingMode(FlatPlusEdges); - scene->addItem(new_item); - // default cursor QApplication::restoreOverrideCursor(); } From 8b9bcefe227d495e64d7d6c7af13f3e28efbcd4f Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 21 Apr 2015 18:00:19 +0200 Subject: [PATCH 020/217] remeshing of the patch works when the patch describes the full mesh otherwise, it enters an endless loop for now --- .../CGAL/Polygon_mesh_processing/get_border.h | 2 + .../internal/remesh_impl.h | 134 ++++++++++++++---- .../remeshing_test.cpp | 82 ++++++++--- 3 files changed, 176 insertions(+), 42 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/get_border.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/get_border.h index f6eedccd736..b9db4aa5926 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/get_border.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/get_border.h @@ -37,6 +37,8 @@ namespace Polygon_mesh_processing { * of `faces`, seen from inside the surface patch * * @todo code : what shall we do for more than one connected components + * @todo code : make sure the halfedges returned actually belong to a face + * from `faces`. It's not the case yet */ template sq_high) long_edges.insert(long_edge(halfedge(e, mesh_), sqlen)); @@ -132,10 +134,10 @@ namespace internal { Point refinement_point = this->midpoint(he); //split edge - halfedge_descriptor hnew = (!is_border(he, mesh_)) - ? CGAL::Euler::split_edge(he, mesh_) - : CGAL::Euler::split_edge(opposite(he, mesh_), mesh_); - + halfedge_descriptor hnew = CGAL::Euler::split_edge(he, mesh_); + CGAL_assertion(he == next(hnew, mesh_)); + + //move refinement point vertex_descriptor vnew = target(hnew, mesh_); vpmap_[vnew] = refinement_point; @@ -146,17 +148,34 @@ namespace internal { //if it was more than twice the "long" threshold, insert them long_edges.insert(long_edge(hnew, sqlen_new)); long_edges.insert(long_edge(next(hnew, mesh_), sqlen_new)); + std::cout << "H " << sqlen_new << std::endl; } + //after splitting + Halfedge_status s1 = status(he); + halfedge_added(hnew, s1); + Halfedge_status s2 = status(opposite(he, mesh_)); + halfedge_added(opposite(hnew, mesh_), s2); + CGAL_assertion((s1 == s2 && s1 == PATCH) + || (s1 != s2 && (s1 == PATCH_BORDER && s2 == MESH_BORDER)) + || (s1 != s2 && (s2 == PATCH_BORDER && s1 == MESH_BORDER)) + ); + //insert new edges to keep triangular faces, and update long_edges if (!is_border(hnew, mesh_)) { halfedge_descriptor hnew2 = CGAL::Euler::split_face(hnew, next(next(hnew, mesh_), mesh_), mesh_); + halfedge_added(hnew2, PATCH/*only possible scenario*/); + halfedge_added(opposite(hnew2, mesh_), PATCH); + double sql = sqlength(hnew2); if (sql > sq_high) + { long_edges.insert(long_edge(hnew2, sql)); + std::cout << "A " << sql << std::endl; + } } //do it again on the other side if we're not on boundary halfedge_descriptor hnew_opp = opposite(hnew, mesh_); @@ -165,9 +184,15 @@ namespace internal { halfedge_descriptor hnew2 = CGAL::Euler::split_face(prev(hnew_opp, mesh_), next(hnew_opp, mesh_), mesh_); + halfedge_added(hnew2, PATCH/*only possible scenario*/); + halfedge_added(opposite(hnew2, mesh_), PATCH); + double sql = sqlength(hnew2); if (sql > sq_high) + { long_edges.insert(long_edge(hnew2, sql)); + std::cout << "B " << sql << std::endl; + } } ++nb_splits; @@ -197,6 +222,8 @@ namespace internal { Boost_bimap short_edges; BOOST_FOREACH(edge_descriptor e, edges(mesh_)) { + if (!is_split_or_collapse_allowed(e)) + continue; double sqlen = sqlength(e); if (sqlen < sq_low) short_edges.insert(short_edge(halfedge(e, mesh_), sqlen)); @@ -220,6 +247,7 @@ namespace internal { //and an edge incident to boundary can be collapsed, //but only if the boundary vertex is kept, so re-insert opposite(he) //to collapse it + //todo : handle this border case using the status map if (!is_border_edge(he, mesh_)) { if (is_border(va, mesh_)) @@ -268,6 +296,9 @@ namespace internal { halfedge_descriptor enp = next(opposite(he, mesh_), mesh_); ); + //before collapse + halfedge_and_opp_removed(he); + //perform collapse Point target_point = vpmap_[vb]; vertex_descriptor vkept = CGAL::Euler::collapse_edge(edge(he, mesh_), mesh_); @@ -369,7 +400,7 @@ namespace internal { std::map barycenters; BOOST_FOREACH(vertex_descriptor v, vertices(mesh_)) { - if (is_border(v, mesh_)) + if (!is_on_patch(v)) continue; Vector_3 move = CGAL::NULL_VECTOR; unsigned int star_size = 0; @@ -383,10 +414,11 @@ namespace internal { } // compute moves + //todo : iterate on barycenters instead. Would avoid retesting is_on_patch std::map new_locations; BOOST_FOREACH(vertex_descriptor v, vertices(mesh_)) { - if (is_border(v, mesh_)) + if (!is_on_patch(v)) continue; Vector_3 nv = boost::get(propmap_normals, v); Point qv = barycenters[v]; @@ -420,7 +452,7 @@ namespace internal { BOOST_FOREACH(vertex_descriptor v, vertices(mesh_)) { - if (is_border(v, mesh_)) + if (!is_on_patch(v)) continue; vpmap_[v] = tree_ptr_->closest_point(vpmap_[v]); } @@ -480,10 +512,12 @@ namespace internal { bool is_flip_allowed(const edge_descriptor& e) const { - if (is_border(e, mesh_)) - return false;//we can't flip border edges - + //only the patch, and non-border edges are + //allowed to be flipped halfedge_descriptor he = halfedge(e, mesh_); + if (!is_on_patch(he)) + return false; + Point p1 = vpmap_[target(he, mesh_)]; Point p2 = vpmap_[source(he, mesh_)]; Vector_3 normal(p1, p2); @@ -505,9 +539,28 @@ namespace internal { && (plane1.oriented_side(p4) != plane2.oriented_side(p4)); } + bool is_split_or_collapse_allowed(const edge_descriptor& e) const + { + halfedge_descriptor he = halfedge(e, mesh_); + return is_on_patch(he) + || (is_on_border(he) && is_on_patch_border(opposite(he, mesh_))) + || (is_on_border(opposite(he, mesh_)) && is_on_patch_border(he)); + } + template void tag_halfedges_status(FaceRange face_range) { + //tag MESH, //h and hopp belong to the mesh, not the patch + //tag MESH_BORDER //h belongs to the mesh, face(hopp, pmesh) == null_face() + BOOST_FOREACH(halfedge_descriptor h, halfedges(mesh_)) + { + //being part of the border of the mesh is predominant + if (is_border(h, mesh_)) + halfedge_status_map_[h] = MESH_BORDER; //erase previous value if exists + else + halfedge_status_map_[h] = MESH; + } + //tag PATCH, //h and hopp belong to the patch to be remeshed BOOST_FOREACH(face_descriptor f, face_range) { @@ -518,38 +571,48 @@ namespace internal { } } + //override the border of PATCH //tag PATCH_BORDER,//h belongs to the patch, hopp doesn't std::vector border_halfedges; PMP::get_border(mesh_, face_range, std::back_inserter(border_halfedges)); BOOST_FOREACH(halfedge_descriptor h, border_halfedges) { - halfedge_status_map_[h] = PATCH_BORDER; - } + typename std::map::iterator it + = halfedge_status_map_.find(h); + CGAL_assertion(it != halfedge_status_map_.end()); - //tag MESH, //h and hopp belong to the mesh, not the patch - //tag MESH_BORDER //h belongs to the mesh, face(hopp, pmesh) == null_face() - BOOST_FOREACH(halfedge_descriptor h, halfedges(mesh_)) - { - //being part of the border of the mesh is predominant - if (is_border(h, mesh_)) - halfedge_status_map_[h] = MESH_BORDER; //erase previous value if exists + if (it->second == PATCH) + halfedge_status_map_[h] = PATCH_BORDER; else { - //h is not border, does not belong to patch, nor to patch border - if (halfedge_status_map_.find(h) == halfedge_status_map_.end()) - halfedge_status_map_[h] = MESH; + //todo : this is a workaround because get_border does not always provide + // halfedges from the right side + CGAL_assertion(status(opposite(h, mesh_)) == PATCH); + halfedge_status_map_[opposite(h, mesh_)] = PATCH_BORDER; } } + CGAL_assertion(halfedge_status_map_.size() == num_halfedges(mesh_)); } bool is_on_patch(const halfedge_descriptor& h) const { - return halfedge_status_map_[h] == PATCH; + return status(h) == PATCH; + } + + bool is_on_patch(const vertex_descriptor& v) const + { + BOOST_FOREACH(halfedge_descriptor h, + halfedges_around_target(v, mesh_)) + { + if (!is_on_patch(h)) + return false; + } + return true; } bool is_on_patch_border(const halfedge_descriptor& h) const { - return halfedge_status_map_[h] == PATCH_BORDER; + return status(h) == PATCH_BORDER; } bool is_on_patch_border(const edge_descriptor& e) const { @@ -559,8 +622,7 @@ namespace internal { bool is_on_border(const halfedge_descriptor& h) const { - CGAL_assertion(is_border(h, mesh_) == halfedge_status_map_[h]); - return halfedge_status_map_[h] == MESH_BORDER; + return status(h) == MESH_BORDER; } bool is_on_border(const edge_descriptor& e) const { @@ -568,6 +630,26 @@ namespace internal { || is_on_border(opposite(halfedge(e, mesh_), mesh_)); } + Halfedge_status status(const halfedge_descriptor& h) const + { + typename std::map < halfedge_descriptor, Halfedge_status >::const_iterator + it = halfedge_status_map_.find(h); + CGAL_assertion(it != halfedge_status_map_.end()); + return it->second; + } + + void halfedge_added(const halfedge_descriptor& h, + const Halfedge_status& s) + { + halfedge_status_map_[h] = s; + } + + void halfedge_and_opp_removed(const halfedge_descriptor& h) + { + halfedge_status_map_.erase(h); + halfedge_status_map_.erase(opposite(h, mesh_)); + } + private: PolygonMesh& mesh_; VertexPointMap& vpmap_; diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp index baf496d817c..f087c76fb35 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp @@ -2,33 +2,71 @@ #include #include +#include #include #include #include +#include typedef CGAL::Exact_predicates_inexact_constructions_kernel K; typedef CGAL::Surface_mesh Mesh; -typedef boost::graph_traits::edge_descriptor edge_descriptor; -typedef boost::graph_traits::vertex_descriptor vertex_descriptor; +typedef boost::graph_traits::halfedge_descriptor halfedge_descriptor; +typedef boost::graph_traits::edge_descriptor edge_descriptor; +typedef boost::graph_traits::vertex_descriptor vertex_descriptor; +typedef boost::graph_traits::face_descriptor face_descriptor; -template -void test_edge_lengths(const Mesh& pmesh, - const double& high, - const VPmap& vpmap) +// extract vertices which are at most k (inclusive) far from vertex v +std::vector extract_k_ring(vertex_descriptor v, + int k, + const Mesh& m) { - double sqhigh = high * high; - BOOST_FOREACH(edge_descriptor e, edges(pmesh)) + vertex_descriptor vv = v; + + std::map D; + std::vector Q; + Q.push_back(vv); + D[vv] = 0; + + std::size_t current_index = 0; + int dist_v; + while (current_index < Q.size() && (dist_v = D[Q[current_index]]) < k) { - vertex_descriptor v1 = target(halfedge(e, pmesh), pmesh); - vertex_descriptor v2 = source(halfedge(e, pmesh), pmesh); - double sql = CGAL::squared_distance(vpmap[v1], vpmap[v2]); - if (sqhigh < sql) - std::cout << "sqhigh = " << sqhigh << "\t sql = " << sql << std::endl; - CGAL_assertion(sqhigh >= sql); + vv = Q[current_index++]; + BOOST_FOREACH(halfedge_descriptor he, + halfedges_around_target(halfedge(vv,m), m)) + { + vertex_descriptor new_v = source(he, m); + if (D.insert(std::make_pair(new_v, dist_v + 1)).second) { + Q.push_back(new_v); + } + } } + return Q; +} + +std::set k_ring(vertex_descriptor v, + int k, + const Mesh& m) +{ + std::vector vring + = extract_k_ring(v, k - 1, m); + + std::set kring; + BOOST_FOREACH(vertex_descriptor vd, vring) + { + BOOST_FOREACH(face_descriptor f, + faces_around_target(halfedge(vd, m), m)) + { + if (f == boost::graph_traits::null_face()) + continue; + if (kring.find(f) == kring.end()) + kring.insert(f); + } + } + return kring; } int main() @@ -45,15 +83,27 @@ int main() double low = 4. / 5. * target_edge_length; double high = 4. / 3. * target_edge_length; + unsigned int center_id = 26; + unsigned int i = 0; + vertex_descriptor patch_center; + BOOST_FOREACH(vertex_descriptor v, vertices(m)) + { + if (i++ == center_id) + { + patch_center = v; + break; + } + } + const std::set& patch = k_ring(patch_center, 3, m); + CGAL::Polygon_mesh_processing::incremental_triangle_based_remeshing(m, - faces(m), + patch, target_edge_length, CGAL::Polygon_mesh_processing::parameters::number_of_iterations(5)); boost::property_map::const_type vpmap = boost::get(CGAL::vertex_point, m); -// test_edge_lengths(m, high, vpmap); std::ofstream out("U_remeshed.off"); out << m; From 940a92d69a9550f2418eee4e3cbd793b4be06c7d Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Mon, 27 Apr 2015 10:12:41 +0200 Subject: [PATCH 021/217] fix get_border : return only halfedges that belong to `faces` --- .../CGAL/Polygon_mesh_processing/get_border.h | 22 +- .../internal/remesh_impl.h | 368 ++++++++++++++---- 2 files changed, 304 insertions(+), 86 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/get_border.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/get_border.h index b9db4aa5926..32fc01ca49c 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/get_border.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/get_border.h @@ -37,8 +37,6 @@ namespace Polygon_mesh_processing { * of `faces`, seen from inside the surface patch * * @todo code : what shall we do for more than one connected components - * @todo code : make sure the halfedges returned actually belong to a face - * from `faces`. It's not the case yet */ template::edge_descriptor edge_descriptor; - typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; - + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::face_descriptor face_descriptor; //collect halfedges that appear only once - std::set border; + // the bool is true if the halfedge stored is the one of the face, + // false if it is its opposite + std::map border; BOOST_FOREACH(face_descriptor f, faces) { BOOST_FOREACH(halfedge_descriptor h, halfedges_around_face(halfedge(f, pmesh), pmesh)) { //halfedge_descriptor is model of `LessThanComparable` - halfedge_descriptor he = (h < opposite(h, pmesh)) + bool from_face = (h < opposite(h, pmesh)); + halfedge_descriptor he = from_face ? h : opposite(h, pmesh); if (border.find(he) != border.end()) border.erase(he); //even number of appearances else - border.insert(he);//odd number of appearances + border.insert(std::make_pair(he, from_face));//odd number of appearances } } //copy them in out - BOOST_FOREACH(halfedge_descriptor h, border) + typedef typename std::map::value_type HD_bool; + BOOST_FOREACH(const HD_bool& hd, border) { - *out++ = h; + if (hd.second) + *out++ = hd.first; + else + *out++ = opposite(hd.first, pmesh); } } diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 79f48b20dbb..538107057fc 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -70,7 +70,6 @@ namespace internal { , vpmap_(vpmap) , own_tree_(true) , input_triangles_() - , patch_(boost::begin(face_range), boost::end(face_range)) , halfedge_status_map_() { CGAL_assertion(CGAL::is_triangle_mesh(mesh_)); @@ -115,13 +114,15 @@ namespace internal { Boost_bimap long_edges; BOOST_FOREACH(edge_descriptor e, edges(mesh_)) { - if (!is_split_or_collapse_allowed(e)) + if (!is_split_allowed(e)) continue; double sqlen = sqlength(e); if(sqlen > sq_high) long_edges.insert(long_edge(halfedge(e, mesh_), sqlen)); } + std::cout << "Halfedges : " << nb_valid_halfedges() << std::endl; + //split long edges unsigned int nb_splits = 0; while (!long_edges.empty()) @@ -136,7 +137,8 @@ namespace internal { //split edge halfedge_descriptor hnew = CGAL::Euler::split_edge(he, mesh_); CGAL_assertion(he == next(hnew, mesh_)); - + ++nb_splits; + //move refinement point vertex_descriptor vnew = target(hnew, mesh_); vpmap_[vnew] = refinement_point; @@ -146,59 +148,67 @@ namespace internal { if (sqlen_new > sq_high) { //if it was more than twice the "long" threshold, insert them - long_edges.insert(long_edge(hnew, sqlen_new)); + long_edges.insert(long_edge(hnew, sqlen_new)); long_edges.insert(long_edge(next(hnew, mesh_), sqlen_new)); - std::cout << "H " << sqlen_new << std::endl; } //after splitting - Halfedge_status s1 = status(he); - halfedge_added(hnew, s1); - Halfedge_status s2 = status(opposite(he, mesh_)); - halfedge_added(opposite(hnew, mesh_), s2); - CGAL_assertion((s1 == s2 && s1 == PATCH) - || (s1 != s2 && (s1 == PATCH_BORDER && s2 == MESH_BORDER)) - || (s1 != s2 && (s2 == PATCH_BORDER && s1 == MESH_BORDER)) - ); + halfedge_added(hnew, status(he)); + halfedge_added(opposite(hnew, mesh_), status(opposite(he, mesh_))); //insert new edges to keep triangular faces, and update long_edges - if (!is_border(hnew, mesh_)) + halfedge_descriptor hnew_opp = opposite(hnew, mesh_); + if (!is_on_border(hnew)) { halfedge_descriptor hnew2 = CGAL::Euler::split_face(hnew, next(next(hnew, mesh_), mesh_), mesh_); - halfedge_added(hnew2, PATCH/*only possible scenario*/); - halfedge_added(opposite(hnew2, mesh_), PATCH); + Halfedge_status snew = (is_on_patch(hnew) + || (is_on_patch_border(hnew) && is_on_mesh(hnew_opp)) + || (is_on_patch_border(hnew) && is_on_border(hnew_opp))) + ? PATCH + : MESH; + halfedge_added(hnew2, snew); + halfedge_added(opposite(hnew2, mesh_), snew); - double sql = sqlength(hnew2); - if (sql > sq_high) + if (snew == PATCH) { - long_edges.insert(long_edge(hnew2, sql)); - std::cout << "A " << sql << std::endl; + double sql = sqlength(hnew2); + if (sql > sq_high) + long_edges.insert(long_edge(hnew2, sql)); } } + //do it again on the other side if we're not on boundary - halfedge_descriptor hnew_opp = opposite(hnew, mesh_); - if (!is_border(hnew_opp, mesh_)) + if (!is_on_border(hnew_opp)) { halfedge_descriptor hnew2 = CGAL::Euler::split_face(prev(hnew_opp, mesh_), next(hnew_opp, mesh_), mesh_); - halfedge_added(hnew2, PATCH/*only possible scenario*/); - halfedge_added(opposite(hnew2, mesh_), PATCH); + Halfedge_status snew = (is_on_patch(hnew_opp) + || (is_on_patch_border(hnew_opp) && is_on_mesh(hnew)) + || (is_on_patch_border(hnew_opp) && is_on_border(hnew))) + ? PATCH + : MESH; + halfedge_added(hnew2, snew); + halfedge_added(opposite(hnew2, mesh_), snew); - double sql = sqlength(hnew2); - if (sql > sq_high) + if (snew == PATCH) { - long_edges.insert(long_edge(hnew2, sql)); - std::cout << "B " << sql << std::endl; + double sql = sqlength(hnew2); + if (sql > sq_high) + long_edges.insert(long_edge(hnew2, sql)); } } - - ++nb_splits; + CGAL_assertion(halfedge_status_map_.size() == nb_valid_halfedges()); } std::cout << " done ("<< nb_splits << " splits)." << std::endl; + CGAL_expensive_assertion(is_triangle_mesh(mesh_)); + debug_status_map(); + debug_patch_border(); + debug_mesh_border(); + #ifdef CGAL_DUMP_REMESHING_STEPS dump("1-edge_split.off"); #endif @@ -222,7 +232,7 @@ namespace internal { Boost_bimap short_edges; BOOST_FOREACH(edge_descriptor e, edges(mesh_)) { - if (!is_split_or_collapse_allowed(e)) + if (!is_collapse_allowed(e)) continue; double sqlen = sqlength(e); if (sqlen < sq_low) @@ -238,25 +248,53 @@ namespace internal { double sqlen = eit->first; short_edges.right.erase(eit); - //let's try to collapse he into vb - vertex_descriptor va = target(he, mesh_); - vertex_descriptor vb = source(he, mesh_); - //handle the boundary case : - //a boundary edge can be collapsed, - //and an edge incident to boundary can be collapsed, - //but only if the boundary vertex is kept, so re-insert opposite(he) - //to collapse it - //todo : handle this border case using the status map - if (!is_border_edge(he, mesh_)) + //a PATCH_BORDER edge can be collapsed, + //and an edge incident to PATCH_BORDER can be collapsed, + //but only if the boundary vertex is kept, + //so re-insert opposite(he) to collapse it + if (is_on_border(he)) { - if (is_border(va, mesh_)) - { - if (!is_border(vb, mesh_)) - short_edges.insert(short_edge(opposite(he, mesh_), sqlen)); - continue; - } + he = opposite(he, mesh_); //he now is PATCH_BORDER + CGAL_assertion(is_on_patch_border(he)); } + else if (is_on_patch_border(opposite(he, mesh_))) + { + CGAL_assertion(is_on_mesh(he)); + he = opposite(he, mesh_); //he now is PATCH_BORDER + CGAL_assertion(is_on_patch_border(he)); + } + + //let's try to collapse he into vb + vertex_descriptor va = source(he, mesh_); + vertex_descriptor vb = target(he, mesh_); + + //todo : this test can be restricted to avoid some tests + if (is_on_patch_border(va) && !is_on_patch_border(vb)) + { + std::cout << "*"; + he = opposite(he, mesh_); + va = source(he, mesh_); + vb = target(he, mesh_); + + CGAL_assertion(is_on_patch_border(vb) && !is_on_patch_border(va)); + } + else std::cout << "!"; + + std::vector > vav; + BOOST_FOREACH(halfedge_descriptor ht, halfedges_around_target(va, mesh_)) + { + vav.push_back(std::make_pair(ht, status(ht))); + vav.push_back(std::make_pair(opposite(ht, mesh_), status(opposite(ht, mesh_)))); + } + std::vector > vbv; + BOOST_FOREACH(halfedge_descriptor ht, halfedges_around_target(vb, mesh_)) + { + vbv.push_back(std::make_pair(ht, status(ht))); + vbv.push_back(std::make_pair(opposite(ht, mesh_), status(opposite(ht, mesh_)))); + } + + CGAL_assertion(is_collapse_allowed(he)); if (degree(va, mesh_) < 3 || degree(vb, mesh_) < 3 @@ -291,13 +329,28 @@ namespace internal { short_edges.left.erase(opposite(hb, mesh_)); } - CGAL_assertion_code( - halfedge_descriptor en = next(he, mesh_); - halfedge_descriptor enp = next(opposite(he, mesh_), mesh_); - ); - //before collapse + unsigned int nb = nb_valid_halfedges(); + CGAL_assertion(nb == halfedge_status_map_.size()); + Halfedge_status hs = status(he); + Halfedge_status hso = status(opposite(he, mesh_)); + + std::cout << " status "<< hs << " opp = " << hso << std::endl; + + halfedge_descriptor ep_p = prev(opposite(he, mesh_), mesh_); + halfedge_descriptor epo_p = opposite(prev(opposite(he, mesh_), mesh_), mesh_); + + Halfedge_status s_ep_p = status( prev(opposite(he, mesh_), mesh_)); + Halfedge_status s_epo_p = status(opposite(prev(opposite(he, mesh_), mesh_), mesh_)); + CGAL_assertion_code(halfedge_descriptor en = next(he, mesh_)); + halfedge_descriptor enp = next(opposite(he, mesh_), mesh_); + halfedge_descriptor enop = opposite(enp, mesh_); + + bool mesh_border_case = is_on_border(opposite(he, mesh_)); + if (!mesh_border_case) + halfedge_and_opp_removed(prev(opposite(he, mesh_), mesh_)); halfedge_and_opp_removed(he); + halfedge_and_opp_removed(prev(he, mesh_)); //perform collapse Point target_point = vpmap_[vb]; @@ -305,20 +358,45 @@ namespace internal { vpmap_[vkept] = target_point; ++nb_collapses; + bool kepta = (va == vkept); + bool keptb = (vb == vkept); + + if (!mesh_border_case) + { + update_status(enp, s_ep_p); + update_status(enop, s_epo_p); + } + std::vector > vkv; + BOOST_FOREACH(halfedge_descriptor ht, halfedges_around_target(vkept, mesh_)) + { + vkv.push_back(std::make_pair(ht, status(ht))); + vkv.push_back(std::make_pair(opposite(ht, mesh_), status(opposite(ht, mesh_)))); + } + + unsigned int nbb = nb_valid_halfedges(); + CGAL_assertion(nbb == halfedge_status_map_.size()); CGAL_assertion(source(en, mesh_) == source(enp, mesh_)); - CGAL_expensive_assertion(is_triangle_mesh(mesh_)); + debug_status_map(); //insert new/remaining short edges BOOST_FOREACH(halfedge_descriptor ht, halfedges_around_target(vkept, mesh_)) { + if (!is_collapse_allowed(ht)) + continue; double sqlen = sqlength(ht); if (sqlen < sq_low) short_edges.insert(short_edge(ht, sqlen)); } - } + }//end if(collapse_ok) } std::cout << " done (" << nb_collapses << " collapses)." << std::endl; + CGAL_assertion(nb_valid_halfedges() == halfedge_status_map_.size()); + CGAL_expensive_assertion(is_triangle_mesh(mesh_)); + debug_status_map(); + debug_patch_border(); + debug_mesh_border(); + #ifdef CGAL_DUMP_REMESHING_STEPS dump("2-edge_collapse.off"); #endif @@ -349,9 +427,19 @@ namespace internal { + CGAL::abs(valence(vc) - target_valence(vc)) + CGAL::abs(valence(vd) - target_valence(vd)); + Halfedge_status s1 = status(he); + Halfedge_status s1o = status(opposite(he, mesh_)); + CGAL::Euler::flip_edge(he, mesh_); ++nb_flips; + Halfedge_status s2 = status(he); + Halfedge_status s2o = status(opposite(he, mesh_)); + CGAL_assertion(s1 == s2 && s1 == PATCH); + CGAL_assertion(s1o == s2o && s1o == PATCH); + CGAL_assertion(nb_valid_halfedges() == halfedge_status_map_.size()); + CGAL_assertion(!is_border(he, mesh_)); + CGAL_assertion( (vc == target(he, mesh_) && vd == source(he, mesh_)) || (vd == target(he, mesh_) && vc == source(he, mesh_))); @@ -365,12 +453,18 @@ namespace internal { { CGAL::Euler::flip_edge(he, mesh_); --nb_flips; + + Halfedge_status s3 = status(he); + CGAL_assertion(s1 == s3); + CGAL_assertion(!is_border(he, mesh_)); CGAL_assertion( (va == source(he, mesh_) && vb == target(he, mesh_)) || (vb == source(he, mesh_) && va == target(he, mesh_))); } } std::cout << "done. ("<< nb_flips << " flips)" << std::endl; + CGAL_assertion(nb_valid_halfedges() == halfedge_status_map_.size()); + debug_status_map(); #ifdef CGAL_DUMP_REMESHING_STEPS dump("3-edge_flips.off"); @@ -539,16 +633,28 @@ namespace internal { && (plane1.oriented_side(p4) != plane2.oriented_side(p4)); } - bool is_split_or_collapse_allowed(const edge_descriptor& e) const + //todo : simplify the list of cases + bool is_split_allowed(const edge_descriptor& e) const { halfedge_descriptor he = halfedge(e, mesh_); - return is_on_patch(he) + return is_on_patch(he) //opp is also on patch + || (is_on_border(he) && is_on_patch_border(opposite(he, mesh_))) + || (is_on_border(opposite(he, mesh_)) && is_on_patch_border(he)) + || is_on_patch_border(he) + || is_on_patch_border(opposite(he, mesh_)); + } + + //todo : allow to collapse edges on patch boundary (or not?) + bool is_collapse_allowed(const edge_descriptor& e) const + { + halfedge_descriptor he = halfedge(e, mesh_); + return is_on_patch(he) //opp is also on patch || (is_on_border(he) && is_on_patch_border(opposite(he, mesh_))) || (is_on_border(opposite(he, mesh_)) && is_on_patch_border(he)); } template - void tag_halfedges_status(FaceRange face_range) + void tag_halfedges_status(const FaceRange& face_range) { //tag MESH, //h and hopp belong to the mesh, not the patch //tag MESH_BORDER //h belongs to the mesh, face(hopp, pmesh) == null_face() @@ -580,23 +686,33 @@ namespace internal { typename std::map::iterator it = halfedge_status_map_.find(h); CGAL_assertion(it != halfedge_status_map_.end()); + CGAL_assertion(it->second == PATCH); - if (it->second == PATCH) - halfedge_status_map_[h] = PATCH_BORDER; - else - { - //todo : this is a workaround because get_border does not always provide - // halfedges from the right side - CGAL_assertion(status(opposite(h, mesh_)) == PATCH); - halfedge_status_map_[opposite(h, mesh_)] = PATCH_BORDER; - } + halfedge_status_map_[h] = PATCH_BORDER; } - CGAL_assertion(halfedge_status_map_.size() == num_halfedges(mesh_)); + CGAL_assertion(halfedge_status_map_.size() == nb_valid_halfedges()); + debug_patch_border(); + } + + Halfedge_status status(const halfedge_descriptor& h) const + { + typename std::map < halfedge_descriptor, Halfedge_status >::const_iterator + it = halfedge_status_map_.find(h); + CGAL_assertion(it != halfedge_status_map_.end()); + return it->second; + } + + void update_status(const halfedge_descriptor& h, const Halfedge_status& s) + { + CGAL_assertion(halfedge_status_map_.find(h) != halfedge_status_map_.end()); + halfedge_status_map_[h] = s; } bool is_on_patch(const halfedge_descriptor& h) const { - return status(h) == PATCH; + bool res =(status(h) == PATCH); + CGAL_assertion(res == (status(opposite(h, mesh_)) == PATCH)); + return res; } bool is_on_patch(const vertex_descriptor& v) const @@ -612,36 +728,58 @@ namespace internal { bool is_on_patch_border(const halfedge_descriptor& h) const { - return status(h) == PATCH_BORDER; + bool res = (status(h) == PATCH_BORDER); + if (res) + { + CGAL_assertion_code(Halfedge_status hs = status(opposite(h, mesh_))); + CGAL_assertion(hs == MESH_BORDER || hs == MESH); + } + return res; } bool is_on_patch_border(const edge_descriptor& e) const { return is_on_patch_border(halfedge(e,mesh_)) || is_on_patch_border(opposite(halfedge(e, mesh_), mesh_)); } + bool is_on_patch_border(const vertex_descriptor& v) const + { + BOOST_FOREACH(halfedge_descriptor h, halfedges_around_target(v, mesh_)) + { + if (is_on_patch_border(h) || is_on_patch_border(opposite(h, mesh_))) + return true; + } + return false; + } bool is_on_border(const halfedge_descriptor& h) const { - return status(h) == MESH_BORDER; + Halfedge_status s = status(h); + bool res = (s == MESH_BORDER); + CGAL_assertion(res == is_border(h, mesh_)); + CGAL_assertion(res == is_border(next(h, mesh_), mesh_)); + + CGAL_assertion_code(Halfedge_status s1 = status(opposite(h, mesh_))); + CGAL_assertion_code(Halfedge_status s2 = status(opposite(next(h, mesh_), mesh_))); + if (res && s1 != s2) + CGAL_assertion(is_on_patch_border(target(h, mesh_))); + return res; } + bool is_on_border(const edge_descriptor& e) const { return is_on_border(halfedge(e, mesh_)) || is_on_border(opposite(halfedge(e, mesh_), mesh_)); } - Halfedge_status status(const halfedge_descriptor& h) const + bool is_on_mesh(const halfedge_descriptor& h) const { - typename std::map < halfedge_descriptor, Halfedge_status >::const_iterator - it = halfedge_status_map_.find(h); - CGAL_assertion(it != halfedge_status_map_.end()); - return it->second; + return status(h) == MESH; } void halfedge_added(const halfedge_descriptor& h, const Halfedge_status& s) { - halfedge_status_map_[h] = s; + halfedge_status_map_.insert(std::make_pair(h, s)); } void halfedge_and_opp_removed(const halfedge_descriptor& h) @@ -650,13 +788,89 @@ namespace internal { halfedge_status_map_.erase(opposite(h, mesh_)); } + unsigned int nb_valid_halfedges() const + { + unsigned int nb = 0; + BOOST_FOREACH(halfedge_descriptor h, halfedges(mesh_)) + ++nb; + return nb; + } + + void debug_status_map() const + { + typedef typename std::map::value_type + HD_pair; + BOOST_FOREACH(const HD_pair& hs, halfedge_status_map_) + { + bool b1 = is_on_patch(hs.first); + bool b2 = is_on_patch_border(hs.first); + bool b3 = is_on_mesh(hs.first); + bool b4 = is_on_border(hs.first); + //std::cout << hs.first << "\t" << hs.second << "\t "; + //std::cout << b1 << " " << b2 << " " << b3 << " " << b4 << std::endl; + } + } + + void debug_patch_border() const + { + std::map patch_border; + typedef typename std::map::value_type + HD_pair; + BOOST_FOREACH(const HD_pair& hs, halfedge_status_map_) + { + if (is_on_patch_border(hs.first)) + { + if (patch_border.find(target(hs.first, mesh_)) != patch_border.end()) + patch_border[target(hs.first, mesh_)]++; + else + patch_border[target(hs.first, mesh_)] = 1; + + if (patch_border.find(source(hs.first, mesh_)) != patch_border.end()) + patch_border[source(hs.first, mesh_)]++; + else + patch_border[source(hs.first, mesh_)] = 1; + } + } + //check we found each vertex exactly twice + typedef typename std::map::value_type + V_pair; + BOOST_FOREACH(const V_pair& v, patch_border) + CGAL_assertion(v.second == 2); + } + + void debug_mesh_border() const + { + std::map mesh_border; + typedef typename std::map::value_type + HD_pair; + BOOST_FOREACH(const HD_pair& hs, halfedge_status_map_) + { + if (is_on_border(hs.first)) + { + if (mesh_border.find(target(hs.first, mesh_)) != mesh_border.end()) + mesh_border[target(hs.first, mesh_)]++; + else + mesh_border[target(hs.first, mesh_)] = 1; + + if (mesh_border.find(source(hs.first, mesh_)) != mesh_border.end()) + mesh_border[source(hs.first, mesh_)]++; + else + mesh_border[source(hs.first, mesh_)] = 1; + } + } + //check we found each vertex exactly twice + typedef typename std::map::value_type + V_pair; + BOOST_FOREACH(const V_pair& v, mesh_border) + CGAL_assertion(v.second == 2); + } + private: PolygonMesh& mesh_; VertexPointMap& vpmap_; const AABB_tree* tree_ptr_; bool own_tree_; Triangle_list input_triangles_; - std::vector patch_; std::map halfedge_status_map_; };//end class Incremental_remesher From 1797dab16d6bbdbd784847cd0a3698e17f7b6c2a Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Mon, 27 Apr 2015 12:01:40 +0200 Subject: [PATCH 022/217] fix notations --- .../internal/remesh_impl.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 538107057fc..087588d75af 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -337,14 +337,14 @@ namespace internal { std::cout << " status "<< hs << " opp = " << hso << std::endl; - halfedge_descriptor ep_p = prev(opposite(he, mesh_), mesh_); + halfedge_descriptor ep_p = prev(opposite(he, mesh_), mesh_); halfedge_descriptor epo_p = opposite(prev(opposite(he, mesh_), mesh_), mesh_); - Halfedge_status s_ep_p = status( prev(opposite(he, mesh_), mesh_)); - Halfedge_status s_epo_p = status(opposite(prev(opposite(he, mesh_), mesh_), mesh_)); + Halfedge_status s_ep_p = status(ep_p); + Halfedge_status s_epo_p = status(epo_p); CGAL_assertion_code(halfedge_descriptor en = next(he, mesh_)); - halfedge_descriptor enp = next(opposite(he, mesh_), mesh_); - halfedge_descriptor enop = opposite(enp, mesh_); + halfedge_descriptor en_p = next(opposite(he, mesh_), mesh_); + halfedge_descriptor eno_p = opposite(en_p, mesh_); bool mesh_border_case = is_on_border(opposite(he, mesh_)); if (!mesh_border_case) @@ -363,8 +363,8 @@ namespace internal { if (!mesh_border_case) { - update_status(enp, s_ep_p); - update_status(enop, s_epo_p); + update_status(en_p, s_ep_p); + update_status(eno_p, s_epo_p); } std::vector > vkv; BOOST_FOREACH(halfedge_descriptor ht, halfedges_around_target(vkept, mesh_)) @@ -375,7 +375,7 @@ namespace internal { unsigned int nbb = nb_valid_halfedges(); CGAL_assertion(nbb == halfedge_status_map_.size()); - CGAL_assertion(source(en, mesh_) == source(enp, mesh_)); + CGAL_assertion(source(en, mesh_) == source(en_p, mesh_)); debug_status_map(); //insert new/remaining short edges From 5e6a0e635d300c3bb974fb17d9e42a32368b1e5c Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Mon, 27 Apr 2015 12:49:30 +0200 Subject: [PATCH 023/217] fix status updates (does not fix it all) --- .../internal/remesh_impl.h | 106 ++++++++---------- 1 file changed, 47 insertions(+), 59 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 087588d75af..93af809b6df 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -121,8 +121,6 @@ namespace internal { long_edges.insert(long_edge(halfedge(e, mesh_), sqlen)); } - std::cout << "Halfedges : " << nb_valid_halfedges() << std::endl; - //split long edges unsigned int nb_splits = 0; while (!long_edges.empty()) @@ -200,14 +198,16 @@ namespace internal { long_edges.insert(long_edge(hnew2, sql)); } } - CGAL_assertion(halfedge_status_map_.size() == nb_valid_halfedges()); } std::cout << " done ("<< nb_splits << " splits)." << std::endl; +#ifdef CGAL_PMP_REMESHING_DEBUG CGAL_expensive_assertion(is_triangle_mesh(mesh_)); + CGAL_assertion(halfedge_status_map_.size() == nb_valid_halfedges()); debug_status_map(); debug_patch_border(); debug_mesh_border(); +#endif #ifdef CGAL_DUMP_REMESHING_STEPS dump("1-edge_split.off"); @@ -272,29 +272,14 @@ namespace internal { //todo : this test can be restricted to avoid some tests if (is_on_patch_border(va) && !is_on_patch_border(vb)) { - std::cout << "*"; he = opposite(he, mesh_); va = source(he, mesh_); vb = target(he, mesh_); CGAL_assertion(is_on_patch_border(vb) && !is_on_patch_border(va)); } - else std::cout << "!"; - std::vector > vav; - BOOST_FOREACH(halfedge_descriptor ht, halfedges_around_target(va, mesh_)) - { - vav.push_back(std::make_pair(ht, status(ht))); - vav.push_back(std::make_pair(opposite(ht, mesh_), status(opposite(ht, mesh_)))); - } - std::vector > vbv; - BOOST_FOREACH(halfedge_descriptor ht, halfedges_around_target(vb, mesh_)) - { - vbv.push_back(std::make_pair(ht, status(ht))); - vbv.push_back(std::make_pair(opposite(ht, mesh_), status(opposite(ht, mesh_)))); - } - - CGAL_assertion(is_collapse_allowed(he)); + CGAL_assertion(is_collapse_allowed(edge(he, mesh_))); if (degree(va, mesh_) < 3 || degree(vb, mesh_) < 3 @@ -330,21 +315,15 @@ namespace internal { } //before collapse - unsigned int nb = nb_valid_halfedges(); - CGAL_assertion(nb == halfedge_status_map_.size()); - Halfedge_status hs = status(he); - Halfedge_status hso = status(opposite(he, mesh_)); - - std::cout << " status "<< hs << " opp = " << hso << std::endl; - halfedge_descriptor ep_p = prev(opposite(he, mesh_), mesh_); - halfedge_descriptor epo_p = opposite(prev(opposite(he, mesh_), mesh_), mesh_); - - Halfedge_status s_ep_p = status(ep_p); - Halfedge_status s_epo_p = status(epo_p); - CGAL_assertion_code(halfedge_descriptor en = next(he, mesh_)); - halfedge_descriptor en_p = next(opposite(he, mesh_), mesh_); - halfedge_descriptor eno_p = opposite(en_p, mesh_); + halfedge_descriptor epo_p = opposite(ep_p, mesh_); + halfedge_descriptor en = next(he, mesh_); + halfedge_descriptor en_p = next(opposite(he, mesh_), mesh_); + Halfedge_status s_ep_p = status(ep_p); + Halfedge_status s_en_p = status(en_p); + Halfedge_status s_epo_p = status(epo_p); + Halfedge_status s_ep = status(prev(he, mesh_)); + Halfedge_status s_epo = status(opposite(prev(he, mesh_), mesh_)); bool mesh_border_case = is_on_border(opposite(he, mesh_)); if (!mesh_border_case) @@ -358,30 +337,23 @@ namespace internal { vpmap_[vkept] = target_point; ++nb_collapses; - bool kepta = (va == vkept); - bool keptb = (vb == vkept); - + // merge halfedge_status to keep the more important on both sides + merge_status(en, s_epo, s_ep); if (!mesh_border_case) - { - update_status(en_p, s_ep_p); - update_status(eno_p, s_epo_p); - } - std::vector > vkv; - BOOST_FOREACH(halfedge_descriptor ht, halfedges_around_target(vkept, mesh_)) - { - vkv.push_back(std::make_pair(ht, status(ht))); - vkv.push_back(std::make_pair(opposite(ht, mesh_), status(opposite(ht, mesh_)))); - } + merge_status(en_p, s_epo_p, s_ep_p); +#ifdef CGAL_PMP_REMESHING_DEBUG unsigned int nbb = nb_valid_halfedges(); CGAL_assertion(nbb == halfedge_status_map_.size()); CGAL_assertion(source(en, mesh_) == source(en_p, mesh_)); debug_status_map(); + debug_patch_border(); +#endif //insert new/remaining short edges BOOST_FOREACH(halfedge_descriptor ht, halfedges_around_target(vkept, mesh_)) { - if (!is_collapse_allowed(ht)) + if (!is_collapse_allowed(edge(ht, mesh_))) continue; double sqlen = sqlength(ht); if (sqlen < sq_low) @@ -391,11 +363,13 @@ namespace internal { } std::cout << " done (" << nb_collapses << " collapses)." << std::endl; +#ifdef CGAL_PMP_REMESHING_DEBUG CGAL_assertion(nb_valid_halfedges() == halfedge_status_map_.size()); CGAL_expensive_assertion(is_triangle_mesh(mesh_)); debug_status_map(); debug_patch_border(); debug_mesh_border(); +#endif #ifdef CGAL_DUMP_REMESHING_STEPS dump("2-edge_collapse.off"); @@ -463,8 +437,11 @@ namespace internal { } } std::cout << "done. ("<< nb_flips << " flips)" << std::endl; + +#ifdef CGAL_PMP_REMESHING_DEBUG CGAL_assertion(nb_valid_halfedges() == halfedge_status_map_.size()); debug_status_map(); +#endif #ifdef CGAL_DUMP_REMESHING_STEPS dump("3-edge_flips.off"); @@ -691,7 +668,10 @@ namespace internal { halfedge_status_map_[h] = PATCH_BORDER; } CGAL_assertion(halfedge_status_map_.size() == nb_valid_halfedges()); + +#ifdef CGAL_PMP_REMESHING_DEBUG debug_patch_border(); +#endif } Halfedge_status status(const halfedge_descriptor& h) const @@ -702,10 +682,26 @@ namespace internal { return it->second; } - void update_status(const halfedge_descriptor& h, const Halfedge_status& s) + void merge_status(const halfedge_descriptor& en, + const Halfedge_status& s_epo, + const Halfedge_status& s_ep) { - CGAL_assertion(halfedge_status_map_.find(h) != halfedge_status_map_.end()); - halfedge_status_map_[h] = s; + CGAL_assertion(halfedge_status_map_.find(en) != halfedge_status_map_.end()); + + //get missing data + halfedge_descriptor eno = opposite(en, mesh_); + Halfedge_status s_en = status(en); + Halfedge_status s_eno = status(eno); + + if(s_epo == MESH_BORDER + || s_ep == MESH_BORDER + || s_epo == PATCH_BORDER + || s_ep == PATCH_BORDER) + { + halfedge_status_map_[en] = s_epo; + halfedge_status_map_[eno] = s_ep; + } + // else keep current status for en and eno } bool is_on_patch(const halfedge_descriptor& h) const @@ -753,15 +749,9 @@ namespace internal { bool is_on_border(const halfedge_descriptor& h) const { - Halfedge_status s = status(h); - bool res = (s == MESH_BORDER); + bool res = (status(h) == MESH_BORDER); CGAL_assertion(res == is_border(h, mesh_)); CGAL_assertion(res == is_border(next(h, mesh_), mesh_)); - - CGAL_assertion_code(Halfedge_status s1 = status(opposite(h, mesh_))); - CGAL_assertion_code(Halfedge_status s2 = status(opposite(next(h, mesh_), mesh_))); - if (res && s1 != s2) - CGAL_assertion(is_on_patch_border(target(h, mesh_))); return res; } @@ -806,8 +796,6 @@ namespace internal { bool b2 = is_on_patch_border(hs.first); bool b3 = is_on_mesh(hs.first); bool b4 = is_on_border(hs.first); - //std::cout << hs.first << "\t" << hs.second << "\t "; - //std::cout << b1 << " " << b2 << " " << b3 << " " << b4 << std::endl; } } From c4496845e490f06e83dc0069a5421bae737e897b Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Mon, 27 Apr 2015 17:11:39 +0200 Subject: [PATCH 024/217] use const ref for FaceRange input --- .../CGAL/Polygon_mesh_processing/internal/remesh_impl.h | 2 +- .../include/CGAL/Polygon_mesh_processing/remesh.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 93af809b6df..23dd0d0909e 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -64,7 +64,7 @@ namespace internal { public: Incremental_remesher(PolygonMesh& pmesh - , FaceRange face_range + , const FaceRange& face_range , VertexPointMap& vpmap) : mesh_(pmesh) , vpmap_(vpmap) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h index fed8e9addb8..b242d3f4082 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h @@ -53,7 +53,7 @@ template void incremental_triangle_based_remeshing(PolygonMesh& pmesh - , FaceRange faces + , const FaceRange& faces , const double& target_edge_length , const NamedParameters& np) { @@ -90,7 +90,7 @@ void incremental_triangle_based_remeshing(PolygonMesh& pmesh template void incremental_triangle_based_remeshing(PolygonMesh& pmesh - , FaceRange faces + , const FaceRange& faces , const double& target_edge_length) { incremental_triangle_based_remeshing(pmesh, From d7caded018c338afa32227617eead81550ea609c Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Mon, 27 Apr 2015 17:18:26 +0200 Subject: [PATCH 025/217] remove useless template qualifier --- .../include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h | 1 - 1 file changed, 1 deletion(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 23dd0d0909e..9a624edf86a 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -630,7 +630,6 @@ namespace internal { || (is_on_border(opposite(he, mesh_)) && is_on_patch_border(he)); } - template void tag_halfedges_status(const FaceRange& face_range) { //tag MESH, //h and hopp belong to the mesh, not the patch From abc92fcc24eca4f92564186a8f936f13d405ea64 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Mon, 27 Apr 2015 17:27:16 +0200 Subject: [PATCH 026/217] fix assertion code --- .../CGAL/Polygon_mesh_processing/internal/remesh_impl.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 9a624edf86a..f4c5a899d4f 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -659,16 +659,16 @@ namespace internal { PMP::get_border(mesh_, face_range, std::back_inserter(border_halfedges)); BOOST_FOREACH(halfedge_descriptor h, border_halfedges) { - typename std::map::iterator it - = halfedge_status_map_.find(h); + typedef typename std::map::iterator IT; + CGAL_assertion_code(IT it = halfedge_status_map_.find(h)); CGAL_assertion(it != halfedge_status_map_.end()); CGAL_assertion(it->second == PATCH); halfedge_status_map_[h] = PATCH_BORDER; } - CGAL_assertion(halfedge_status_map_.size() == nb_valid_halfedges()); #ifdef CGAL_PMP_REMESHING_DEBUG + CGAL_assertion(halfedge_status_map_.size() == nb_valid_halfedges()); debug_patch_border(); #endif } From 54922319ff4750506b78245227590af74cd5e6b0 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Mon, 27 Apr 2015 17:29:37 +0200 Subject: [PATCH 027/217] remove todo --- .../include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h | 1 - 1 file changed, 1 deletion(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index f4c5a899d4f..b099c12d2ff 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -621,7 +621,6 @@ namespace internal { || is_on_patch_border(opposite(he, mesh_)); } - //todo : allow to collapse edges on patch boundary (or not?) bool is_collapse_allowed(const edge_descriptor& e) const { halfedge_descriptor he = halfedge(e, mesh_); From 577e0f08f052287f6f922b8080d7381256fd356f Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Mon, 27 Apr 2015 17:32:17 +0200 Subject: [PATCH 028/217] use macro and 17 digits in cout --- .../test/Polygon_mesh_processing/remeshing_test.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp index f087c76fb35..bd23a07f12d 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp @@ -1,4 +1,5 @@ +#define CGAL_PMP_REMESHING_DEBUG #include #include @@ -71,6 +72,7 @@ std::set k_ring(vertex_descriptor v, int main() { + std::cout.precision(17); std::ifstream input("data/U.off"); Mesh m; From 9e8ad02f94d1d4621ad8b8bb4af0c2884ef543d2 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 28 Apr 2015 11:00:14 +0200 Subject: [PATCH 029/217] more in remeshing test --- .../remeshing_test.cpp | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp index bd23a07f12d..7104a6f6188 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp @@ -1,5 +1,5 @@ -#define CGAL_PMP_REMESHING_DEBUG +//#define CGAL_PMP_REMESHING_DEBUG #include #include @@ -7,9 +7,11 @@ #include +#include #include #include #include +#include typedef CGAL::Exact_predicates_inexact_constructions_kernel K; typedef CGAL::Surface_mesh Mesh; @@ -70,21 +72,24 @@ std::set k_ring(vertex_descriptor v, return kring; } -int main() +int main(int argc, char* argv[]) { std::cout.precision(17); - std::ifstream input("data/U.off"); - Mesh m; + const char* filename = (argc > 1) ? argv[1] : "data/U.off"; + std::ifstream input(filename); + Mesh m; if (!input || !(input >> m)){ std::cerr << "Error: can not read file.\n"; return 1; } - double target_edge_length = 0.01; + double target_edge_length = (argc > 2) ? atof(argv[2]) : 0.01; double low = 4. / 5. * target_edge_length; double high = 4. / 3. * target_edge_length; + unsigned int nb_iter = (argc > 3) ? atoi(argv[3]) : 5; + unsigned int center_id = 26; unsigned int i = 0; vertex_descriptor patch_center; @@ -98,16 +103,21 @@ int main() } const std::set& patch = k_ring(patch_center, 3, m); + CGAL::Timer t; + t.start(); + CGAL::Polygon_mesh_processing::incremental_triangle_based_remeshing(m, - patch, + faces(m),//patch, target_edge_length, - CGAL::Polygon_mesh_processing::parameters::number_of_iterations(5)); + CGAL::Polygon_mesh_processing::parameters::number_of_iterations(nb_iter)); - boost::property_map::const_type vpmap - = boost::get(CGAL::vertex_point, m); + t.stop(); + std::cout << "Remeshing took " << t.time() << std::endl; + //boost::property_map::const_type vpmap + // = boost::get(CGAL::vertex_point, m); - std::ofstream out("U_remeshed.off"); + std::ofstream out("remeshed.off"); out << m; out.close(); From 8d06f1861c1c1a97842ec95c84fd1ef069c510a0 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 28 Apr 2015 11:13:11 +0200 Subject: [PATCH 030/217] add input dialog for nb of iterations of remeshing --- ...hedron_demo_isotropic_remeshing_plugin.cpp | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp index a45a4e5696e..c7b58e7b4c2 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp @@ -87,6 +87,20 @@ public Q_SLOTS: std::cout << "Remeshing aborted" << std::endl; return; } + double nb_iter = QInputDialog::getInt(this->mw, + QString("Isotropic remeshing : Number of iterations"), + QString("Enter number of iterations"),//question + 1, //value + 1, //min + 1000, //max + 1, //step + &ok); //Qt::WindowFlags flags = 0); + if (!ok) + { + std::cout << "Remeshing aborted" << std::endl; + return; + } + // wait cursor QApplication::setOverrideCursor(Qt::WaitCursor); @@ -97,7 +111,8 @@ public Q_SLOTS: CGAL::Polygon_mesh_processing::incremental_triangle_based_remeshing( *selection_item->polyhedron() , selection_item->selected_facets - , target_length); + , target_length + , CGAL::Polygon_mesh_processing::parameters::number_of_iterations(nb_iter)); selection_item->changed_with_poly_item(); } @@ -105,7 +120,8 @@ public Q_SLOTS: CGAL::Polygon_mesh_processing::incremental_triangle_based_remeshing( *poly_item->polyhedron() , faces(*poly_item->polyhedron()) - , target_length); + , target_length + , CGAL::Polygon_mesh_processing::parameters::number_of_iterations(nb_iter)); poly_item->changed(); } From 8a8e3f288863773c3e6126ecc9d017b9ee062ee3 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 15 May 2015 17:16:37 +0200 Subject: [PATCH 031/217] detect sharp edges and surface patches --- Polyhedron/demo/Polyhedron/CMakeLists.txt | 6 + ...yhedron_demo_detect_sharp_edges_plugin.cpp | 127 ++++++++++++++++++ ...ron_demo_detect_surface_patches_plugin.cpp | 102 ++++++++++++++ 3 files changed, 235 insertions(+) create mode 100644 Polyhedron/demo/Polyhedron/Polyhedron_demo_detect_sharp_edges_plugin.cpp create mode 100644 Polyhedron/demo/Polyhedron/Polyhedron_demo_detect_surface_patches_plugin.cpp diff --git a/Polyhedron/demo/Polyhedron/CMakeLists.txt b/Polyhedron/demo/Polyhedron/CMakeLists.txt index c41592a91b7..5b36f18593a 100644 --- a/Polyhedron/demo/Polyhedron/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/CMakeLists.txt @@ -503,6 +503,12 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND) polyhedron_demo_plugin(isotropic_remeshing_plugin Polyhedron_demo_isotropic_remeshing_plugin) target_link_libraries(isotropic_remeshing_plugin scene_polyhedron_item scene_polyhedron_selection_item) + + polyhedron_demo_plugin(detect_sharp_edges_plugin Polyhedron_demo_detect_sharp_edges_plugin) + target_link_libraries(detect_sharp_edges_plugin scene_polyhedron_item) + + polyhedron_demo_plugin(detect_surface_patches_plugin Polyhedron_demo_detect_surface_patches_plugin) + target_link_libraries(detect_surface_patches_plugin scene_polyhedron_item) # # Exporting diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_detect_sharp_edges_plugin.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_detect_sharp_edges_plugin.cpp new file mode 100644 index 00000000000..36cf09155c9 --- /dev/null +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_detect_sharp_edges_plugin.cpp @@ -0,0 +1,127 @@ +#include +#include +#include +#include +#include + +#include "Scene_polyhedron_item.h" +#include "Polyhedron_type.h" + +#include "Polyhedron_demo_plugin_helper.h" +#include "Polyhedron_demo_plugin_interface.h" + +#include + +class Polyhedron_demo_detect_sharp_edges_plugin : + public QObject, + public Polyhedron_demo_plugin_helper +{ + Q_OBJECT + Q_INTERFACES(Polyhedron_demo_plugin_interface) + +public: + void init(QMainWindow* mainWindow, Scene_interface* scene_interface) { + this->scene = scene_interface; + this->mw = mainWindow; + actionSharEdges = new QAction("Detect sharp features", mw); + actionSharEdges->setObjectName("detectSharpFeaturesAction"); + if(actionSharEdges) { + connect(actionSharEdges, SIGNAL(triggered()), + this, SLOT(detectSharpEdgesWithInputDialog())); + } + } + + bool applicable(QAction*) const + { + Q_FOREACH(int index, scene->selectionIndices()) + { + if (qobject_cast(scene->item(scene->mainSelectionIndex()))) + return true; + } + return false; + } + + // used by Polyhedron_demo_plugin_helper + QList actions() const { + return QList() << actionSharEdges; + } + +public slots: +void detectSharpEdges(bool input_dialog = false, double angle = 60); + void detectSharpEdgesWithInputDialog(); + +protected: + Kernel::Vector_3 facet_normal(Polyhedron::Facet_handle f); + bool is_sharp(Polyhedron::Halfedge_handle he); + +private: + QAction* actionSharEdges; +}; // end Polyhedron_demo_detect_sharp_edges_plugin + +void Polyhedron_demo_detect_sharp_edges_plugin::detectSharpEdgesWithInputDialog() +{ + detectSharpEdges(true); +} + +void Polyhedron_demo_detect_sharp_edges_plugin::detectSharpEdges(bool input_dialog, + double angle) +{ + typedef std::pair Poly_tuple; + + // Get selected items + QList polyhedrons; + Q_FOREACH(int index, scene->selectionIndices()) + { + Scene_polyhedron_item* item = + qobject_cast(scene->item(index)); + if(!item) + return; + + Polyhedron* pMesh = item->polyhedron(); + if(!pMesh) + return; + + polyhedrons << make_pair(index, pMesh); + } + + if(input_dialog) { + bool ok = true; + angle = QInputDialog::getDouble(NULL, + tr("Sharp edges max angle"), + tr("Angle in degrees between 0 and 180:"), + angle, // value + 0., // min + 180., // max + 2, // decimals + &ok); + if(!ok) return; + } + // Detect edges + QApplication::setOverrideCursor(Qt::WaitCursor); + CGAL::Mesh_3::Detect_features_in_polyhedra detect_features; + Q_FOREACH(Poly_tuple tuple, polyhedrons) + { + Polyhedron* pMesh = tuple.second; + if(!pMesh) continue; + + for(Polyhedron::Edge_iterator + eit = pMesh->edges_begin(), + end = pMesh->edges_end(); eit != end; ++eit) + { + eit->set_feature_edge(false); + } + + // Detect edges in current polyhedron + detect_features.detect_sharp_edges(*pMesh, angle); + + // update scene + scene->itemChanged(tuple.first); + } + + // default cursor + QApplication::restoreOverrideCursor(); +} + +Q_EXPORT_PLUGIN2(Polyhedron_demo_detect_sharp_edges_plugin, Polyhedron_demo_detect_sharp_edges_plugin) + +#include "Polyhedron_demo_detect_sharp_edges_plugin.moc" diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_detect_surface_patches_plugin.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_detect_surface_patches_plugin.cpp new file mode 100644 index 00000000000..3c74929c8d9 --- /dev/null +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_detect_surface_patches_plugin.cpp @@ -0,0 +1,102 @@ +#include +#include +#include +#include + +#include "Scene_polyhedron_item.h" +#include "Polyhedron_demo_plugin_helper.h" +#include "Polyhedron_type.h" + +#include + +#include +#include + +class Polyhedron_demo_detect_surface_patches_plugin : + public QObject, + public Polyhedron_demo_plugin_helper +{ + Q_OBJECT + Q_INTERFACES(Polyhedron_demo_plugin_interface) + +public: + void init(QMainWindow* mainWindow, Scene_interface* scene_interface) + { + this->scene = scene_interface; + this->mw = mainWindow; + actionSurfacePatches = new QAction("Detect surface patches", mw); + actionSurfacePatches->setObjectName("detectSurfacePatches"); + if (actionSurfacePatches ) + { + connect(actionSurfacePatches, SIGNAL(triggered()), + this, SLOT(detectSurfacePatches())); + } + } + + QList actions() const + { + return QList() << actionSurfacePatches; + } + + bool applicable(QAction*) const + { + Q_FOREACH(int index, scene->selectionIndices()) + { + if (qobject_cast(scene->item(scene->mainSelectionIndex()))) + return true; + } + return false; + } + +public slots: + void detectSurfacePatches(); + +private: + QAction* actionSurfacePatches; +}; // end Polyhedron_demo_detect_surface_patches_plugin + + +void +Polyhedron_demo_detect_surface_patches_plugin:: +detectSurfacePatches() +{ + typedef std::pair Poly_tuple; + + // Get selected items + QList polyhedrons; + Q_FOREACH(int index, scene->selectionIndices()) + { + Scene_polyhedron_item* item = + qobject_cast(scene->item(index)); + if ( NULL == item ) { continue; } + + Polyhedron* pMesh = item->polyhedron(); + if ( NULL == pMesh ) { continue; } + + polyhedrons << std::make_pair(index, pMesh); + } + + QApplication::setOverrideCursor(Qt::WaitCursor); + + // Detect surface patches + CGAL::Mesh_3::Detect_features_in_polyhedra detect_features; + Q_FOREACH(Poly_tuple tuple, polyhedrons) + { + Polyhedron* pMesh = tuple.second; + if ( NULL == pMesh ) { continue; } + + // Detect patches in current polyhedron + detect_features.detect_surface_patches(*pMesh); + + // update scene + scene->itemChanged(tuple.first); + } + + // default cursor + QApplication::restoreOverrideCursor(); +} + +Q_EXPORT_PLUGIN2(Polyhedron_demo_detect_surface_patches_plugin, + Polyhedron_demo_detect_surface_patches_plugin) + +#include "Polyhedron_demo_detect_surface_patches_plugin.moc" From 73642feab7ac069df9b3b55d16a90eb65d9d8156 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 15 May 2015 17:47:44 +0200 Subject: [PATCH 032/217] add checbox to use feature edges as selection boundaries --- .../demo/Polyhedron/Selection_widget.ui | 62 ++++++++++++------- 1 file changed, 41 insertions(+), 21 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Selection_widget.ui b/Polyhedron/demo/Polyhedron/Selection_widget.ui index e67698ec800..eff12e394e7 100644 --- a/Polyhedron/demo/Polyhedron/Selection_widget.ui +++ b/Polyhedron/demo/Polyhedron/Selection_widget.ui @@ -180,6 +180,47 @@ + + + + + + + + + 10 + 10 + 151 + 16 + + + + Use feature edges + + + + + + + + Create Point Set Item from Selected Vertices + + + + + + + Create Polyline Item from Selected Edges + + + + + + + Create Polyhedron Item from Selected Facets + + + @@ -213,27 +254,6 @@ - - - - Create Point Set Item from Selected Vertices - - - - - - - Create Polyline Item from Selected Edges - - - - - - - Create Polyhedron Item from Selected Facets - - - From 83957ed495bce12cd0df1f99245578e695b31bb7 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Mon, 18 May 2015 17:31:32 +0200 Subject: [PATCH 033/217] add code to the selection tool to be able to select a surface patch for now it works only for facets and the checkbox is not used --- BGL/include/CGAL/boost/graph/selection.h | 11 ++- .../internal/remesh_impl.h | 2 +- .../Polyhedron_demo_selection_plugin.cpp | 1 + .../Scene_polyhedron_item_k_ring_selection.h | 44 ++++++++-- .../Scene_polyhedron_selection_item.h | 8 +- .../demo/Polyhedron/Selection_widget.ui | 82 +++++++++++-------- 6 files changed, 103 insertions(+), 45 deletions(-) diff --git a/BGL/include/CGAL/boost/graph/selection.h b/BGL/include/CGAL/boost/graph/selection.h index 01e3169eb15..b9b7c301429 100644 --- a/BGL/include/CGAL/boost/graph/selection.h +++ b/BGL/include/CGAL/boost/graph/selection.h @@ -65,19 +65,24 @@ extract_selection_boundary( } } //end of namespace internal -template +template OutputIterator dilate_face_selection( const FaceRange& selection, FaceGraph& graph, unsigned int k, IsFaceSelectedPMap is_selected, + SurfacePatchPMap surface_patch, OutputIterator out) { typedef boost::graph_traits GT; typedef typename GT::face_descriptor face_descriptor; typedef typename GT::halfedge_descriptor halfedge_descriptor; + int patch_id = (selection.empty()) + ? -1 + : get(surface_patch, *selection.begin()); + std::vector current_selection(selection.begin(), selection.end()); for (unsigned int i=0; i(degree(v, mesh_)); } int target_valence(const vertex_descriptor& v) const diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_selection_plugin.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_selection_plugin.cpp index 31a1554e3ec..1ae2f1f81ac 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_demo_selection_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_selection_plugin.cpp @@ -306,6 +306,7 @@ public Q_SLOTS: } int steps = ui_widget.Dilate_erode_spin_box->value(); + bool use_surface_patches = ui_widget.use_patches_checkBox->isChecked(); selection_item->dilate_or_erode(steps); } // To handle empty selection items coming from loader diff --git a/Polyhedron/demo/Polyhedron/Scene_polyhedron_item_k_ring_selection.h b/Polyhedron/demo/Polyhedron/Scene_polyhedron_item_k_ring_selection.h index 7d1d16f16a3..cd8ef08cad2 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polyhedron_item_k_ring_selection.h +++ b/Polyhedron/demo/Polyhedron/Scene_polyhedron_item_k_ring_selection.h @@ -15,6 +15,39 @@ #include +template +struct Surface_patch_property_map +{ + typedef boost::graph_traits::edge_descriptor edge_descriptor; + typedef boost::graph_traits::face_descriptor face_descriptor; + typedef boost::graph_traits::vertex_descriptor vertex_descriptor; + + static face_descriptor face(edge_descriptor e) { return face(e, poly_); } + static face_descriptor face(face_descriptor f) { return f; } + static face_descriptor face(vertex_descriptor v) { + return face(halfedge(v, poly_), poly_); + } +private: + const Polyhedron& poly_; + +public: + Surface_patch_property_map(const Polyhedron& p) + : poly_(p) + {} + + friend int get(Surface_patch_property_map, Handle h) + { + if (use_surface_patches) + return face(h)->patch_id(); + else + return -1; + } + friend void put(Surface_patch_property_map, Handle h, int pid) + { + face(h)->set_patch_id(pid); + } +}; + class SCENE_POLYHEDRON_ITEM_K_RING_SELECTION_EXPORT Scene_polyhedron_item_k_ring_selection : public QObject { @@ -22,7 +55,7 @@ class SCENE_POLYHEDRON_ITEM_K_RING_SELECTION_EXPORT Scene_polyhedron_item_k_ring public: struct Active_handle { enum Type{ VERTEX = 0, FACET = 1, EDGE = 2 }; }; - typedef boost::graph_traits::edge_descriptor edge_descriptor; + typedef boost::graph_traits::edge_descriptor edge_descriptor; // Hold mouse keyboard state together struct Mouse_keyboard_state @@ -133,10 +166,11 @@ protected: selection.insert(clicked); if (k>0) CGAL::dilate_face_selection(CGAL::make_array(clicked), - *poly_item->polyhedron(), - k, - Is_selected_from_set(selection), - CGAL::Emptyset_iterator()); + *poly_item->polyhedron(), + k, + Is_selected_from_set(selection), + Surface_patch_property_map(*poly_item->polyhedron()), + CGAL::Emptyset_iterator()); return selection; } diff --git a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h index e4a68907fa2..b7b907fd5e5 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h +++ b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h @@ -105,7 +105,9 @@ struct Selection_traits IsFaceSelectedPMap is_selected, OutputIterator out) { - return dilate_face_selection(selection, graph, k, is_selected, out); + return dilate_face_selection(selection, graph, k, is_selected, + Surface_patch_property_map(graph), + out); } SelectionItem* item; @@ -576,8 +578,8 @@ public: }; template - void dilate_selection(unsigned int steps) { - + void dilate_selection(unsigned int steps) + { typedef Selection_traits Tr; Tr tr(this); diff --git a/Polyhedron/demo/Polyhedron/Selection_widget.ui b/Polyhedron/demo/Polyhedron/Selection_widget.ui index eff12e394e7..0595594a5e4 100644 --- a/Polyhedron/demo/Polyhedron/Selection_widget.ui +++ b/Polyhedron/demo/Polyhedron/Selection_widget.ui @@ -182,43 +182,36 @@ + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 35 + + - - - - 10 - 10 - 151 - 16 - - - - Use feature edges - - - - - - - - Create Point Set Item from Selected Vertices - - - - - - - Create Polyline Item from Selected Edges - - - - - - - Create Polyhedron Item from Selected Facets - + + + + + Use surface patches + + + + @@ -264,6 +257,27 @@ + + + + Create Point Set Item from Selected Vertices + + + + + + + Create Polyline Item from Selected Edges + + + + + + + Create Polyhedron Item from Selected Facets + + + From d34d47a6d592fff6a11329e210d693ba4483ef28 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 19 May 2015 15:36:16 +0200 Subject: [PATCH 034/217] Revert "detect sharp edges and surface patches" This reverts commit 80b1363f1db4db8391398188bcb33427ffc69aac. --- BGL/include/CGAL/boost/graph/selection.h | 11 +- .../internal/remesh_impl.h | 2 +- Polyhedron/demo/Polyhedron/CMakeLists.txt | 6 - ...yhedron_demo_detect_sharp_edges_plugin.cpp | 127 ------------------ ...ron_demo_detect_surface_patches_plugin.cpp | 102 -------------- .../Polyhedron_demo_selection_plugin.cpp | 1 - .../Scene_polyhedron_item_k_ring_selection.h | 44 +----- .../Scene_polyhedron_selection_item.h | 4 +- .../demo/Polyhedron/Selection_widget.ui | 47 ++----- 9 files changed, 22 insertions(+), 322 deletions(-) delete mode 100644 Polyhedron/demo/Polyhedron/Polyhedron_demo_detect_sharp_edges_plugin.cpp delete mode 100644 Polyhedron/demo/Polyhedron/Polyhedron_demo_detect_surface_patches_plugin.cpp diff --git a/BGL/include/CGAL/boost/graph/selection.h b/BGL/include/CGAL/boost/graph/selection.h index b9b7c301429..01e3169eb15 100644 --- a/BGL/include/CGAL/boost/graph/selection.h +++ b/BGL/include/CGAL/boost/graph/selection.h @@ -65,24 +65,19 @@ extract_selection_boundary( } } //end of namespace internal -template +template OutputIterator dilate_face_selection( const FaceRange& selection, FaceGraph& graph, unsigned int k, IsFaceSelectedPMap is_selected, - SurfacePatchPMap surface_patch, OutputIterator out) { typedef boost::graph_traits GT; typedef typename GT::face_descriptor face_descriptor; typedef typename GT::halfedge_descriptor halfedge_descriptor; - int patch_id = (selection.empty()) - ? -1 - : get(surface_patch, *selection.begin()); - std::vector current_selection(selection.begin(), selection.end()); for (unsigned int i=0; i(degree(v, mesh_)); + return degree(v, mesh_); } int target_valence(const vertex_descriptor& v) const diff --git a/Polyhedron/demo/Polyhedron/CMakeLists.txt b/Polyhedron/demo/Polyhedron/CMakeLists.txt index 5b36f18593a..39216f78828 100644 --- a/Polyhedron/demo/Polyhedron/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/CMakeLists.txt @@ -504,12 +504,6 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND) polyhedron_demo_plugin(isotropic_remeshing_plugin Polyhedron_demo_isotropic_remeshing_plugin) target_link_libraries(isotropic_remeshing_plugin scene_polyhedron_item scene_polyhedron_selection_item) - polyhedron_demo_plugin(detect_sharp_edges_plugin Polyhedron_demo_detect_sharp_edges_plugin) - target_link_libraries(detect_sharp_edges_plugin scene_polyhedron_item) - - polyhedron_demo_plugin(detect_surface_patches_plugin Polyhedron_demo_detect_surface_patches_plugin) - target_link_libraries(detect_surface_patches_plugin scene_polyhedron_item) - # # Exporting # diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_detect_sharp_edges_plugin.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_detect_sharp_edges_plugin.cpp deleted file mode 100644 index 36cf09155c9..00000000000 --- a/Polyhedron/demo/Polyhedron/Polyhedron_demo_detect_sharp_edges_plugin.cpp +++ /dev/null @@ -1,127 +0,0 @@ -#include -#include -#include -#include -#include - -#include "Scene_polyhedron_item.h" -#include "Polyhedron_type.h" - -#include "Polyhedron_demo_plugin_helper.h" -#include "Polyhedron_demo_plugin_interface.h" - -#include - -class Polyhedron_demo_detect_sharp_edges_plugin : - public QObject, - public Polyhedron_demo_plugin_helper -{ - Q_OBJECT - Q_INTERFACES(Polyhedron_demo_plugin_interface) - -public: - void init(QMainWindow* mainWindow, Scene_interface* scene_interface) { - this->scene = scene_interface; - this->mw = mainWindow; - actionSharEdges = new QAction("Detect sharp features", mw); - actionSharEdges->setObjectName("detectSharpFeaturesAction"); - if(actionSharEdges) { - connect(actionSharEdges, SIGNAL(triggered()), - this, SLOT(detectSharpEdgesWithInputDialog())); - } - } - - bool applicable(QAction*) const - { - Q_FOREACH(int index, scene->selectionIndices()) - { - if (qobject_cast(scene->item(scene->mainSelectionIndex()))) - return true; - } - return false; - } - - // used by Polyhedron_demo_plugin_helper - QList actions() const { - return QList() << actionSharEdges; - } - -public slots: -void detectSharpEdges(bool input_dialog = false, double angle = 60); - void detectSharpEdgesWithInputDialog(); - -protected: - Kernel::Vector_3 facet_normal(Polyhedron::Facet_handle f); - bool is_sharp(Polyhedron::Halfedge_handle he); - -private: - QAction* actionSharEdges; -}; // end Polyhedron_demo_detect_sharp_edges_plugin - -void Polyhedron_demo_detect_sharp_edges_plugin::detectSharpEdgesWithInputDialog() -{ - detectSharpEdges(true); -} - -void Polyhedron_demo_detect_sharp_edges_plugin::detectSharpEdges(bool input_dialog, - double angle) -{ - typedef std::pair Poly_tuple; - - // Get selected items - QList polyhedrons; - Q_FOREACH(int index, scene->selectionIndices()) - { - Scene_polyhedron_item* item = - qobject_cast(scene->item(index)); - if(!item) - return; - - Polyhedron* pMesh = item->polyhedron(); - if(!pMesh) - return; - - polyhedrons << make_pair(index, pMesh); - } - - if(input_dialog) { - bool ok = true; - angle = QInputDialog::getDouble(NULL, - tr("Sharp edges max angle"), - tr("Angle in degrees between 0 and 180:"), - angle, // value - 0., // min - 180., // max - 2, // decimals - &ok); - if(!ok) return; - } - // Detect edges - QApplication::setOverrideCursor(Qt::WaitCursor); - CGAL::Mesh_3::Detect_features_in_polyhedra detect_features; - Q_FOREACH(Poly_tuple tuple, polyhedrons) - { - Polyhedron* pMesh = tuple.second; - if(!pMesh) continue; - - for(Polyhedron::Edge_iterator - eit = pMesh->edges_begin(), - end = pMesh->edges_end(); eit != end; ++eit) - { - eit->set_feature_edge(false); - } - - // Detect edges in current polyhedron - detect_features.detect_sharp_edges(*pMesh, angle); - - // update scene - scene->itemChanged(tuple.first); - } - - // default cursor - QApplication::restoreOverrideCursor(); -} - -Q_EXPORT_PLUGIN2(Polyhedron_demo_detect_sharp_edges_plugin, Polyhedron_demo_detect_sharp_edges_plugin) - -#include "Polyhedron_demo_detect_sharp_edges_plugin.moc" diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_detect_surface_patches_plugin.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_detect_surface_patches_plugin.cpp deleted file mode 100644 index 3c74929c8d9..00000000000 --- a/Polyhedron/demo/Polyhedron/Polyhedron_demo_detect_surface_patches_plugin.cpp +++ /dev/null @@ -1,102 +0,0 @@ -#include -#include -#include -#include - -#include "Scene_polyhedron_item.h" -#include "Polyhedron_demo_plugin_helper.h" -#include "Polyhedron_type.h" - -#include - -#include -#include - -class Polyhedron_demo_detect_surface_patches_plugin : - public QObject, - public Polyhedron_demo_plugin_helper -{ - Q_OBJECT - Q_INTERFACES(Polyhedron_demo_plugin_interface) - -public: - void init(QMainWindow* mainWindow, Scene_interface* scene_interface) - { - this->scene = scene_interface; - this->mw = mainWindow; - actionSurfacePatches = new QAction("Detect surface patches", mw); - actionSurfacePatches->setObjectName("detectSurfacePatches"); - if (actionSurfacePatches ) - { - connect(actionSurfacePatches, SIGNAL(triggered()), - this, SLOT(detectSurfacePatches())); - } - } - - QList actions() const - { - return QList() << actionSurfacePatches; - } - - bool applicable(QAction*) const - { - Q_FOREACH(int index, scene->selectionIndices()) - { - if (qobject_cast(scene->item(scene->mainSelectionIndex()))) - return true; - } - return false; - } - -public slots: - void detectSurfacePatches(); - -private: - QAction* actionSurfacePatches; -}; // end Polyhedron_demo_detect_surface_patches_plugin - - -void -Polyhedron_demo_detect_surface_patches_plugin:: -detectSurfacePatches() -{ - typedef std::pair Poly_tuple; - - // Get selected items - QList polyhedrons; - Q_FOREACH(int index, scene->selectionIndices()) - { - Scene_polyhedron_item* item = - qobject_cast(scene->item(index)); - if ( NULL == item ) { continue; } - - Polyhedron* pMesh = item->polyhedron(); - if ( NULL == pMesh ) { continue; } - - polyhedrons << std::make_pair(index, pMesh); - } - - QApplication::setOverrideCursor(Qt::WaitCursor); - - // Detect surface patches - CGAL::Mesh_3::Detect_features_in_polyhedra detect_features; - Q_FOREACH(Poly_tuple tuple, polyhedrons) - { - Polyhedron* pMesh = tuple.second; - if ( NULL == pMesh ) { continue; } - - // Detect patches in current polyhedron - detect_features.detect_surface_patches(*pMesh); - - // update scene - scene->itemChanged(tuple.first); - } - - // default cursor - QApplication::restoreOverrideCursor(); -} - -Q_EXPORT_PLUGIN2(Polyhedron_demo_detect_surface_patches_plugin, - Polyhedron_demo_detect_surface_patches_plugin) - -#include "Polyhedron_demo_detect_surface_patches_plugin.moc" diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_selection_plugin.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_selection_plugin.cpp index 1ae2f1f81ac..31a1554e3ec 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_demo_selection_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_selection_plugin.cpp @@ -306,7 +306,6 @@ public Q_SLOTS: } int steps = ui_widget.Dilate_erode_spin_box->value(); - bool use_surface_patches = ui_widget.use_patches_checkBox->isChecked(); selection_item->dilate_or_erode(steps); } // To handle empty selection items coming from loader diff --git a/Polyhedron/demo/Polyhedron/Scene_polyhedron_item_k_ring_selection.h b/Polyhedron/demo/Polyhedron/Scene_polyhedron_item_k_ring_selection.h index cd8ef08cad2..7d1d16f16a3 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polyhedron_item_k_ring_selection.h +++ b/Polyhedron/demo/Polyhedron/Scene_polyhedron_item_k_ring_selection.h @@ -15,39 +15,6 @@ #include -template -struct Surface_patch_property_map -{ - typedef boost::graph_traits::edge_descriptor edge_descriptor; - typedef boost::graph_traits::face_descriptor face_descriptor; - typedef boost::graph_traits::vertex_descriptor vertex_descriptor; - - static face_descriptor face(edge_descriptor e) { return face(e, poly_); } - static face_descriptor face(face_descriptor f) { return f; } - static face_descriptor face(vertex_descriptor v) { - return face(halfedge(v, poly_), poly_); - } -private: - const Polyhedron& poly_; - -public: - Surface_patch_property_map(const Polyhedron& p) - : poly_(p) - {} - - friend int get(Surface_patch_property_map, Handle h) - { - if (use_surface_patches) - return face(h)->patch_id(); - else - return -1; - } - friend void put(Surface_patch_property_map, Handle h, int pid) - { - face(h)->set_patch_id(pid); - } -}; - class SCENE_POLYHEDRON_ITEM_K_RING_SELECTION_EXPORT Scene_polyhedron_item_k_ring_selection : public QObject { @@ -55,7 +22,7 @@ class SCENE_POLYHEDRON_ITEM_K_RING_SELECTION_EXPORT Scene_polyhedron_item_k_ring public: struct Active_handle { enum Type{ VERTEX = 0, FACET = 1, EDGE = 2 }; }; - typedef boost::graph_traits::edge_descriptor edge_descriptor; + typedef boost::graph_traits::edge_descriptor edge_descriptor; // Hold mouse keyboard state together struct Mouse_keyboard_state @@ -166,11 +133,10 @@ protected: selection.insert(clicked); if (k>0) CGAL::dilate_face_selection(CGAL::make_array(clicked), - *poly_item->polyhedron(), - k, - Is_selected_from_set(selection), - Surface_patch_property_map(*poly_item->polyhedron()), - CGAL::Emptyset_iterator()); + *poly_item->polyhedron(), + k, + Is_selected_from_set(selection), + CGAL::Emptyset_iterator()); return selection; } diff --git a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h index b7b907fd5e5..5d281d3b18d 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h +++ b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h @@ -105,9 +105,7 @@ struct Selection_traits IsFaceSelectedPMap is_selected, OutputIterator out) { - return dilate_face_selection(selection, graph, k, is_selected, - Surface_patch_property_map(graph), - out); + return dilate_face_selection(selection, graph, k, is_selected, out); } SelectionItem* item; diff --git a/Polyhedron/demo/Polyhedron/Selection_widget.ui b/Polyhedron/demo/Polyhedron/Selection_widget.ui index 0595594a5e4..d178b56ad88 100644 --- a/Polyhedron/demo/Polyhedron/Selection_widget.ui +++ b/Polyhedron/demo/Polyhedron/Selection_widget.ui @@ -180,40 +180,6 @@ - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 16777215 - 35 - - - - - - - - - - Use surface patches - - - - - - @@ -311,6 +277,19 @@ + + + + Qt::Vertical + + + + 20 + 40 + + + + From 6fd3b99f774755d6d4f610f333f379a3743cb5c2 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 19 May 2015 14:17:12 +0200 Subject: [PATCH 035/217] detect sharp edges Conflicts: Polyhedron/demo/Polyhedron/CMakeLists.txt --- Polyhedron/demo/Polyhedron/CMakeLists.txt | 4 + .../Polyhedron_demo_detect_sharp_edges.h | 26 ++++ ...yhedron_demo_detect_sharp_edges_plugin.cpp | 119 ++++++++++++++++++ 3 files changed, 149 insertions(+) create mode 100644 Polyhedron/demo/Polyhedron/Polyhedron_demo_detect_sharp_edges.h create mode 100644 Polyhedron/demo/Polyhedron/Polyhedron_demo_detect_sharp_edges_plugin.cpp diff --git a/Polyhedron/demo/Polyhedron/CMakeLists.txt b/Polyhedron/demo/Polyhedron/CMakeLists.txt index 39216f78828..93b5627ba0a 100644 --- a/Polyhedron/demo/Polyhedron/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/CMakeLists.txt @@ -501,6 +501,10 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND) polyhedron_demo_plugin(shortest_path_plugin Polyhedron_demo_shortest_path_plugin ${shortestPathUI_FILES}) target_link_libraries(shortest_path_plugin scene_polyhedron_item scene_polylines_item scene_polyhedron_selection_item scene_polyhedron_shortest_path_item scene_basic_objects) + polyhedron_demo_plugin(detect_sharp_edges_plugin Polyhedron_demo_detect_sharp_edges_plugin) + target_link_libraries(detect_sharp_edges_plugin scene_polyhedron_item) + + polyhedron_demo_plugin(isotropic_remeshing_plugin Polyhedron_demo_isotropic_remeshing_plugin) target_link_libraries(isotropic_remeshing_plugin scene_polyhedron_item scene_polyhedron_selection_item) diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_detect_sharp_edges.h b/Polyhedron/demo/Polyhedron/Polyhedron_demo_detect_sharp_edges.h new file mode 100644 index 00000000000..21549a86a79 --- /dev/null +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_detect_sharp_edges.h @@ -0,0 +1,26 @@ + +#ifndef POLYHEDRON_DEMO_DETECT_SHARP_EDGES_H +#define POLYHEDRON_DEMO_DETECT_SHARP_EDGES_H + +#include + +namespace CGAL +{ + template + void detect_sharp_edges(Polyhedron* pMesh, const double angle) + { + CGAL::Mesh_3::Detect_features_in_polyhedra detect_features; + + for (typename Polyhedron::Edge_iterator + eit = pMesh->edges_begin(), + end = pMesh->edges_end(); eit != end; ++eit) + { + eit->set_feature_edge(false); + } + + // Detect edges in current polyhedron + detect_features.detect_sharp_edges(*pMesh, angle); + } +}//end namespace CGAL + +#endif //POLYHEDRON_DEMO_DETECT_SHARP_EDGES_H diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_detect_sharp_edges_plugin.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_detect_sharp_edges_plugin.cpp new file mode 100644 index 00000000000..5269f4c9536 --- /dev/null +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_detect_sharp_edges_plugin.cpp @@ -0,0 +1,119 @@ +#include +#include +#include +#include +#include + +#include "Scene_polyhedron_item.h" +#include "Scene_polygon_soup_item.h" +#include "Polyhedron_type.h" + +#include "Polyhedron_demo_plugin_helper.h" +#include "Polyhedron_demo_plugin_interface.h" +#include "Polyhedron_demo_detect_sharp_edges.h" + +class Polyhedron_demo_detect_sharp_edges_plugin : + public QObject, + public Polyhedron_demo_plugin_helper +{ + Q_OBJECT + Q_INTERFACES(Polyhedron_demo_plugin_interface) + +public: + void init(QMainWindow* mainWindow, Scene_interface* scene_interface) { + this->scene = scene_interface; + this->mw = mainWindow; + actionSharEdges = new QAction("Detect sharp features", mw); + actionSharEdges->setObjectName("detectSharpFeaturesAction"); + if(actionSharEdges) { + connect(actionSharEdges, SIGNAL(triggered()), + this, SLOT(detectSharpEdgesWithInputDialog())); + } + } + + bool applicable(QAction*) const { + Q_FOREACH(int index, scene->selectionIndices()) + { + Scene_polyhedron_item* item = + qobject_cast(scene->item(index)); + if (item) return true; + } + return false; + } + + // used by Polyhedron_demo_plugin_helper + QList actions() const { + return QList() << actionSharEdges; + } + +public Q_SLOTS: +void detectSharpEdges(bool input_dialog = false, double angle = 60); + void detectSharpEdgesWithInputDialog(); + +protected: + Kernel::Vector_3 facet_normal(Polyhedron::Facet_handle f); + bool is_sharp(Polyhedron::Halfedge_handle he); + +private: + QAction* actionSharEdges; +}; // end Polyhedron_demo_detect_sharp_edges_plugin + +void Polyhedron_demo_detect_sharp_edges_plugin::detectSharpEdgesWithInputDialog() +{ + detectSharpEdges(true); +} + +void Polyhedron_demo_detect_sharp_edges_plugin::detectSharpEdges(bool input_dialog, + double angle) +{ + typedef std::pair Poly_tuple; + + // Get selected items + QList polyhedrons; + Q_FOREACH(int index, scene->selectionIndices()) + { + Scene_polyhedron_item* item = + qobject_cast(scene->item(index)); + if(!item) + return; + + Polyhedron* pMesh = item->polyhedron(); + if(!pMesh) + return; + + polyhedrons << make_pair(index, pMesh); + } + + if(input_dialog) { + bool ok = true; + angle = QInputDialog::getDouble(NULL, + tr("Sharp edges max angle"), + tr("Angle in degrees between 0 and 180:"), + angle, // value + 0., // min + 180., // max + 2, // decimals + &ok); + if(!ok) return; + } + // Detect edges + QApplication::setOverrideCursor(Qt::WaitCursor); + + Q_FOREACH(Poly_tuple tuple, polyhedrons) + { + Polyhedron* pMesh = tuple.second; + if (!pMesh) continue; + + CGAL::detect_sharp_edges(pMesh, angle); + + // update scene + scene->itemChanged(tuple.first); + } + + // default cursor + QApplication::restoreOverrideCursor(); +} + +Q_EXPORT_PLUGIN2(Polyhedron_demo_detect_sharp_edges_plugin, Polyhedron_demo_detect_sharp_edges_plugin) + +#include "Polyhedron_demo_detect_sharp_edges_plugin.moc" From 00b50b3e3e4078cfcfdf55fddc84db7de96057b9 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 19 May 2015 15:10:52 +0200 Subject: [PATCH 036/217] select sharp edges button and code added Conflicts: Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h --- .../Polyhedron_demo_selection_plugin.cpp | 14 +++ .../Scene_polyhedron_selection_item.h | 30 ++++++ .../demo/Polyhedron/Selection_widget.ui | 100 +++++++++++++++--- 3 files changed, 131 insertions(+), 13 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_selection_plugin.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_selection_plugin.cpp index 31a1554e3ec..0195666dec1 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_demo_selection_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_selection_plugin.cpp @@ -98,6 +98,8 @@ public: connect(ui_widget.Keep_connected_components_button, SIGNAL(clicked()), this, SLOT(on_Keep_connected_components_button_clicked())); connect(ui_widget.Dilate_erode_button, SIGNAL(clicked()), this, SLOT(on_Dilate_erode_button_clicked())); connect(ui_widget.Create_polyhedron_item_button, SIGNAL(clicked()), this, SLOT(on_Create_polyhedron_item_button_clicked())); + connect(ui_widget.Select_sharp_edges_button, SIGNAL(clicked()), this, SLOT(on_Select_sharp_edges_button_clicked())); + QObject* scene = dynamic_cast(scene_interface); if(scene) { connect(scene, SIGNAL(itemAboutToBeDestroyed(Scene_item*)), this, SLOT(item_about_to_be_destroyed(Scene_item*))); @@ -298,6 +300,18 @@ public Q_SLOTS: print_message("Error: polyhedron item is not created!"); } } + + void on_Select_sharp_edges_button_clicked() { + Scene_polyhedron_selection_item* selection_item = get_selected_item(); + if (!selection_item) { + print_message("Error: there is no selected polyhedron selection item!"); + return; + } + + double angle = ui_widget.Sharp_angle_spinbox->value(); + selection_item->select_sharp_edges(angle); + } + void on_Dilate_erode_button_clicked() { Scene_polyhedron_selection_item* selection_item = get_selected_item(); if(!selection_item) { diff --git a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h index 5d281d3b18d..c48c85df38f 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h +++ b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h @@ -13,6 +13,7 @@ #include #include #include +#include "Polyhedron_demo_detect_sharp_edges.h" #include #include @@ -20,6 +21,7 @@ #include #include +#include namespace PMP = CGAL::Polygon_mesh_processing; @@ -705,6 +707,34 @@ public: return out->size_of_vertices() > 0; } + struct Is_sharp_edge_property_map + { + friend bool get(Is_sharp_edge_property_map, + Polyhedron::Halfedge_handle h) + { + return h->is_feature_edge(); + } + friend void put(Is_sharp_edge_property_map, + Polyhedron::Halfedge_handle h, + bool b) + { + h->set_feature_edge(b); + } + }; + + void select_sharp_edges(const double angle) + { + CGAL::detect_sharp_edges(polyhedron(), angle); + + Is_sharp_edge_property_map is_sharp; + BOOST_FOREACH(edge_descriptor e, edges(*polyhedron())) + { + Polyhedron::Halfedge_handle h = halfedge(e, *polyhedron()); + if (get(is_sharp, h)) + selected_edges.insert(e); + } + } + void changed_with_poly_item() { // no need to update indices poly_item->changed(); diff --git a/Polyhedron/demo/Polyhedron/Selection_widget.ui b/Polyhedron/demo/Polyhedron/Selection_widget.ui index d178b56ad88..fce61d9f557 100644 --- a/Polyhedron/demo/Polyhedron/Selection_widget.ui +++ b/Polyhedron/demo/Polyhedron/Selection_widget.ui @@ -180,6 +180,93 @@ + + + + + + + + + 10 + 10 + 291 + 80 + + + + + + + true + + + + + 0 + 0 + 287 + 76 + + + + + + 210 + 30 + 75 + 23 + + + + Select + + + + + + 121 + 30 + 81 + 22 + + + + + 0 + 0 + + + + 180 + + + 60 + + + + + + 5 + 30 + 111 + 20 + + + + Sharp edges angle: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + @@ -277,19 +364,6 @@ - - - - Qt::Vertical - - - - 20 - 40 - - - - From a59eb5fb0ee263eb48488bc61761b12d82ccc5e1 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 19 May 2015 15:22:01 +0200 Subject: [PATCH 037/217] fix the selection widget layout --- .../demo/Polyhedron/Selection_widget.ui | 127 +++++++----------- 1 file changed, 47 insertions(+), 80 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Selection_widget.ui b/Polyhedron/demo/Polyhedron/Selection_widget.ui index fce61d9f557..cd351afef89 100644 --- a/Polyhedron/demo/Polyhedron/Selection_widget.ui +++ b/Polyhedron/demo/Polyhedron/Selection_widget.ui @@ -182,93 +182,60 @@ + + + 316 + 50 + + - - - - 10 - 10 - 291 - 80 - - - - - - - true - - - - - 0 - 0 - 287 - 76 - - - - - - 210 - 30 - 75 - 23 - - - - Select - - - - - - 121 - 30 - 81 - 22 - - - - - 0 - 0 - - - - 180 - - - 60 - - - - - - 5 - 30 - 111 - 20 - - - - Sharp edges angle: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - + + + + + Sharp edges angle: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + 180 + + + 60 + + + + + + + Select + + + + + + + 316 + 50 + + From 9b4145d6ca81abc6469a4b893ababacb4d369334 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 19 May 2015 15:24:22 +0200 Subject: [PATCH 038/217] add itemChanged to update display --- Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h index c48c85df38f..48afb7f499c 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h +++ b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h @@ -733,6 +733,7 @@ public: if (get(is_sharp, h)) selected_edges.insert(e); } + changed_with_poly_item(); } void changed_with_poly_item() { From f958fe7d5dab7a6667af36e9093be53005897c78 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 19 May 2015 17:25:53 +0200 Subject: [PATCH 039/217] fix warning --- .../include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index b099c12d2ff..e7d8c3604cd 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -573,7 +573,7 @@ namespace internal { int valence(const vertex_descriptor& v) const { - return degree(v, mesh_); + return static_cast(degree(v, mesh_)); } int target_valence(const vertex_descriptor& v) const From 0f0beddb20d68eaa9f39bd75c269f862ac95a0f0 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 19 May 2015 17:29:11 +0200 Subject: [PATCH 040/217] WIP : selection of a connected component --- .../Scene_polyhedron_item_k_ring_selection.h | 3 +- .../Scene_polyhedron_selection_item.h | 46 ++++++++++++++++--- .../demo/Polyhedron/Selection_widget.ui | 5 ++ 3 files changed, 46 insertions(+), 8 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Scene_polyhedron_item_k_ring_selection.h b/Polyhedron/demo/Polyhedron/Scene_polyhedron_item_k_ring_selection.h index 7d1d16f16a3..c4205a1877e 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polyhedron_item_k_ring_selection.h +++ b/Polyhedron/demo/Polyhedron/Scene_polyhedron_item_k_ring_selection.h @@ -20,7 +20,8 @@ class SCENE_POLYHEDRON_ITEM_K_RING_SELECTION_EXPORT Scene_polyhedron_item_k_ring { Q_OBJECT public: - struct Active_handle { enum Type{ VERTEX = 0, FACET = 1, EDGE = 2 }; }; + struct Active_handle { + enum Type{ VERTEX = 0, FACET = 1, EDGE = 2 , CONNECTED_COMPONENT = 3}; }; typedef boost::graph_traits::edge_descriptor edge_descriptor; diff --git a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h index 48afb7f499c..6f143634c8d 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h +++ b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h @@ -427,6 +427,7 @@ public: case Active_handle::VERTEX: select_all(); break; case Active_handle::FACET: + case Active_handle::CONNECTED_COMPONENT: select_all(); break; case Active_handle::EDGE: selected_edges.insert(edges(*polyhedron()).first, edges(*polyhedron()).second); @@ -449,6 +450,7 @@ public: case Active_handle::VERTEX: clear(); break; case Active_handle::FACET: + case Active_handle::CONNECTED_COMPONENT: clear(); break; case Active_handle::EDGE: clear(); break; @@ -519,7 +521,7 @@ public: case Active_handle::FACET: dilate_selection(steps); break; - default: + case Active_handle::EDGE: dilate_selection(steps); } } @@ -532,7 +534,7 @@ public: case Active_handle::FACET: erode_selection(-steps); break; - default: + case Active_handle::EDGE: erode_selection(-steps); } } @@ -791,20 +793,50 @@ protected: } } - template - void has_been_selected(const std::set& selection) + template + bool treat_selection(const HandleRange& selection) { - if(!visible()) { return; } + typedef HandleRange::value_type HandleType; Selection_traits tr(this); bool any_change = false; - if(is_insert) { + if (is_insert) { BOOST_FOREACH(HandleType h, selection) any_change |= tr.container().insert(h).second; } else{ BOOST_FOREACH(HandleType h, selection) - any_change |= (tr.container().erase(h)!=0); + any_change |= (tr.container().erase(h) != 0); + } + return any_change; + } + + Facet_handle face(Facet_handle fh) + { return fh; } + Facet_handle face(Vertex_handle) + { return boost::graph_traits::null_face(); } + Facet_handle face(edge_descriptor) + { return boost::graph_traits::null_face(); } + + template + void has_been_selected(const std::set& selection) + { + if(!visible()) { return; } + + bool any_change = false; + + if (get_active_handle_type() == Active_handle::CONNECTED_COMPONENT) + { + std::vector selected_cc; + CGAL::Polygon_mesh_processing::connected_component( + face(*selection.begin()), + *polyhedron(), + std::back_inserter(selected_cc)); + any_change = treat_selection(selected_cc); + } + else + { + any_change = treat_selection(selection); } if(any_change) { Q_EMIT itemChanged(); } } diff --git a/Polyhedron/demo/Polyhedron/Selection_widget.ui b/Polyhedron/demo/Polyhedron/Selection_widget.ui index cd351afef89..b5ea7d36ecc 100644 --- a/Polyhedron/demo/Polyhedron/Selection_widget.ui +++ b/Polyhedron/demo/Polyhedron/Selection_widget.ui @@ -46,6 +46,11 @@ Edge + + + Connected component (facet) + + From 9e3daf9085fc0d5a8f74393f67cc3080112785d6 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Wed, 20 May 2015 11:47:32 +0200 Subject: [PATCH 041/217] selection of one connected component, based on the sharp edges detected/selected --- .../Scene_polyhedron_item_k_ring_selection.h | 5 +++-- .../demo/Polyhedron/Scene_polyhedron_selection_item.h | 10 +++++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Scene_polyhedron_item_k_ring_selection.h b/Polyhedron/demo/Polyhedron/Scene_polyhedron_item_k_ring_selection.h index c4205a1877e..f0873ca3d18 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polyhedron_item_k_ring_selection.h +++ b/Polyhedron/demo/Polyhedron/Scene_polyhedron_item_k_ring_selection.h @@ -72,8 +72,9 @@ public Q_SLOTS: } void facet_has_been_selected(void* void_ptr) { - if(active_handle_type != Active_handle::FACET) { return; } - process_selection( static_cast(void_ptr)->halfedge()->facet() ); + if (active_handle_type == Active_handle::FACET + || active_handle_type == Active_handle::CONNECTED_COMPONENT) + process_selection(static_cast(void_ptr)->halfedge()->facet()); } void edge_has_been_selected(void* void_ptr) { diff --git a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h index 6f143634c8d..3943b3b7d25 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h +++ b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h @@ -716,6 +716,11 @@ public: { return h->is_feature_edge(); } + friend bool get(Is_sharp_edge_property_map, + edge_descriptor e) + { + return e.halfedge()->is_feature_edge(); + } friend void put(Is_sharp_edge_property_map, Polyhedron::Halfedge_handle h, bool b) @@ -827,11 +832,14 @@ protected: if (get_active_handle_type() == Active_handle::CONNECTED_COMPONENT) { + Is_sharp_edge_property_map is_sharp; std::vector selected_cc; CGAL::Polygon_mesh_processing::connected_component( face(*selection.begin()), *polyhedron(), - std::back_inserter(selected_cc)); + std::back_inserter(selected_cc), + CGAL::Polygon_mesh_processing::parameters::edge_is_constrained_map(is_sharp)); + any_change = treat_selection(selected_cc); } else From e6a7b5a0a33c9891a6f1d48aeac4ca18e9ec4c24 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Wed, 20 May 2015 15:40:45 +0200 Subject: [PATCH 042/217] use get and set to access vertex point map, instead of operator[] --- .../internal/remesh_impl.h | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index e7d8c3604cd..f8b4ceea2cf 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -83,7 +83,8 @@ namespace internal { vertex_descriptor v1 = target(h, mesh_); vertex_descriptor v2 = target(next(h, mesh_), mesh_); vertex_descriptor v3 = target(next(next(h, mesh_), mesh_), mesh_); - input_triangles_.push_back(Triangle_3(vpmap[v1], vpmap[v2], vpmap[v3])); + input_triangles_.push_back( + Triangle_3(get(vpmap, v1), get(vpmap, v2), get(vpmap, v3))); } tree_ptr_ = new AABB_tree(input_triangles_.begin(), input_triangles_.end()); @@ -139,7 +140,7 @@ namespace internal { //move refinement point vertex_descriptor vnew = target(hnew, mesh_); - vpmap_[vnew] = refinement_point; + put(vpmap_, vnew, refinement_point); //check sub-edges double sqlen_new = 0.25 * sqlen; @@ -332,9 +333,9 @@ namespace internal { halfedge_and_opp_removed(prev(he, mesh_)); //perform collapse - Point target_point = vpmap_[vb]; + Point target_point = get(vpmap_, vb); vertex_descriptor vkept = CGAL::Euler::collapse_edge(edge(he, mesh_), mesh_); - vpmap_[vkept] = target_point; + put(vpmap_, vkept, target_point); ++nb_collapses; // merge halfedge_status to keep the more important on both sides @@ -477,11 +478,11 @@ namespace internal { unsigned int star_size = 0; BOOST_FOREACH(halfedge_descriptor h, halfedges_around_target(v, mesh_)) { - move = move + Vector_3(vpmap_[v], vpmap_[source(h, mesh_)]); + move = move + Vector_3(get(vpmap_, v), get(vpmap_, source(h, mesh_))); ++star_size; } move = (1. / (double)star_size) * move; - barycenters[v] = vpmap_[v] + move; + barycenters[v] = get(vpmap_, v) + move; } // compute moves @@ -493,14 +494,14 @@ namespace internal { continue; Vector_3 nv = boost::get(propmap_normals, v); Point qv = barycenters[v]; - new_locations[v] = qv + (nv * Vector_3(qv, vpmap_[v])) * nv; + new_locations[v] = qv + (nv * Vector_3(qv, get(vpmap_, v))) * nv; } // perform moves typedef typename std::map::value_type VP_pair; BOOST_FOREACH(const VP_pair& vp, new_locations) { - vpmap_[vp.first] = new_locations[vp.first]; + put(vpmap_, vp.first, new_locations[vp.first]); } CGAL_assertion(is_valid(mesh_)); @@ -525,7 +526,7 @@ namespace internal { { if (!is_on_patch(v)) continue; - vpmap_[v] = tree_ptr_->closest_point(vpmap_[v]); + put(vpmap_, v, tree_ptr_->closest_point(get(vpmap_, v))); } CGAL_assertion(is_valid(mesh_)); @@ -542,7 +543,7 @@ namespace internal { double sqlength(const vertex_descriptor& v1, const vertex_descriptor& v2) const { - return CGAL::squared_distance(vpmap_[v1], vpmap_[v2]); + return CGAL::squared_distance(get(vpmap_, v1), get(vpmap_, v2)); } double sqlength(const halfedge_descriptor& h) const @@ -559,8 +560,8 @@ namespace internal { Point midpoint(const halfedge_descriptor& he) const { - Point p1 = vpmap_[target(he, mesh_)]; - Point p2 = vpmap_[source(he, mesh_)]; + Point p1 = get(vpmap_, target(he, mesh_)); + Point p2 = get(vpmap_, source(he, mesh_)); return CGAL::midpoint(p1, p2); } @@ -589,8 +590,8 @@ namespace internal { if (!is_on_patch(he)) return false; - Point p1 = vpmap_[target(he, mesh_)]; - Point p2 = vpmap_[source(he, mesh_)]; + Point p1 = get(vpmap_, target(he, mesh_)); + Point p2 = get(vpmap_, source(he, mesh_)); Vector_3 normal(p1, p2); //construct planes passing through p1 and p2, @@ -602,8 +603,8 @@ namespace internal { plane1.orthogonal_vector() * plane2.orthogonal_vector() > 0.); //get third points of triangles shared by e - Point p3 = vpmap_[target(next(he, mesh_), mesh_)]; - Point p4 = vpmap_[target(next(opposite(he, mesh_), mesh_), mesh_)]; + Point p3 = get(vpmap_, target(next(he, mesh_), mesh_)); + Point p4 = get(vpmap_, target(next(opposite(he, mesh_), mesh_), mesh_)); //check whether p3 and p4 are between plane1 and plane2 return (plane1.oriented_side(p3) != plane2.oriented_side(p3)) From c41bc2250d9d29ed04584d5b78eee95643bac91a Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Wed, 20 May 2015 16:52:28 +0200 Subject: [PATCH 043/217] start documentation for get_border and incremental_triangle_based_remeshing --- .../CGAL/Polygon_mesh_processing/get_border.h | 16 +++++++--- .../CGAL/Polygon_mesh_processing/remesh.h | 30 +++++++++++++------ 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/get_border.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/get_border.h index 32fc01ca49c..f9887e61f13 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/get_border.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/get_border.h @@ -29,11 +29,19 @@ namespace CGAL{ namespace Polygon_mesh_processing { - /** + /*! + \ingroup PkgPolygonMeshProcessing * collects the border of a face range - * @param faces the range of face descriptors around which the - * border is computed - * @param out the output iterator that collects edges that form the border + + * @tparam PolygonMesh model of `HalfedgeGraph` + * @tparam FaceRange + * @tparam HalfedgeOutputIterator model of `OutputIterator` + holding `boost::graph_traits::%halfedge_descriptor` + for patch border + + * @param faces the range of face descriptors describing the surface patch + * around which the border is computed + * @param out the output iterator that collects halfedges that form the border * of `faces`, seen from inside the surface patch * * @todo code : what shall we do for more than one connected components diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h index b242d3f4082..122b0126388 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h @@ -32,22 +32,34 @@ namespace CGAL { namespace Polygon_mesh_processing { -/** +/*! * \ingroup PkgPolygonMeshProcessing +* @brief remeshes a triangulated region of a polygon mesh. * implements section 6.5.3 "Incremental remeshing" from the PMP book +* * @tparam PolygonMesh model of `MutableFaceGraph` that * has an internal property map for `CGAL::vertex_point_t` -* @tparam FaceRange range of face descriptors, model of `SinglePassRange` +* @tparam FaceRange range of `boost::graph_traits::%face_descriptor`, + model of `Range`. Its iterator type is `InputIterator`. +* @tparam NamedParameters a sequence of \ref namedparameters * -* @param pmesh polygon mesh with patches to be refined +* @param pmesh polygon mesh with patches to be remeshed * @param faces the range of faces defining one patch to remesh +* @param target_edge_length the edge length that is targetted in the remeshed patch +* @param np optional sequence of \ref namedparameters among the ones listed below + +* \cgalNamedParamsBegin +* \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} TODO... +* \cgalParamEnd +* \cgalParamBegin{geom_traits} a geometric traits class instance + \cgalParamEnd +* \cgalNamedParamsEnd * -* named parameters : -* vertex_point_map -* nb_iterations -* geom_traits, that needs Point_3, Vector_3, Plane_3 -* -*@todo we suppose `faces` describe only one patch. Handle several patches +*@todo we suppose `faces` describe only one patch. Handle several patches. +*@todo document `number_of_iterations` */ template Date: Wed, 20 May 2015 16:55:23 +0200 Subject: [PATCH 044/217] doc --- .../Polygon_mesh_processing/PackageDescription.txt | 2 ++ .../Polygon_mesh_processing.txt | 12 +++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt index d2270b38cdc..2bf590b91a4 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt @@ -48,6 +48,7 @@ and provides a list of the parameters that are used in this package. - `CGAL::Polygon_mesh_processing::fair()` - `CGAL::Polygon_mesh_processing::refine()` - `CGAL::Polygon_mesh_processing::triangulate_faces()` +- `CGAL::Polygon_mesh_processing::incremental_triangle_based_remeshing()` ## Hole Filling Functions ## - `CGAL::Polygon_mesh_processing::triangulate_hole()` @@ -86,6 +87,7 @@ and provides a list of the parameters that are used in this package. ## Miscellaneous ## - `CGAL::Polygon_mesh_slicer` +- `CGAL::Polygon_mesh_processing::get_border()` \todo make template parameter names uniform in other packages using BGL. Here we chose PolygonMesh as template parameter. It can be made short to PM. And TriangleMesh (or TM) specifies when the parameter should be a triangle mesh. 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 eb43164526b..a2fe31a6b76 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 @@ -70,9 +70,11 @@ The visual results of aforementioned steps are depicted by \cgalFigureRef{Mech_s \subsection MeshingAPI API -Refinement and fairing functions can be applied to an arbitrary region on a polygon mesh, using : -- `CGAL::Polygon_mesh_processing::refine()` : given a range of facets on a mesh, refines the region. -- `CGAL::Polygon_mesh_processing::fair()` : given a range of vertices on a mesh, fairs the region. +\subsubsection Meshing + +Refinement and fairing functions can be applied to an arbitrary region on a mesh, using : +- `CGAL::Polygon_mesh_processing::refine()` : given a set of facets on a mesh, refines the region. +- `CGAL::Polygon_mesh_processing::fair()` : given a set of vertices on a mesh, fairs the region. Fairing needs a sparse linear solver and we recommend the use of \ref thirdpartyEigen 3.2 or later. Note that fairing might fail if fixed vertices, which are used as boundary conditions, do @@ -91,6 +93,10 @@ This choice is made because the constrained Delaunay triangulation is the triangulation that, given the edges of the face to be triangulated, maximizes the minimum angle of all the angles of the triangles in the triangulation. +\subsubsection Remeshing +- `CGAL::Polygon_mesh_processing::incremental_triangle_based_remeshing()` +\todo user manual remeshing + \subsection MeshingExamples Meshing Examples \subsubsection MeshingExample_1 Refine and Fair a Region on a Polygon Mesh From caad50a628d6614f3b21904af695bec133bd43ad Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Wed, 20 May 2015 17:15:36 +0200 Subject: [PATCH 045/217] documentation --- .../CGAL/Polygon_mesh_processing/get_border.h | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/get_border.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/get_border.h index f9887e61f13..f05d5d185ad 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/get_border.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/get_border.h @@ -31,20 +31,26 @@ namespace Polygon_mesh_processing { /*! \ingroup PkgPolygonMeshProcessing - * collects the border of a face range + * collects the border of a surface patch + * defined as a face range. The border is "seen from inside" the patch, + * i.e. the collected halfedges are + * the ones that belong to the input faces. * @tparam PolygonMesh model of `HalfedgeGraph` - * @tparam FaceRange + * @tparam FaceRange range of + `boost::graph_traits::%face_descriptor`, model of `Range`. + Its iterator type is `InputIterator`. * @tparam HalfedgeOutputIterator model of `OutputIterator` holding `boost::graph_traits::%halfedge_descriptor` for patch border - * @param faces the range of face descriptors describing the surface patch - * around which the border is computed + * @param faces the range of faces defining the patch + * around which the border is collected * @param out the output iterator that collects halfedges that form the border * of `faces`, seen from inside the surface patch * * @todo code : what shall we do for more than one connected components + * @todo add get_border to the user manual */ template Date: Thu, 21 May 2015 11:03:21 +0200 Subject: [PATCH 046/217] add missing typename --- Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h index 3943b3b7d25..14953821250 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h +++ b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h @@ -801,7 +801,7 @@ protected: template bool treat_selection(const HandleRange& selection) { - typedef HandleRange::value_type HandleType; + typedef typename HandleRange::value_type HandleType; Selection_traits tr(this); bool any_change = false; From 374549bf601d37639157dedd19ada314968d2a05 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Thu, 21 May 2015 11:40:45 +0200 Subject: [PATCH 047/217] fix warning --- Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h index 14953821250..34eae94354e 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h +++ b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h @@ -519,6 +519,7 @@ public: dilate_selection(steps); break; case Active_handle::FACET: + case Active_handle::CONNECTED_COMPONENT: dilate_selection(steps); break; case Active_handle::EDGE: @@ -532,6 +533,7 @@ public: erode_selection(-steps); break; case Active_handle::FACET: + case Active_handle::CONNECTED_COMPONENT: erode_selection(-steps); break; case Active_handle::EDGE: From acf142192d0d61ea0665ae6ac9b74277ad1a077e Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Thu, 21 May 2015 12:15:28 +0200 Subject: [PATCH 048/217] add possibility to hide sharp features --- ...yhedron_demo_detect_sharp_edges_plugin.cpp | 2 +- .../demo/Polyhedron/Scene_polyhedron_item.cpp | 22 ++++++++++++++++++- .../demo/Polyhedron/Scene_polyhedron_item.h | 2 ++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_detect_sharp_edges_plugin.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_detect_sharp_edges_plugin.cpp index 5269f4c9536..386799bfb7a 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_demo_detect_sharp_edges_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_detect_sharp_edges_plugin.cpp @@ -80,7 +80,7 @@ void Polyhedron_demo_detect_sharp_edges_plugin::detectSharpEdges(bool input_dial Polyhedron* pMesh = item->polyhedron(); if(!pMesh) return; - + item->show_feature_edges(true); polyhedrons << make_pair(index, pMesh); } diff --git a/Polyhedron/demo/Polyhedron/Scene_polyhedron_item.cpp b/Polyhedron/demo/Polyhedron/Scene_polyhedron_item.cpp index 5eb882ca054..279f186b6c8 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polyhedron_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_polyhedron_item.cpp @@ -64,6 +64,7 @@ Scene_polyhedron_item::Scene_polyhedron_item() : Scene_item_with_display_list(), poly(new Polyhedron), show_only_feature_edges_m(false), + show_feature_edges_m(false), facet_picking_m(false), erase_next_picked_facet_m(false), plugin_has_set_color_vector_m(false) @@ -75,6 +76,7 @@ Scene_polyhedron_item::Scene_polyhedron_item(Polyhedron* const p) : Scene_item_with_display_list(), poly(p), show_only_feature_edges_m(false), + show_feature_edges_m(false), facet_picking_m(false), erase_next_picked_facet_m(false), plugin_has_set_color_vector_m(false) @@ -86,6 +88,7 @@ Scene_polyhedron_item::Scene_polyhedron_item(const Polyhedron& p) : Scene_item_with_display_list(), poly(new Polyhedron(p)), show_only_feature_edges_m(false), + show_feature_edges_m(false), facet_picking_m(false), erase_next_picked_facet_m(false), plugin_has_set_color_vector_m(false) @@ -235,6 +238,14 @@ QMenu* Scene_polyhedron_item::contextMenu() connect(actionShowOnlyFeatureEdges, SIGNAL(toggled(bool)), this, SLOT(show_only_feature_edges(bool))); + QAction* actionShowFeatureEdges = + menu->addAction(tr("Show feature edges")); + actionShowFeatureEdges->setCheckable(true); + actionShowFeatureEdges->setChecked(show_feature_edges_m); + actionShowFeatureEdges->setObjectName("actionShowFeatureEdges"); + connect(actionShowFeatureEdges, SIGNAL(toggled(bool)), + this, SLOT(show_feature_edges(bool))); + QAction* actionPickFacets = menu->addAction(tr("Facets picking")); actionPickFacets->setCheckable(true); @@ -264,6 +275,12 @@ void Scene_polyhedron_item::show_only_feature_edges(bool b) Q_EMIT itemChanged(); } +void Scene_polyhedron_item::show_feature_edges(bool b) +{ + show_feature_edges_m = b; + Q_EMIT itemChanged(); +} + void Scene_polyhedron_item::enable_facets_picking(bool b) { facet_picking_m = b; @@ -299,7 +316,9 @@ void Scene_polyhedron_item::direct_draw_edges() const { ::glVertex3d(b.x(),b.y(),b.z()); } } - ::glColor3d(1.0, 0.0, 0.0); + + if (show_feature_edges_m) + ::glColor3d(1.0, 0.0, 0.0); for(he = poly->edges_begin(); he != poly->edges_end(); he++) @@ -310,6 +329,7 @@ void Scene_polyhedron_item::direct_draw_edges() const { ::glVertex3d(a.x(),a.y(),a.z()); ::glVertex3d(b.x(),b.y(),b.z()); } + ::glEnd(); } diff --git a/Polyhedron/demo/Polyhedron/Scene_polyhedron_item.h b/Polyhedron/demo/Polyhedron/Scene_polyhedron_item.h index 9ed0d56fde6..7bbb26b5535 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polyhedron_item.h +++ b/Polyhedron/demo/Polyhedron/Scene_polyhedron_item.h @@ -56,6 +56,7 @@ public: public Q_SLOTS: virtual void changed(); void show_only_feature_edges(bool); + void show_feature_edges(bool); void enable_facets_picking(bool); void set_erase_next_picked_facet(bool); @@ -91,6 +92,7 @@ private: Color_vector colors_; bool show_only_feature_edges_m; + bool show_feature_edges_m; bool facet_picking_m; bool erase_next_picked_facet_m; //the following variable is used to indicate if the color vector must not be automatically updated. From ad624dbea184f6d6fd8d1cae9e261ebecd245d31 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Thu, 21 May 2015 12:58:45 +0200 Subject: [PATCH 049/217] clear selection after remeshing everything has changed, but some faces have been recycled to the selection has become completely wrong --- .../Polyhedron_demo_isotropic_remeshing_plugin.cpp | 2 ++ .../demo/Polyhedron/Scene_polyhedron_selection_item.h | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp index c7b58e7b4c2..ec1a99e1c24 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp @@ -114,6 +114,8 @@ public Q_SLOTS: , target_length , CGAL::Polygon_mesh_processing::parameters::number_of_iterations(nb_iter)); + selection_item->poly_item_changed(); + selection_item->clear_all(); selection_item->changed_with_poly_item(); } else if (poly_item){ diff --git a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h index 34eae94354e..560d693694c 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h +++ b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h @@ -465,6 +465,12 @@ public: Q_EMIT itemChanged(); } + void clear_all(){ + clear(); + clear(); + clear(); + } + boost::optional get_minimum_isolated_component() { switch(get_active_handle_type()) { case Active_handle::VERTEX: @@ -848,7 +854,7 @@ protected: { any_change = treat_selection(selection); } - if(any_change) { Q_EMIT itemChanged(); } + if(any_change) { Q_EMIT changed_with_poly_item(); } } public: From c554466b8072f265cc382142f16bac53399caeea Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Thu, 21 May 2015 14:32:40 +0200 Subject: [PATCH 050/217] fix default value --- .../CGAL/Polygon_mesh_processing/connected_components.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/connected_components.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/connected_components.h index 26f21a1f4a1..2a4555c1331 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/connected_components.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/connected_components.h @@ -436,7 +436,8 @@ connected_component(typename boost::graph_traits::face_descriptor s internal::No_constraint//default > ::type EdgeConstraintMap; EdgeConstraintMap ecmap - = choose_param(get_param(np, edge_is_constrained), EdgeConstraintMap()); + = choose_param(get_param(np, edge_is_constrained), + internal::No_constraint()); typedef typename boost::graph_traits::face_descriptor face_descriptor; typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; From b6a221a0e952d846a9d4ca665b68d08c58c0a7ea Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Thu, 21 May 2015 14:35:07 +0200 Subject: [PATCH 051/217] use selected edges as boundary for remeshing --- .../Scene_polyhedron_selection_item.h | 35 ++++++------------- 1 file changed, 11 insertions(+), 24 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h index 560d693694c..974fd1360e7 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h +++ b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h @@ -717,35 +717,14 @@ public: return out->size_of_vertices() > 0; } - struct Is_sharp_edge_property_map - { - friend bool get(Is_sharp_edge_property_map, - Polyhedron::Halfedge_handle h) - { - return h->is_feature_edge(); - } - friend bool get(Is_sharp_edge_property_map, - edge_descriptor e) - { - return e.halfedge()->is_feature_edge(); - } - friend void put(Is_sharp_edge_property_map, - Polyhedron::Halfedge_handle h, - bool b) - { - h->set_feature_edge(b); - } - }; - void select_sharp_edges(const double angle) { CGAL::detect_sharp_edges(polyhedron(), angle); - Is_sharp_edge_property_map is_sharp; BOOST_FOREACH(edge_descriptor e, edges(*polyhedron())) { Polyhedron::Halfedge_handle h = halfedge(e, *polyhedron()); - if (get(is_sharp, h)) + if (h->is_feature_edge()) selected_edges.insert(e); } changed_with_poly_item(); @@ -840,13 +819,21 @@ protected: if (get_active_handle_type() == Active_handle::CONNECTED_COMPONENT) { - Is_sharp_edge_property_map is_sharp; + Selection_traits tr(this); + tr.update_indices(); + + std::vector mark(tr.size(), false); + BOOST_FOREACH(edge_descriptor e, selected_edges) + mark[tr.id(e)] = true; + std::vector selected_cc; CGAL::Polygon_mesh_processing::connected_component( face(*selection.begin()), *polyhedron(), std::back_inserter(selected_cc), - CGAL::Polygon_mesh_processing::parameters::edge_is_constrained_map(is_sharp)); + CGAL::Polygon_mesh_processing::parameters::edge_is_constrained_map( + Is_selected_property_map(mark))); any_change = treat_selection(selected_cc); } From 139949d739a71c2f9f3ffd3b88c5f393e6faed39 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Thu, 21 May 2015 14:39:15 +0200 Subject: [PATCH 052/217] split detect_sharp_edges in two functions --- .../Polyhedron_demo_detect_sharp_edges.h | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_detect_sharp_edges.h b/Polyhedron/demo/Polyhedron/Polyhedron_demo_detect_sharp_edges.h index 21549a86a79..ed07702d383 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_demo_detect_sharp_edges.h +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_detect_sharp_edges.h @@ -7,20 +7,26 @@ namespace CGAL { template - void detect_sharp_edges(Polyhedron* pMesh, const double angle) + void reset_sharp_edges(Polyhedron* pMesh) { - CGAL::Mesh_3::Detect_features_in_polyhedra detect_features; - for (typename Polyhedron::Edge_iterator - eit = pMesh->edges_begin(), - end = pMesh->edges_end(); eit != end; ++eit) + eit = pMesh->edges_begin(), + end = pMesh->edges_end(); eit != end; ++eit) { eit->set_feature_edge(false); } + } + + template + void detect_sharp_edges(Polyhedron* pMesh, const double angle) + { + reset_sharp_edges(pMesh); // Detect edges in current polyhedron + CGAL::Mesh_3::Detect_features_in_polyhedra detect_features; detect_features.detect_sharp_edges(*pMesh, angle); } + }//end namespace CGAL #endif //POLYHEDRON_DEMO_DETECT_SHARP_EDGES_H From f7204a0a99d5dbb950bb80770ca88ac23c364108 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 26 May 2015 15:31:42 +0200 Subject: [PATCH 053/217] add edge_is_constrained_map as a parameter for remeshing this property map "tags" the edges that should be kept in the remeshed mesh. They can be splitted or collapsed, but their vertices can't move with the Laplacian, and they can't be flipped. in the Polyhedron demo, this feature is integrated in order to remesh two adjacent surface patches and keep the (possibly sharp) polyline that is delimitating them --- .../internal/remesh_impl.h | 71 +++++++++++++++---- .../CGAL/Polygon_mesh_processing/remesh.h | 22 ++++-- ...hedron_demo_isotropic_remeshing_plugin.cpp | 11 ++- .../Scene_polyhedron_selection_item.h | 2 +- 4 files changed, 83 insertions(+), 23 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index f8b4ceea2cf..7ebcd40e954 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -38,10 +38,40 @@ namespace internal { MESH_BORDER //h belongs to the mesh, face(hopp, pmesh) == null_face() }; + // A property map + template + struct Border_constraint_pmap + { + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename boost::graph_traits::edge_descriptor edge_descriptor; + + std::map border_edges; + const PM& pmesh_; + public: + Border_constraint_pmap(const PM& pmesh, const FaceRange& faces) + : pmesh_(pmesh) + { + std::vector border; + PMP::get_border(pmesh_, faces, std::back_inserter(border)); + + BOOST_FOREACH(edge_descriptor e, edges(pmesh_)) + border_edges.insert(std::make_pair(e, false)); + + BOOST_FOREACH(halfedge_descriptor h, border) + border_edges[edge(h, pmesh_)] = true; + } + friend bool get(Border_constraint_pmap map, + edge_descriptor e) + { + return map.border_edges[e]; + } + }; + template class Incremental_remesher { @@ -65,9 +95,11 @@ namespace internal { public: Incremental_remesher(PolygonMesh& pmesh , const FaceRange& face_range - , VertexPointMap& vpmap) + , VertexPointMap& vpmap + , const EdgeIsConstrainedMap& ecmap) : mesh_(pmesh) , vpmap_(vpmap) + , ecmap_(ecmap) , own_tree_(true) , input_triangles_() , halfedge_status_map_() @@ -163,8 +195,10 @@ namespace internal { next(next(hnew, mesh_), mesh_), mesh_); Halfedge_status snew = (is_on_patch(hnew) - || (is_on_patch_border(hnew) && is_on_mesh(hnew_opp)) - || (is_on_patch_border(hnew) && is_on_border(hnew_opp))) + || (is_on_patch_border(hnew) + && (is_on_mesh(hnew_opp) + || is_on_border(hnew_opp) + || is_on_patch_border(hnew_opp)))) ? PATCH : MESH; halfedge_added(hnew2, snew); @@ -185,8 +219,10 @@ namespace internal { next(hnew_opp, mesh_), mesh_); Halfedge_status snew = (is_on_patch(hnew_opp) - || (is_on_patch_border(hnew_opp) && is_on_mesh(hnew)) - || (is_on_patch_border(hnew_opp) && is_on_border(hnew))) + || (is_on_patch_border(hnew_opp) + && (is_on_mesh(hnew) + || is_on_border(hnew) + || is_on_patch_border(hnew)))) ? PATCH : MESH; halfedge_added(hnew2, snew); @@ -655,16 +691,18 @@ namespace internal { //override the border of PATCH //tag PATCH_BORDER,//h belongs to the patch, hopp doesn't - std::vector border_halfedges; - PMP::get_border(mesh_, face_range, std::back_inserter(border_halfedges)); - BOOST_FOREACH(halfedge_descriptor h, border_halfedges) + BOOST_FOREACH(edge_descriptor e, edges(mesh_)) { - typedef typename std::map::iterator IT; - CGAL_assertion_code(IT it = halfedge_status_map_.find(h)); - CGAL_assertion(it != halfedge_status_map_.end()); - CGAL_assertion(it->second == PATCH); - - halfedge_status_map_[h] = PATCH_BORDER; + if (get(ecmap_, e)) + { + //deal with h and hopp for borders that are sharp edges to be preserved + halfedge_descriptor h = halfedge(e, mesh_); + if (halfedge_status_map_[h] == PATCH) + halfedge_status_map_[h] = PATCH_BORDER; + halfedge_descriptor hopp = opposite(halfedge(e, mesh_), mesh_); + if (halfedge_status_map_[hopp] == PATCH) + halfedge_status_map_[hopp] = PATCH_BORDER; + } } #ifdef CGAL_PMP_REMESHING_DEBUG @@ -727,7 +765,9 @@ namespace internal { if (res) { CGAL_assertion_code(Halfedge_status hs = status(opposite(h, mesh_))); - CGAL_assertion(hs == MESH_BORDER || hs == MESH); + CGAL_assertion(hs == MESH_BORDER + || hs == MESH + || hs == PATCH_BORDER);//when 2 incident patches are remeshed } return res; } @@ -855,6 +895,7 @@ namespace internal { private: PolygonMesh& mesh_; VertexPointMap& vpmap_; + EdgeIsConstrainedMap ecmap_; const AABB_tree* tree_ptr_; bool own_tree_; Triangle_list input_triangles_; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h index 122b0126388..77667421dbe 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h @@ -54,8 +54,10 @@ namespace Polygon_mesh_processing { * \cgalParamEnd * \cgalParamBegin{number_of_iterations} TODO... * \cgalParamEnd -* \cgalParamBegin{geom_traits} a geometric traits class instance - \cgalParamEnd +* \cgalParamBegin{geom_traits} a geometric traits class instance +* \cgalParamEnd +* \cgalParamBegin{edge_is_constrained_map} +* \cgalParamEnd * \cgalNamedParamsEnd * *@todo we suppose `faces` describe only one patch. Handle several patches. @@ -74,14 +76,24 @@ void incremental_triangle_based_remeshing(PolygonMesh& pmesh using boost::get_param; using boost::choose_param; - typedef typename GetGeomTraits::type GeomTraits; + typedef typename GetGeomTraits::type GT; typedef typename GetVertexPointMap::type VPMap; VPMap vpmap = choose_pmap(get_param(np, boost::vertex_point), pmesh, boost::vertex_point); - typename internal::Incremental_remesher - remesher(pmesh, faces, vpmap); + + typedef typename boost::lookup_named_param_def < + CGAL::edge_is_constrained_t, + NamedParameters, + internal::Border_constraint_pmap//default + > ::type ECMap; + ECMap ecmap + = choose_param(get_param(np, edge_is_constrained), + internal::Border_constraint_pmap(pmesh, faces)); + + typename internal::Incremental_remesher + remesher(pmesh, faces, vpmap, ecmap); unsigned int nb_iterations = choose_param(get_param(np, number_of_iterations), 1); diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp index ec1a99e1c24..d1e0a176caf 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp @@ -107,12 +107,19 @@ public Q_SLOTS: QTime time; time.start(); - if (selection_item) { + if (selection_item) + { + std::vector selected( + selection_item->polyhedron()->size_of_halfedges()/2, + false); + CGAL::Polygon_mesh_processing::incremental_triangle_based_remeshing( *selection_item->polyhedron() , selection_item->selected_facets , target_length - , CGAL::Polygon_mesh_processing::parameters::number_of_iterations(nb_iter)); + , CGAL::Polygon_mesh_processing::parameters::number_of_iterations(nb_iter) + .edge_is_constrained_map( + selection_item->selected_edges_pmap(selected))); selection_item->poly_item_changed(); selection_item->clear_all(); diff --git a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h index 974fd1360e7..130a5ed232c 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h +++ b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h @@ -849,7 +849,7 @@ public: selected_edges_pmap(std::vector& mark) { Selection_traits tr(this); + Scene_polyhedron_selection_item> tr(this); tr.update_indices(); for (unsigned int i = 0; i < mark.size(); ++i) From c460008f230182b02ce72b72ff2bf936be0e4bf4 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 26 May 2015 15:50:04 +0200 Subject: [PATCH 054/217] make test simpler (it is equivalent) --- .../Polygon_mesh_processing/internal/remesh_impl.h | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 7ebcd40e954..def188765d3 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -195,10 +195,7 @@ namespace internal { next(next(hnew, mesh_), mesh_), mesh_); Halfedge_status snew = (is_on_patch(hnew) - || (is_on_patch_border(hnew) - && (is_on_mesh(hnew_opp) - || is_on_border(hnew_opp) - || is_on_patch_border(hnew_opp)))) + || (is_on_patch_border(hnew) && !is_on_patch(hnew_opp))) ? PATCH : MESH; halfedge_added(hnew2, snew); @@ -219,10 +216,7 @@ namespace internal { next(hnew_opp, mesh_), mesh_); Halfedge_status snew = (is_on_patch(hnew_opp) - || (is_on_patch_border(hnew_opp) - && (is_on_mesh(hnew) - || is_on_border(hnew) - || is_on_patch_border(hnew)))) + || (is_on_patch_border(hnew_opp) && !is_on_patch(hnew))) ? PATCH : MESH; halfedge_added(hnew2, snew); From ebeb1fdcaa27b5e5eb6fdca0f6f0c1c6335d0cee Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 26 May 2015 16:38:19 +0200 Subject: [PATCH 055/217] edge_is_constrained_map does not need to be kept as a member it is used only in the initialization, to fill the halfedge_status_map --- .../internal/remesh_impl.h | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index def188765d3..fd1b37f9161 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -99,7 +99,6 @@ namespace internal { , const EdgeIsConstrainedMap& ecmap) : mesh_(pmesh) , vpmap_(vpmap) - , ecmap_(ecmap) , own_tree_(true) , input_triangles_() , halfedge_status_map_() @@ -120,7 +119,7 @@ namespace internal { } tree_ptr_ = new AABB_tree(input_triangles_.begin(), input_triangles_.end()); - tag_halfedges_status(face_range); + tag_halfedges_status(face_range, ecmap); } ~Incremental_remesher() @@ -184,11 +183,12 @@ namespace internal { } //after splitting - halfedge_added(hnew, status(he)); - halfedge_added(opposite(hnew, mesh_), status(opposite(he, mesh_))); + halfedge_descriptor hnew_opp = opposite(hnew, mesh_); + halfedge_added(hnew, status(he)); + halfedge_added(hnew_opp, status(opposite(he, mesh_))); //insert new edges to keep triangular faces, and update long_edges - halfedge_descriptor hnew_opp = opposite(hnew, mesh_); + if (!is_on_border(hnew)) { halfedge_descriptor hnew2 = CGAL::Euler::split_face(hnew, @@ -198,7 +198,7 @@ namespace internal { || (is_on_patch_border(hnew) && !is_on_patch(hnew_opp))) ? PATCH : MESH; - halfedge_added(hnew2, snew); + halfedge_added(hnew2, snew); halfedge_added(opposite(hnew2, mesh_), snew); if (snew == PATCH) @@ -219,7 +219,7 @@ namespace internal { || (is_on_patch_border(hnew_opp) && !is_on_patch(hnew))) ? PATCH : MESH; - halfedge_added(hnew2, snew); + halfedge_added(hnew2, snew); halfedge_added(opposite(hnew2, mesh_), snew); if (snew == PATCH) @@ -660,7 +660,8 @@ namespace internal { || (is_on_border(opposite(he, mesh_)) && is_on_patch_border(he)); } - void tag_halfedges_status(const FaceRange& face_range) + void tag_halfedges_status(const FaceRange& face_range + , const EdgeIsConstrainedMap& ecmap) { //tag MESH, //h and hopp belong to the mesh, not the patch //tag MESH_BORDER //h belongs to the mesh, face(hopp, pmesh) == null_face() @@ -687,7 +688,7 @@ namespace internal { //tag PATCH_BORDER,//h belongs to the patch, hopp doesn't BOOST_FOREACH(edge_descriptor e, edges(mesh_)) { - if (get(ecmap_, e)) + if (get(ecmap, e)) { //deal with h and hopp for borders that are sharp edges to be preserved halfedge_descriptor h = halfedge(e, mesh_); @@ -889,7 +890,6 @@ namespace internal { private: PolygonMesh& mesh_; VertexPointMap& vpmap_; - EdgeIsConstrainedMap ecmap_; const AABB_tree* tree_ptr_; bool own_tree_; Triangle_list input_triangles_; From 00cc96f96833d5dfcec7003ce76183a3155e793b Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 29 May 2015 09:47:01 +0200 Subject: [PATCH 056/217] add code to protect_constraints edges tagged as constraints are not refined when protect_constraints is true --- .../internal/named_function_params.h | 15 ++++ .../internal/remesh_impl.h | 90 ++++++++++++++----- .../CGAL/Polygon_mesh_processing/remesh.h | 6 +- 3 files changed, 90 insertions(+), 21 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/named_function_params.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/named_function_params.h index c2a018f96c3..5bbb17e36dc 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/named_function_params.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/named_function_params.h @@ -35,6 +35,7 @@ namespace CGAL{ enum less_halfedge_t { less_halfedge }; enum geom_traits_t { geom_traits }; enum number_of_iterations_t { number_of_iterations }; + enum protect_constraints_t { protect_constraints }; //internal enum weight_calculator_t { weight_calculator }; @@ -130,6 +131,13 @@ namespace CGAL{ return Params(n, *this); } + pmp_bgl_named_params + protect_constraints(const bool& b) const + { + typedef pmp_bgl_named_params Params; + return Params(b, *this); + } + //overload template pmp_bgl_named_params @@ -252,6 +260,13 @@ namespace parameters{ return Params(n); } + pmp_bgl_named_params + protect_constraints(const bool& b) + { + typedef pmp_bgl_named_params Params; + return Params(b); + } + //overload template pmp_bgl_named_params diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index fd1b37f9161..273c732f9a0 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -96,12 +96,14 @@ namespace internal { Incremental_remesher(PolygonMesh& pmesh , const FaceRange& face_range , VertexPointMap& vpmap - , const EdgeIsConstrainedMap& ecmap) + , const EdgeIsConstrainedMap& ecmap + , const bool protect_constraints) : mesh_(pmesh) , vpmap_(vpmap) , own_tree_(true) , input_triangles_() , halfedge_status_map_() + , protect_constraints_(protect_constraints) { CGAL_assertion(CGAL::is_triangle_mesh(mesh_)); @@ -162,9 +164,12 @@ namespace internal { halfedge_descriptor he = eit->second; double sqlen = eit->first; long_edges.right.erase(eit); - Point refinement_point = this->midpoint(he); + + if (protect_constraints_ && !is_split_allowed(edge(he, mesh_))) + continue; //split edge + Point refinement_point = this->midpoint(he); halfedge_descriptor hnew = CGAL::Euler::split_edge(he, mesh_); CGAL_assertion(he == next(hnew, mesh_)); ++nb_splits; @@ -173,6 +178,11 @@ namespace internal { vertex_descriptor vnew = target(hnew, mesh_); put(vpmap_, vnew, refinement_point); + //after splitting + halfedge_descriptor hnew_opp = opposite(hnew, mesh_); + halfedge_added(hnew, status(he)); + halfedge_added(hnew_opp, status(opposite(he, mesh_))); + //check sub-edges double sqlen_new = 0.25 * sqlen; if (sqlen_new > sq_high) @@ -182,20 +192,13 @@ namespace internal { long_edges.insert(long_edge(next(hnew, mesh_), sqlen_new)); } - //after splitting - halfedge_descriptor hnew_opp = opposite(hnew, mesh_); - halfedge_added(hnew, status(he)); - halfedge_added(hnew_opp, status(opposite(he, mesh_))); - //insert new edges to keep triangular faces, and update long_edges - if (!is_on_border(hnew)) { halfedge_descriptor hnew2 = CGAL::Euler::split_face(hnew, next(next(hnew, mesh_), mesh_), mesh_); - Halfedge_status snew = (is_on_patch(hnew) - || (is_on_patch_border(hnew) && !is_on_patch(hnew_opp))) + Halfedge_status snew = (is_on_patch(hnew) || is_on_patch_border(hnew)) ? PATCH : MESH; halfedge_added(hnew2, snew); @@ -215,8 +218,7 @@ namespace internal { halfedge_descriptor hnew2 = CGAL::Euler::split_face(prev(hnew_opp, mesh_), next(hnew_opp, mesh_), mesh_); - Halfedge_status snew = (is_on_patch(hnew_opp) - || (is_on_patch_border(hnew_opp) && !is_on_patch(hnew))) + Halfedge_status snew = (is_on_patch(hnew_opp) || is_on_patch_border(hnew_opp)) ? PATCH : MESH; halfedge_added(hnew2, snew); @@ -641,23 +643,59 @@ namespace internal { && (plane1.oriented_side(p4) != plane2.oriented_side(p4)); } - //todo : simplify the list of cases bool is_split_allowed(const edge_descriptor& e) const { halfedge_descriptor he = halfedge(e, mesh_); - return is_on_patch(he) //opp is also on patch - || (is_on_border(he) && is_on_patch_border(opposite(he, mesh_))) - || (is_on_border(opposite(he, mesh_)) && is_on_patch_border(he)) - || is_on_patch_border(he) - || is_on_patch_border(opposite(he, mesh_)); + halfedge_descriptor hopp = opposite(he, mesh_); + + bool splittable = false; + if (is_on_patch(face(he, mesh_))) + splittable = is_split_allowed(he); + + if (splittable && is_on_patch(face(hopp, mesh_))) + splittable = is_split_allowed(hopp); + + return splittable; + } + + bool is_split_allowed(const halfedge_descriptor& h) const + { + if (!protect_constraints_)//allow splitting constraints + { + return is_on_patch_border(h) + || is_on_patch(h) + || is_on_border(h); + } + else + { + if (!is_on_patch(h)) //PATCH are the only splittable edges + return false; + else + return is_longest_edge_of_face(h); + } + } + + bool is_longest_edge_of_face(const halfedge_descriptor& h) const + { + double sqh = sqlength(h); + return sqh >= sqlength(next(h, mesh_)) + && sqh >= sqlength(next(next(h, mesh_), mesh_)); } bool is_collapse_allowed(const edge_descriptor& e) const { halfedge_descriptor he = halfedge(e, mesh_); + halfedge_descriptor hopp = opposite(he, mesh_); + + if (protect_constraints_) + { + if (is_on_patch_border(he) || is_on_patch_border(hopp)) + return false; + } + return is_on_patch(he) //opp is also on patch - || (is_on_border(he) && is_on_patch_border(opposite(he, mesh_))) - || (is_on_border(opposite(he, mesh_)) && is_on_patch_border(he)); + || (is_on_border(he) && is_on_patch_border(hopp)) + || (is_on_border(hopp) && is_on_patch_border(he)); } void tag_halfedges_status(const FaceRange& face_range @@ -743,6 +781,17 @@ namespace internal { return res; } + bool is_on_patch(const face_descriptor& f) const + { + BOOST_FOREACH(halfedge_descriptor h, + halfedges_around_face(halfedge(f, mesh_), mesh_)) + { + if (is_on_patch(h) || is_on_patch_border(h)) + return true; + } + return false; + } + bool is_on_patch(const vertex_descriptor& v) const { BOOST_FOREACH(halfedge_descriptor h, @@ -894,6 +943,7 @@ namespace internal { bool own_tree_; Triangle_list input_triangles_; std::map halfedge_status_map_; + bool protect_constraints_; };//end class Incremental_remesher }//end namespace internal diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h index 77667421dbe..ec222d5fba5 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h @@ -71,6 +71,8 @@ void incremental_triangle_based_remeshing(PolygonMesh& pmesh , const double& target_edge_length , const NamedParameters& np) { + std::cout.precision(18); + typedef PolygonMesh PM; using boost::choose_pmap; using boost::get_param; @@ -92,8 +94,10 @@ void incremental_triangle_based_remeshing(PolygonMesh& pmesh = choose_param(get_param(np, edge_is_constrained), internal::Border_constraint_pmap(pmesh, faces)); + bool protect = choose_param(get_param(np, protect_constraints), false); + typename internal::Incremental_remesher - remesher(pmesh, faces, vpmap, ecmap); + remesher(pmesh, faces, vpmap, ecmap, protect); unsigned int nb_iterations = choose_param(get_param(np, number_of_iterations), 1); From 2b7bf24205439511dfcf5cc0c57ce03ed92e55ec Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 29 May 2015 10:35:58 +0200 Subject: [PATCH 057/217] add documentation for protect_constraints --- .../include/CGAL/Polygon_mesh_processing/remesh.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h index ec222d5fba5..a1459f129ef 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h @@ -58,6 +58,13 @@ namespace Polygon_mesh_processing { * \cgalParamEnd * \cgalParamBegin{edge_is_constrained_map} * \cgalParamEnd +* \cgalParamBegin{protect_constraints} If `true`, the edges set as constrained +* in `edge_is_constrained_map` (or by default the boundary edges) +* are not splitted nor collapsed during remeshing. +* Note that around edges that have their length higher than +* twice `target_edge_length`, remeshing will fail to provide +* good quality results. +* \cgalParamEnd * \cgalNamedParamsEnd * *@todo we suppose `faces` describe only one patch. Handle several patches. From ca12add0bfb89a1057fe942f1b7f5d3c184ea006 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 29 May 2015 11:44:42 +0200 Subject: [PATCH 058/217] add QDialog for isotropic remeshing options --- Polyhedron/demo/Polyhedron/CMakeLists.txt | 3 +- ...yhedron_demo_isotropic_remeshing_dialog.ui | 187 ++++++++++++++++++ ...hedron_demo_isotropic_remeshing_plugin.cpp | 83 ++++---- 3 files changed, 237 insertions(+), 36 deletions(-) create mode 100644 Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_dialog.ui diff --git a/Polyhedron/demo/Polyhedron/CMakeLists.txt b/Polyhedron/demo/Polyhedron/CMakeLists.txt index 93b5627ba0a..57e641c1891 100644 --- a/Polyhedron/demo/Polyhedron/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/CMakeLists.txt @@ -98,6 +98,7 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND) qt4_wrap_ui( remeshingUI_FILES Remeshing_dialog.ui) qt4_wrap_ui( Mean_curvature_flow_skeleton_pluginUI_FILES Mean_curvature_flow_skeleton_plugin.ui) qt4_wrap_ui( meshingUI_FILES Meshing_dialog.ui ) + qt4_wrap_ui( isotropicRemeshingUI_FILES Polyhedron_demo_isotropic_remeshing_dialog.ui) qt4_wrap_ui( cameraUI_FILES Camera_positions_list.ui ) qt4_wrap_ui( PreferencesUI_FILES Preferences.ui ) qt4_wrap_ui( point_inside_polyhedronUI_FILES Point_inside_polyhedron_widget.ui) @@ -505,7 +506,7 @@ if(CGAL_Qt4_FOUND AND QT4_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND) target_link_libraries(detect_sharp_edges_plugin scene_polyhedron_item) - polyhedron_demo_plugin(isotropic_remeshing_plugin Polyhedron_demo_isotropic_remeshing_plugin) + polyhedron_demo_plugin(isotropic_remeshing_plugin Polyhedron_demo_isotropic_remeshing_plugin ${isotropicRemeshingUI_FILES}) target_link_libraries(isotropic_remeshing_plugin scene_polyhedron_item scene_polyhedron_selection_item) # diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_dialog.ui b/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_dialog.ui new file mode 100644 index 00000000000..63a48bdad5c --- /dev/null +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_dialog.ui @@ -0,0 +1,187 @@ + + + Isotropic_remeshing_dialog + + + true + + + + 0 + 0 + 414 + 225 + + + + Isotropic remeshing criteria + + + + + + + 15 + 75 + true + + + + NO OBJECT + + + + + + + No size + + + + + + + Isotropic remeshing + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Number of iterations + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + nbIterations_spinbox + + + + + + + Target edge length + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + edgeLength_dspinbox + + + + + + + + 110 + 0 + + + + 1000.000000000000000 + + + 0.100000000000000 + + + + + + + + + + true + + + + + + + Protect border/selected edges + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 110 + 0 + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + edgeLength_dspinbox + nbIterations_spinbox + buttonBox + + + + + buttonBox + accepted() + Isotropic_remeshing_dialog + accept() + + + 388 + 288 + + + 157 + 195 + + + + + buttonBox + rejected() + Isotropic_remeshing_dialog + reject() + + + 388 + 288 + + + 286 + 195 + + + + + diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp index d1e0a176caf..58406f3e1cb 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp @@ -13,14 +13,16 @@ #include #include #include -#include #include +#include #include #include #include #include +#include "ui_Polyhedron_demo_isotropic_remeshing_dialog.h" + class Polyhedron_demo_isotropic_remeshing_plugin : public QObject, public Polyhedron_demo_plugin_helper @@ -63,43 +65,52 @@ public Q_SLOTS: if (poly_item || selection_item) { - double diago_length = (poly_item != NULL) - ? poly_item->bbox().diagonal_length() - : selection_item->bbox().diagonal_length(); + // Create dialog box + QDialog dialog(mw); + Ui::Isotropic_remeshing_dialog ui; + ui.setupUi(&dialog); + connect(ui.buttonBox, SIGNAL(accepted()), &dialog, SLOT(accept())); + connect(ui.buttonBox, SIGNAL(rejected()), &dialog, SLOT(reject())); + + //Set default parameters + bool p_ = (poly_item != NULL); + Scene_interface::Bbox bbox = p_ ? poly_item->bbox() : selection_item->bbox(); + ui.objectName->setText(p_ ? poly_item->name() : selection_item->name()); + ui.objectNameSize->setText( + tr("Object bbox size (w,h,d): %1, %2, %3") + .arg(bbox.width(), 0, 'g', 3) + .arg(bbox.height(), 0, 'g', 3) + .arg(bbox.depth(), 0, 'g', 3)); + + double diago_length = bbox.diagonal_length(); + ui.edgeLength_dspinbox->setDecimals(3); + ui.edgeLength_dspinbox->setSingleStep(0.001); + ui.edgeLength_dspinbox->setRange(1e-6 * diago_length, //min + 2. * diago_length);//max + ui.edgeLength_dspinbox->setValue(0.05 * diago_length); std::ostringstream oss; - oss << "Target edge length?" << std::endl; - oss << " Diagonal length of the Bbox of the selection to remesh is "; - oss << diago_length << std::endl; - oss << " (default is 5% of it)" << std::endl; + oss << "Diagonal length of the Bbox of the selection to remesh is "; + oss << diago_length << "." << std::endl; + oss << "Default is 5% of it" << std::endl; + ui.edgeLength_dspinbox->setToolTip(QString::fromStdString(oss.str())); - bool ok; - double target_length = QInputDialog::getDouble(this->mw, - QString("Isotropic remeshing : Edge length"), - QString::fromStdString(oss.str()),//question - 0.05 * diago_length, //value - 1e-6 * diago_length, //min - 2. * diago_length, //max - 3, //decimals - &ok); //Qt::WindowFlags flags = 0); - if (!ok) - { - std::cout << "Remeshing aborted" << std::endl; - return; - } - double nb_iter = QInputDialog::getInt(this->mw, - QString("Isotropic remeshing : Number of iterations"), - QString("Enter number of iterations"),//question - 1, //value - 1, //min - 1000, //max - 1, //step - &ok); //Qt::WindowFlags flags = 0); - if (!ok) + ui.nbIterations_spinbox->setSingleStep(1); + ui.nbIterations_spinbox->setRange(1/*min*/, 1000/*max*/); + ui.nbIterations_spinbox->setValue(1); + + ui.protect_checkbox->setChecked(false); + + // Get values + int i = dialog.exec(); + if (i == QDialog::Rejected) { std::cout << "Remeshing aborted" << std::endl; return; } + double target_length = ui.edgeLength_dspinbox->value(); + int nb_iter = ui.nbIterations_spinbox->value(); + bool protect = ui.protect_checkbox->isChecked(); // wait cursor QApplication::setOverrideCursor(Qt::WaitCursor); @@ -118,19 +129,21 @@ public Q_SLOTS: , selection_item->selected_facets , target_length , CGAL::Polygon_mesh_processing::parameters::number_of_iterations(nb_iter) - .edge_is_constrained_map( - selection_item->selected_edges_pmap(selected))); + .edge_is_constrained_map(selection_item->selected_edges_pmap(selected)) + .protect_constraints(protect)); selection_item->poly_item_changed(); selection_item->clear_all(); selection_item->changed_with_poly_item(); } - else if (poly_item){ + else if (poly_item) + { CGAL::Polygon_mesh_processing::incremental_triangle_based_remeshing( *poly_item->polyhedron() , faces(*poly_item->polyhedron()) , target_length - , CGAL::Polygon_mesh_processing::parameters::number_of_iterations(nb_iter)); + , CGAL::Polygon_mesh_processing::parameters::number_of_iterations(nb_iter) + .protect_constraints(protect)); poly_item->changed(); } From 127327fff3e05d004375aa2ed536cf4ed61e8e56 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 29 May 2015 11:47:32 +0200 Subject: [PATCH 059/217] add vertical spacers between groups --- .../demo/Polyhedron/Selection_widget.ui | 77 +++++++++++++++++-- 1 file changed, 71 insertions(+), 6 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Selection_widget.ui b/Polyhedron/demo/Polyhedron/Selection_widget.ui index b5ea7d36ecc..cbdc0f6be44 100644 --- a/Polyhedron/demo/Polyhedron/Selection_widget.ui +++ b/Polyhedron/demo/Polyhedron/Selection_widget.ui @@ -57,6 +57,19 @@ + + + + Qt::Vertical + + + + 20 + 40 + + + + @@ -134,6 +147,19 @@ + + + + Qt::Vertical + + + + 20 + 40 + + + + @@ -185,6 +211,19 @@ + + + + Qt::Vertical + + + + 20 + 40 + + + + @@ -233,6 +272,19 @@ + + + + Qt::Vertical + + + + 20 + 40 + + + + @@ -273,14 +325,17 @@ - - - + + + Qt::Vertical - - Keep connected components of Selected Facets + + + 20 + 40 + - + @@ -310,6 +365,16 @@ + + + + + + + Keep connected components of Selected Facets + + + From 67874c737d6f9cc5c636e01552908640ba710bbc Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 29 May 2015 13:10:50 +0200 Subject: [PATCH 060/217] fix test when splitting of constraints is allowed --- .../internal/remesh_impl.h | 67 ++++++++++--------- 1 file changed, 34 insertions(+), 33 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 273c732f9a0..23e523b9fa3 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -198,7 +198,9 @@ namespace internal { halfedge_descriptor hnew2 = CGAL::Euler::split_face(hnew, next(next(hnew, mesh_), mesh_), mesh_); - Halfedge_status snew = (is_on_patch(hnew) || is_on_patch_border(hnew)) + Halfedge_status snew = (is_on_patch(hnew) + || (is_on_patch_border(hnew) && !is_on_patch(hnew_opp)) + || (is_on_patch_border(hnew) && is_on_patch_border(hnew_opp))) ? PATCH : MESH; halfedge_added(hnew2, snew); @@ -218,8 +220,10 @@ namespace internal { halfedge_descriptor hnew2 = CGAL::Euler::split_face(prev(hnew_opp, mesh_), next(hnew_opp, mesh_), mesh_); - Halfedge_status snew = (is_on_patch(hnew_opp) || is_on_patch_border(hnew_opp)) - ? PATCH + Halfedge_status snew = (is_on_patch(hnew_opp) + || (is_on_patch_border(hnew_opp) && !is_on_patch(hnew)) + || (is_on_patch_border(hnew_opp) && is_on_patch_border(hnew))) + ? PATCH : MESH; halfedge_added(hnew2, snew); halfedge_added(opposite(hnew2, mesh_), snew); @@ -645,41 +649,38 @@ namespace internal { bool is_split_allowed(const edge_descriptor& e) const { - halfedge_descriptor he = halfedge(e, mesh_); - halfedge_descriptor hopp = opposite(he, mesh_); + halfedge_descriptor h = halfedge(e, mesh_); + halfedge_descriptor hopp = opposite(h, mesh_); - bool splittable = false; - if (is_on_patch(face(he, mesh_))) - splittable = is_split_allowed(he); - - if (splittable && is_on_patch(face(hopp, mesh_))) - splittable = is_split_allowed(hopp); - - return splittable; - } - - bool is_split_allowed(const halfedge_descriptor& h) const - { - if (!protect_constraints_)//allow splitting constraints - { - return is_on_patch_border(h) - || is_on_patch(h) - || is_on_border(h); - } - else + if (protect_constraints_) { if (!is_on_patch(h)) //PATCH are the only splittable edges return false; - else - return is_longest_edge_of_face(h); - } - } + else //h and hopp are PATCH + { + //check whether h is the longest edge in its associated face + //overwise refinement will go for an endless loop + double sqh = sqlength(h); + if (sqh < sqlength(next(h, mesh_)) + || sqh < sqlength(next(next(h, mesh_), mesh_))) + return false; - bool is_longest_edge_of_face(const halfedge_descriptor& h) const - { - double sqh = sqlength(h); - return sqh >= sqlength(next(h, mesh_)) - && sqh >= sqlength(next(next(h, mesh_), mesh_)); + //do the same for hopp + return sqh >= sqlength(next(hopp, mesh_)) + && sqh >= sqlength(next(next(hopp, mesh_), mesh_)); + } + } + else //allow splitting constraints + { + if (is_on_mesh(h) && is_on_mesh(hopp)) + return false; + else if (is_on_mesh(h) && is_on_border(hopp)) + return false; + else if (is_on_mesh(hopp) && is_on_border(h)) + return false; + else + return true; + } } bool is_collapse_allowed(const edge_descriptor& e) const From 117a24807df6a77636d74dda1609ebee7d935a5f Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 29 May 2015 13:50:15 +0200 Subject: [PATCH 061/217] make tests simpler --- .../CGAL/Polygon_mesh_processing/internal/remesh_impl.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 23e523b9fa3..ef317dd95b6 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -198,9 +198,7 @@ namespace internal { halfedge_descriptor hnew2 = CGAL::Euler::split_face(hnew, next(next(hnew, mesh_), mesh_), mesh_); - Halfedge_status snew = (is_on_patch(hnew) - || (is_on_patch_border(hnew) && !is_on_patch(hnew_opp)) - || (is_on_patch_border(hnew) && is_on_patch_border(hnew_opp))) + Halfedge_status snew = (is_on_patch(hnew) || is_on_patch_border(hnew)) ? PATCH : MESH; halfedge_added(hnew2, snew); @@ -220,9 +218,7 @@ namespace internal { halfedge_descriptor hnew2 = CGAL::Euler::split_face(prev(hnew_opp, mesh_), next(hnew_opp, mesh_), mesh_); - Halfedge_status snew = (is_on_patch(hnew_opp) - || (is_on_patch_border(hnew_opp) && !is_on_patch(hnew)) - || (is_on_patch_border(hnew_opp) && is_on_patch_border(hnew))) + Halfedge_status snew = (is_on_patch(hnew_opp) || is_on_patch_border(hnew_opp)) ? PATCH : MESH; halfedge_added(hnew2, snew); From 8d5312d2639a068dd2d923d8abf31597a72826a2 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 29 May 2015 14:02:26 +0200 Subject: [PATCH 062/217] reorganize test --- .../CGAL/Polygon_mesh_processing/internal/remesh_impl.h | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index ef317dd95b6..b1653c1f8cd 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -657,12 +657,10 @@ namespace internal { //check whether h is the longest edge in its associated face //overwise refinement will go for an endless loop double sqh = sqlength(h); - if (sqh < sqlength(next(h, mesh_)) - || sqh < sqlength(next(next(h, mesh_), mesh_))) - return false; - + return sqh >= sqlength(next(h, mesh_)) + && sqh >= sqlength(next(next(h, mesh_), mesh_)) //do the same for hopp - return sqh >= sqlength(next(hopp, mesh_)) + && sqh >= sqlength(next(hopp, mesh_)) && sqh >= sqlength(next(next(hopp, mesh_), mesh_)); } } From 8b5902b038e65ebb934c23f9dac180b764a1394c Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 29 May 2015 15:34:29 +0200 Subject: [PATCH 063/217] add function to split long edges listed by the user this changes the remesher internal API only --- .../internal/remesh_impl.h | 86 +++++++++++++++++-- .../CGAL/Polygon_mesh_processing/remesh.h | 51 ++++++++++- .../remeshing_test.cpp | 13 ++- 3 files changed, 138 insertions(+), 12 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index b1653c1f8cd..53837fb2dc0 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -68,10 +68,8 @@ namespace internal { }; template class Incremental_remesher { @@ -94,9 +92,7 @@ namespace internal { public: Incremental_remesher(PolygonMesh& pmesh - , const FaceRange& face_range , VertexPointMap& vpmap - , const EdgeIsConstrainedMap& ecmap , const bool protect_constraints) : mesh_(pmesh) , vpmap_(vpmap) @@ -120,8 +116,6 @@ namespace internal { Triangle_3(get(vpmap, v1), get(vpmap, v2), get(vpmap, v3))); } tree_ptr_ = new AABB_tree(input_triangles_.begin(), input_triangles_.end()); - - tag_halfedges_status(face_range, ecmap); } ~Incremental_remesher() @@ -130,6 +124,85 @@ namespace internal { delete tree_ptr_; } + template + void init_faces_remeshing(const FaceRange& face_range + , const EdgeIsConstrainedMap& ecmap) + { + tag_halfedges_status(face_range, ecmap); + } + + // split edges of edge_range that have their length > high + template + void split_long_edges(const EdgeRange& edge_range, + const double& high) + { + typedef boost::bimap< + boost::bimaps::set_of, + boost::bimaps::multiset_of > > Boost_bimap; + typedef typename Boost_bimap::value_type long_edge; + + std::cout << "Split long edges (" << high << ")..."; + double sq_high = high*high; + + //collect long edges + Boost_bimap long_edges; + BOOST_FOREACH(edge_descriptor e, edge_range) + { + double sqlen = sqlength(e); + if (sqlen > sq_high) + long_edges.insert(long_edge(halfedge(e, mesh_), sqlen)); + } + + //split long edges + unsigned int nb_splits = 0; + while (!long_edges.empty()) + { + //the edge with longest length + typename Boost_bimap::right_map::iterator eit = long_edges.right.begin(); + halfedge_descriptor he = eit->second; + double sqlen = eit->first; + long_edges.right.erase(eit); + + //split edge + Point refinement_point = this->midpoint(he); + halfedge_descriptor hnew = CGAL::Euler::split_edge(he, mesh_); + CGAL_assertion(he == next(hnew, mesh_)); + ++nb_splits; + + //move refinement point + vertex_descriptor vnew = target(hnew, mesh_); + put(vpmap_, vnew, refinement_point); + + //after splitting + halfedge_descriptor hnew_opp = opposite(hnew, mesh_); + + //check sub-edges + double sqlen_new = 0.25 * sqlen; + if (sqlen_new > sq_high) + { + //if it was more than twice the "long" threshold, insert them + long_edges.insert(long_edge(hnew, sqlen_new)); + long_edges.insert(long_edge(next(hnew, mesh_), sqlen_new)); + } + + //insert new edges to keep triangular faces, and update long_edges + if (!is_border(hnew, mesh_)) + { + halfedge_descriptor hnew2 + = CGAL::Euler::split_face(hnew, next(next(hnew, mesh_), mesh_), mesh_); + } + + //do it again on the other side if we're not on boundary + if (!is_border(hnew_opp, mesh_)) + { + halfedge_descriptor hnew2 + = CGAL::Euler::split_face(prev(hnew_opp, mesh_), next(hnew_opp, mesh_), mesh_); + } + } + std::cout << " done (" << nb_splits << " splits)." << std::endl; + } + // PMP book : // "visits all edges of the mesh //if an edge is longer than the given threshold `high`, the edge @@ -693,6 +766,7 @@ namespace internal { || (is_on_border(hopp) && is_on_patch_border(he)); } + template void tag_halfedges_status(const FaceRange& face_range , const EdgeIsConstrainedMap& ecmap) { diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h index a1459f129ef..fb054794d7b 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h @@ -67,6 +67,8 @@ namespace Polygon_mesh_processing { * \cgalParamEnd * \cgalNamedParamsEnd * +* @sa `split_long_edges` +* *@todo we suppose `faces` describe only one patch. Handle several patches. *@todo document `number_of_iterations` */ @@ -78,8 +80,6 @@ void incremental_triangle_based_remeshing(PolygonMesh& pmesh , const double& target_edge_length , const NamedParameters& np) { - std::cout.precision(18); - typedef PolygonMesh PM; using boost::choose_pmap; using boost::get_param; @@ -103,8 +103,9 @@ void incremental_triangle_based_remeshing(PolygonMesh& pmesh bool protect = choose_param(get_param(np, protect_constraints), false); - typename internal::Incremental_remesher - remesher(pmesh, faces, vpmap, ecmap, protect); + typename internal::Incremental_remesher + remesher(pmesh, vpmap, protect); + remesher.init_faces_remeshing(faces, ecmap); unsigned int nb_iterations = choose_param(get_param(np, number_of_iterations), 1); @@ -134,6 +135,48 @@ void incremental_triangle_based_remeshing(PolygonMesh& pmesh parameters::all_default()); } +/*! +* \ingroup PkgPolygonMeshProcessing +* @brief splits the edges listed in `edges` +* +* @tparam PolygonMesh model of `MutableFaceGraph` that +* has an internal property map for `CGAL::vertex_point_t` +*/ +template +void split_long_edges(PolygonMesh& pmesh + , EdgeRange& edge_range + , const double& max_length + , const NamedParameters& np) +{ + typedef PolygonMesh PM; + using boost::choose_pmap; + using boost::get_param; + + typedef typename GetGeomTraits::type GT; + typedef typename GetVertexPointMap::type VPMap; + VPMap vpmap = choose_pmap(get_param(np, boost::vertex_point), + pmesh, + boost::vertex_point); + + typename internal::Incremental_remesher + remesher(pmesh, vpmap, false/*protect constraints*/); + + remesher.split_long_edges(edge_range, max_length); +} + +template +void split_long_edges(PolygonMesh& pmesh + , EdgeRange& edges + , const double& max_length) +{ + split_long_edges(pmesh, + edges, + max_length, + parameters::all_default()); +} + } //end namespace Polygon_mesh_processing } //end namespace CGAL diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp index 7104a6f6188..99109836bc3 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -103,13 +104,21 @@ int main(int argc, char* argv[]) } const std::set& patch = k_ring(patch_center, 3, m); + std::vector border; + PMP::get_border(m, patch, std::back_inserter(border)); + + CGAL::Polygon_mesh_processing::split_long_edges( + m, border, 1.5 * target_edge_length); + CGAL::Timer t; t.start(); CGAL::Polygon_mesh_processing::incremental_triangle_based_remeshing(m, - faces(m),//patch, + patch, target_edge_length, - CGAL::Polygon_mesh_processing::parameters::number_of_iterations(nb_iter)); + CGAL::Polygon_mesh_processing::parameters::number_of_iterations(nb_iter) + .protect_constraints(true) + ); t.stop(); std::cout << "Remeshing took " << t.time() << std::endl; From edbe0338f615b982dfd83df9d72f9eb91e24edae Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 29 May 2015 17:01:02 +0200 Subject: [PATCH 064/217] add checkbox to split only selected edges --- ...yhedron_demo_isotropic_remeshing_dialog.ui | 103 +++++++++++------- ...hedron_demo_isotropic_remeshing_plugin.cpp | 49 ++++++++- 2 files changed, 113 insertions(+), 39 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_dialog.ui b/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_dialog.ui index 63a48bdad5c..cefb9e94d95 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_dialog.ui +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_dialog.ui @@ -10,7 +10,7 @@ 0 0 414 - 225 + 282 @@ -38,25 +38,41 @@ + + + + Remesh + + + + + + Split only border/selected edges + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + Isotropic remeshing - - - - Qt::Vertical - - - - 20 - 40 - - - - @@ -70,19 +86,6 @@ - - - - Target edge length - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - edgeLength_dspinbox - - - @@ -99,6 +102,16 @@ + + + + + 110 + 0 + + + + @@ -109,6 +122,19 @@ + + + + Target edge length + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + edgeLength_dspinbox + + + @@ -119,19 +145,22 @@ - - - - - 110 - 0 - - - - + + + + Qt::Vertical + + + + 20 + 40 + + + + diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp index 58406f3e1cb..bf1f0aad970 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp @@ -72,6 +72,12 @@ public Q_SLOTS: connect(ui.buttonBox, SIGNAL(accepted()), &dialog, SLOT(accept())); connect(ui.buttonBox, SIGNAL(rejected()), &dialog, SLOT(reject())); + //connect checkbox to spinbox + connect(ui.splitEdgesOnly_checkbox, SIGNAL(toggled(bool)), + ui.nbIterations_spinbox, SLOT(setDisabled(bool))); + connect(ui.splitEdgesOnly_checkbox, SIGNAL(toggled(bool)), + ui.protect_checkbox, SLOT(setDisabled(bool))); + //Set default parameters bool p_ = (poly_item != NULL); Scene_interface::Bbox bbox = p_ ? poly_item->bbox() : selection_item->bbox(); @@ -108,6 +114,7 @@ public Q_SLOTS: std::cout << "Remeshing aborted" << std::endl; return; } + bool edges_only = ui.splitEdgesOnly_checkbox->isChecked(); double target_length = ui.edgeLength_dspinbox->value(); int nb_iter = ui.nbIterations_spinbox->value(); bool protect = ui.protect_checkbox->isChecked(); @@ -118,8 +125,29 @@ public Q_SLOTS: QTime time; time.start(); + typedef boost::graph_traits::edge_descriptor edge_descriptor; + typedef boost::graph_traits::halfedge_descriptor halfedge_descriptor; if (selection_item) { + if (edges_only) + { + const Polyhedron& pmesh = *selection_item->polyhedron(); + std::vector edges; + BOOST_FOREACH(edge_descriptor e, selection_item->selected_edges) + { + if (selection_item->selected_facets.find(face(halfedge(e, pmesh), pmesh)) + != selection_item->selected_facets.end() + || selection_item->selected_facets.find(face(opposite(halfedge(e, pmesh), pmesh), pmesh)) + != selection_item->selected_facets.end()) + edges.push_back(e); + } + CGAL::Polygon_mesh_processing::split_long_edges( + *selection_item->polyhedron() + , edges + , target_length); + } + else + { std::vector selected( selection_item->polyhedron()->size_of_halfedges()/2, false); @@ -131,20 +159,37 @@ public Q_SLOTS: , CGAL::Polygon_mesh_processing::parameters::number_of_iterations(nb_iter) .edge_is_constrained_map(selection_item->selected_edges_pmap(selected)) .protect_constraints(protect)); - + } selection_item->poly_item_changed(); selection_item->clear_all(); selection_item->changed_with_poly_item(); } else if (poly_item) { + if (edges_only) + { + const Polyhedron& pmesh = *poly_item->polyhedron(); + std::vector border; + CGAL::Polygon_mesh_processing::get_border(pmesh, + faces(*poly_item->polyhedron()), + std::back_inserter(border)); + std::vector border_edges; + BOOST_FOREACH(halfedge_descriptor h, border) + border_edges.push_back(edge(h, pmesh)); + + CGAL::Polygon_mesh_processing::split_long_edges(*poly_item->polyhedron() + , border_edges + , target_length); + } + else + { CGAL::Polygon_mesh_processing::incremental_triangle_based_remeshing( *poly_item->polyhedron() , faces(*poly_item->polyhedron()) , target_length , CGAL::Polygon_mesh_processing::parameters::number_of_iterations(nb_iter) .protect_constraints(protect)); - + } poly_item->changed(); } else{ From 6f667c7a241decdd7cd2ecfeb437522c9e59ba5b Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 29 May 2015 17:01:19 +0200 Subject: [PATCH 065/217] reorganize --- .../CGAL/Polygon_mesh_processing/internal/remesh_impl.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 53837fb2dc0..7d3fda886d3 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -174,9 +174,6 @@ namespace internal { vertex_descriptor vnew = target(hnew, mesh_); put(vpmap_, vnew, refinement_point); - //after splitting - halfedge_descriptor hnew_opp = opposite(hnew, mesh_); - //check sub-edges double sqlen_new = 0.25 * sqlen; if (sqlen_new > sq_high) @@ -194,6 +191,7 @@ namespace internal { } //do it again on the other side if we're not on boundary + halfedge_descriptor hnew_opp = opposite(hnew, mesh_); if (!is_border(hnew_opp, mesh_)) { halfedge_descriptor hnew2 From 0844e79b67bd0ed56620a0d7a9ae7cabf70894de Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Mon, 1 Jun 2015 15:51:23 +0200 Subject: [PATCH 066/217] add code to read selection from input --- .../remeshing_test.cpp | 50 +++++++++++++++++-- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp index 99109836bc3..fa5863d5579 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp @@ -73,6 +73,43 @@ std::set k_ring(vertex_descriptor v, return kring; } +std::set collect_patch(const char* file, + const Mesh& m) +{ + std::set patch; + std::ifstream in(file); + if (!in.is_open()) + return patch; + + std::string line; + std::size_t id; + + if (!std::getline(in, line)) { return patch; } + std::istringstream vertex_line(line); + while (vertex_line >> id) { + if (id >= m.number_of_vertices()) { return patch; } + //do nothing with vertices + } + + if (!std::getline(in, line)) { return patch; } + std::istringstream facet_line(line); + while (facet_line >> id) { + if (id >= m.number_of_faces()) { return patch; } + patch.insert(Mesh::Face_index(id)); + } + + if (!std::getline(in, line)) { return patch; } + std::istringstream edge_line(line); + while (edge_line >> id) { + if (id >= m.number_of_edges()) { return patch; } + //do nothing with edges + } + + in.close(); + return patch; +} + + int main(int argc, char* argv[]) { std::cout.precision(17); @@ -86,9 +123,6 @@ int main(int argc, char* argv[]) } double target_edge_length = (argc > 2) ? atof(argv[2]) : 0.01; - double low = 4. / 5. * target_edge_length; - double high = 4. / 3. * target_edge_length; - unsigned int nb_iter = (argc > 3) ? atoi(argv[3]) : 5; unsigned int center_id = 26; @@ -102,13 +136,19 @@ int main(int argc, char* argv[]) break; } } - const std::set& patch = k_ring(patch_center, 3, m); + + const std::set& patch = + (argc > 4) + ? collect_patch(argv[4], m) + : k_ring(patch_center, 3, m); std::vector border; PMP::get_border(m, patch, std::back_inserter(border)); CGAL::Polygon_mesh_processing::split_long_edges( - m, border, 1.5 * target_edge_length); + m, + border, + /*1.5 * */target_edge_length); CGAL::Timer t; t.start(); From 97379e50b208b0c4491eafa03785cbf2c93431cd Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Mon, 1 Jun 2015 16:15:43 +0200 Subject: [PATCH 067/217] add null vector test (should not happen!) --- .../CGAL/Polygon_mesh_processing/compute_normal.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/compute_normal.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/compute_normal.h index 49ed3e120cc..f85400054d6 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/compute_normal.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/compute_normal.h @@ -93,13 +93,16 @@ compute_face_normal(typename boost::graph_traits::face_descriptor f typedef typename Kernel::Vector_3 Vector; using boost::get_param; - using boost::choose_param; + using boost::choose_const_pmap; Vector normal = CGAL::NULL_VECTOR; sum_normals(pmesh, f - , choose_param(get_param(np, vertex_point), get(CGAL::vertex_point, pmesh)) + , choose_const_pmap(get_param(np, CGAL::vertex_point), pmesh, CGAL::vertex_point) , normal); + if (normal == CGAL::NULL_VECTOR) + return normal; + return normal / std::sqrt(normal * normal); } @@ -183,11 +186,16 @@ compute_vertex_normal(typename boost::graph_traits::vertex_descript if (!is_border(he, pmesh)) { Vector n = compute_face_normal(face(he, pmesh), pmesh, np); + if (n == CGAL::NULL_VECTOR) + continue; normal = normal + (n / std::sqrt(n*n)); } he = opposite(next(he, pmesh), pmesh); } while (he != end); + if (normal == CGAL::NULL_VECTOR) + return normal; + return normal / std::sqrt(normal * normal); } From 7543f35ff2e0648135a3d0c6c76f5654502752db Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 2 Jun 2015 11:47:42 +0200 Subject: [PATCH 068/217] adapt code to PATCH_BORDER cases and add debugging code --- .../internal/remesh_impl.h | 107 ++++++++++++------ 1 file changed, 71 insertions(+), 36 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 7d3fda886d3..6faef62ae3f 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -24,6 +24,10 @@ #include #include +#ifdef CGAL_PMP_REMESHING_DEBUG +#include +#endif + namespace PMP = CGAL::Polygon_mesh_processing; @@ -199,6 +203,9 @@ namespace internal { } } std::cout << " done (" << nb_splits << " splits)." << std::endl; +#ifdef CGAL_DUMP_REMESHING_STEPS + dump("0-border_split.off"); +#endif } // PMP book : @@ -352,22 +359,22 @@ namespace internal { double sqlen = eit->first; short_edges.right.erase(eit); + CGAL_assertion(is_valid(he, mesh_)); + //handle the boundary case : //a PATCH_BORDER edge can be collapsed, //and an edge incident to PATCH_BORDER can be collapsed, //but only if the boundary vertex is kept, //so re-insert opposite(he) to collapse it - if (is_on_border(he)) + if (!is_on_patch(he)) { - he = opposite(he, mesh_); //he now is PATCH_BORDER - CGAL_assertion(is_on_patch_border(he)); - } - else if (is_on_patch_border(opposite(he, mesh_))) - { - CGAL_assertion(is_on_mesh(he)); - he = opposite(he, mesh_); //he now is PATCH_BORDER - CGAL_assertion(is_on_patch_border(he)); - } + CGAL_assertion(!protect_constraints_);//is_collapse_allowed returned false + if (is_on_border(he) || is_on_mesh(he)) + { + he = opposite(he, mesh_); //he now is PATCH_BORDER + CGAL_assertion(is_on_patch_border(he)); + } + }//end if(not on PATCH) //let's try to collapse he into vb vertex_descriptor va = source(he, mesh_); @@ -436,11 +443,22 @@ namespace internal { halfedge_and_opp_removed(prev(he, mesh_)); //perform collapse + Point source_point = get(vpmap_, va); Point target_point = get(vpmap_, vb); + + debug_self_intersections(va); + debug_self_intersections(vb); + + if (va == PM::Vertex_index(388) && vb == PM::Vertex_index(375)) + std::cout << "stop" << std::endl; + vertex_descriptor vkept = CGAL::Euler::collapse_edge(edge(he, mesh_), mesh_); + debug_self_intersections(vkept); + put(vpmap_, vkept, target_point); ++nb_collapses; + // merge halfedge_status to keep the more important on both sides merge_status(en, s_epo, s_ep); if (!mesh_border_case) @@ -452,6 +470,7 @@ namespace internal { CGAL_assertion(source(en, mesh_) == source(en_p, mesh_)); debug_status_map(); debug_patch_border(); + debug_self_intersections(vkept); #endif //insert new/remaining short edges @@ -565,11 +584,15 @@ namespace internal { typedef std::map VNormalsMap; VNormalsMap vnormals; boost::associative_property_map propmap_normals(vnormals); - - PMP::compute_vertex_normals(mesh_, - propmap_normals, - PMP::parameters::vertex_point_map(vpmap_). - geom_traits(GeomTraits())); + BOOST_FOREACH(vertex_descriptor v, vertices(mesh_)) + { + if (!is_on_patch(v)) + continue; + Vector_3 vn = PMP::compute_vertex_normal(v, mesh_ + , PMP::parameters::vertex_point_map(vpmap_) + .geom_traits(GeomTraits())); + put(propmap_normals, v, vn); + } // at each vertex, compute barycenter of neighbors std::map barycenters; @@ -584,27 +607,30 @@ namespace internal { move = move + Vector_3(get(vpmap_, v), get(vpmap_, source(h, mesh_))); ++star_size; } + CGAL_assertion(star_size > 0); move = (1. / (double)star_size) * move; + barycenters[v] = get(vpmap_, v) + move; } // compute moves //todo : iterate on barycenters instead. Would avoid retesting is_on_patch + typedef typename std::map::value_type VP_pair; std::map new_locations; - BOOST_FOREACH(vertex_descriptor v, vertices(mesh_)) + BOOST_FOREACH(const VP_pair& vp, barycenters) { - if (!is_on_patch(v)) - continue; + vertex_descriptor v = vp.first; + Point pv = get(vpmap_, v); Vector_3 nv = boost::get(propmap_normals, v); - Point qv = barycenters[v]; - new_locations[v] = qv + (nv * Vector_3(qv, get(vpmap_, v))) * nv; + Point qv = vp.second; //barycenter at v + + new_locations[v] = qv + (nv * Vector_3(qv, pv)) * nv; } // perform moves - typedef typename std::map::value_type VP_pair; BOOST_FOREACH(const VP_pair& vp, new_locations) { - put(vpmap_, vp.first, new_locations[vp.first]); + put(vpmap_, vp.first, vp.second); } CGAL_assertion(is_valid(mesh_)); @@ -671,7 +697,7 @@ namespace internal { void dump(const char* filename) const { std::ofstream out(filename); -// out << mesh_; + out << mesh_; out.close(); } @@ -729,10 +755,10 @@ namespace internal { //overwise refinement will go for an endless loop double sqh = sqlength(h); return sqh >= sqlength(next(h, mesh_)) - && sqh >= sqlength(next(next(h, mesh_), mesh_)) - //do the same for hopp - && sqh >= sqlength(next(hopp, mesh_)) - && sqh >= sqlength(next(next(hopp, mesh_), mesh_)); + && sqh >= sqlength(next(next(h, mesh_), mesh_)) + //do the same for hopp + && sqh >= sqlength(next(hopp, mesh_)) + && sqh >= sqlength(next(next(hopp, mesh_), mesh_)); } } else //allow splitting constraints @@ -753,15 +779,12 @@ namespace internal { halfedge_descriptor he = halfedge(e, mesh_); halfedge_descriptor hopp = opposite(he, mesh_); - if (protect_constraints_) - { - if (is_on_patch_border(he) || is_on_patch_border(hopp)) - return false; - } - - return is_on_patch(he) //opp is also on patch - || (is_on_border(he) && is_on_patch_border(hopp)) - || (is_on_border(hopp) && is_on_patch_border(he)); + if (is_on_patch(he)) //hopp is also on patch + return true; + else if (is_on_patch_border(he) || is_on_patch_border(hopp)) + return !protect_constraints_;//allowed only when no protection + else + return false; } template @@ -976,6 +999,18 @@ namespace internal { CGAL_assertion(v.second == 2); } + void debug_self_intersections(const vertex_descriptor& v) const + { + std::cout << "Test self intersections..."; + std::vector > facets; + PMP::does_self_intersect( + mesh_, + std::back_inserter(facets), + PMP::parameters::vertex_point_map(vpmap_)); + CGAL_assertion(facets.empty()); + std::cout << "done." << std::endl; + } + void debug_mesh_border() const { std::map mesh_border; From 679e93b252522f011648c8bc145733504bc9a17c Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 2 Jun 2015 12:15:51 +0200 Subject: [PATCH 069/217] remove degenerate faces a posteriori --- .../internal/remesh_impl.h | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 6faef62ae3f..6f1d304df2f 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -443,22 +444,12 @@ namespace internal { halfedge_and_opp_removed(prev(he, mesh_)); //perform collapse - Point source_point = get(vpmap_, va); Point target_point = get(vpmap_, vb); - debug_self_intersections(va); - debug_self_intersections(vb); - - if (va == PM::Vertex_index(388) && vb == PM::Vertex_index(375)) - std::cout << "stop" << std::endl; - vertex_descriptor vkept = CGAL::Euler::collapse_edge(edge(he, mesh_), mesh_); - debug_self_intersections(vkept); - put(vpmap_, vkept, target_point); ++nb_collapses; - // merge halfedge_status to keep the more important on both sides merge_status(en, s_epo, s_ep); if (!mesh_border_case) @@ -470,7 +461,6 @@ namespace internal { CGAL_assertion(source(en, mesh_) == source(en_p, mesh_)); debug_status_map(); debug_patch_border(); - debug_self_intersections(vkept); #endif //insert new/remaining short edges @@ -484,6 +474,9 @@ namespace internal { } }//end if(collapse_ok) } + + PMP::remove_degenerate_faces(mesh_/*todo : add named parameters*/); + std::cout << " done (" << nb_collapses << " collapses)." << std::endl; #ifdef CGAL_PMP_REMESHING_DEBUG @@ -492,6 +485,7 @@ namespace internal { debug_status_map(); debug_patch_border(); debug_mesh_border(); +// debug_self_intersections(); #endif #ifdef CGAL_DUMP_REMESHING_STEPS @@ -999,7 +993,7 @@ namespace internal { CGAL_assertion(v.second == 2); } - void debug_self_intersections(const vertex_descriptor& v) const + void debug_self_intersections() const { std::cout << "Test self intersections..."; std::vector > facets; From 891b426f827e9d0a96117dce4f7a06e76adea9c3 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 2 Jun 2015 16:08:08 +0200 Subject: [PATCH 070/217] new attempt to avoid self intersections --- .../internal/remesh_impl.h | 82 +++++++++++++++++-- 1 file changed, 76 insertions(+), 6 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 6f1d304df2f..962a5601580 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -387,9 +387,23 @@ namespace internal { he = opposite(he, mesh_); va = source(he, mesh_); vb = target(he, mesh_); - CGAL_assertion(is_on_patch_border(vb) && !is_on_patch_border(va)); } + else if (is_on_patch(va) && is_on_patch(vb)) + { + if(!collapse_does_not_invert_face(he)) + { + if (collapse_does_not_invert_face(opposite(he, mesh_))) + { + he = opposite(he, mesh_); + va = source(he, mesh_); + vb = target(he, mesh_); + } + else + continue;//both directions invert a face + } + CGAL_assertion(collapse_does_not_invert_face(he)); + } CGAL_assertion(is_collapse_allowed(edge(he, mesh_))); @@ -479,17 +493,17 @@ namespace internal { std::cout << " done (" << nb_collapses << " collapses)." << std::endl; +#ifdef CGAL_DUMP_REMESHING_STEPS + dump("2-edge_collapse.off"); +#endif + #ifdef CGAL_PMP_REMESHING_DEBUG CGAL_assertion(nb_valid_halfedges() == halfedge_status_map_.size()); CGAL_expensive_assertion(is_triangle_mesh(mesh_)); debug_status_map(); debug_patch_border(); debug_mesh_border(); -// debug_self_intersections(); -#endif - -#ifdef CGAL_DUMP_REMESHING_STEPS - dump("2-edge_collapse.off"); + debug_self_intersections(); #endif } @@ -781,6 +795,62 @@ namespace internal { return false; } + bool collapse_does_not_invert_face(const halfedge_descriptor& h) const + { + vertex_descriptor vs = source(h, mesh_); + vertex_descriptor vt = target(h, mesh_); + + //backup source point + Point ps = get(vpmap_, vs); + //move source at target + put(vpmap_, vs, get(vpmap_, vt)); + + typedef typename GeomTraits::Triangle_3 Triangle; + + Vector_3 normal = CGAL::NULL_VECTOR; + BOOST_FOREACH(halfedge_descriptor hd, halfedges_around_target(h, mesh_)) + { + Triangle tr(get(vpmap_, target(hd, mesh_)), + get(vpmap_, target(next(hd, mesh_), mesh_)), + get(vpmap_, target(next(next(hd, mesh_), mesh_), mesh_))); + if (!tr.is_degenerate()) + { + //Vector_3 nt = tr.supporting_plane().orthogonal_vector(); + Vector_3 nt = PMP::compute_face_normal(face(hd, mesh_), mesh_); + if (normal == CGAL::NULL_VECTOR) + normal = nt; + else if (normal * nt <= 0.) + { + //restore position + put(vpmap_, vs, ps); + return false; + } + } + } + //restore position + put(vpmap_, vs, ps); + return true; + } + + bool has_consistent_orientation(const halfedge_descriptor& h) const + { + Point p = get(vpmap_, source(h, mesh_)); + Point q = get(vpmap_, target(h, mesh_)); + Point r = get(vpmap_, target(next(h, mesh_), mesh_)); + Point r2 = get(vpmap_, target(next(opposite(h, mesh_), mesh_), mesh_)); + + typedef GeomTraits GT; + Vector_3 rp = GT().construct_vector_3_object()(r, p); + Vector_3 rq = GT().construct_vector_3_object()(r, q); + Vector_3 r2p = GT().construct_vector_3_object()(r2, p); + Vector_3 r2q = GT().construct_vector_3_object()(r2, q); + + Vector_3 n1 = GT().construct_cross_product_vector_3_object()(rp, rq); + Vector_3 n2 = GT().construct_cross_product_vector_3_object()(r2q, r2p); + + return is_positive(GT().compute_scalar_product_3_object()(n1, n2)); + } + template void tag_halfedges_status(const FaceRange& face_range , const EdgeIsConstrainedMap& ecmap) From d56e54ec6f199bda3da57c99be5d806dd4615bca Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Thu, 4 Jun 2015 11:33:13 +0200 Subject: [PATCH 071/217] fix the edge collapse step degenerate faces where responsible for some self intersections, so we remove them after collapses and flips the function that checks that no triangle gets inverted by a flip has also been fixed we had to check both the 1-ring of source(h) and target(h), even though those vertices got the same coordinates The common faces in their rings were degenerate, but their normals had all to be checked for consistent orientation also add more debugging code --- .../internal/remesh_impl.h | 108 ++++++++++++------ 1 file changed, 74 insertions(+), 34 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 962a5601580..8d75a07bb0a 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -381,7 +381,6 @@ namespace internal { vertex_descriptor va = source(he, mesh_); vertex_descriptor vb = target(he, mesh_); - //todo : this test can be restricted to avoid some tests if (is_on_patch_border(va) && !is_on_patch_border(vb)) { he = opposite(he, mesh_); @@ -464,6 +463,12 @@ namespace internal { put(vpmap_, vkept, target_point); ++nb_collapses; +#ifdef CGAL_PMP_REMESHING_DEBUG + debug_normals(vkept); + //PMP::remove_degenerate_faces(mesh_/*todo : add named parameters*/); + //debug_self_intersections(vkept); +#endif + // merge halfedge_status to keep the more important on both sides merge_status(en, s_epo, s_ep); if (!mesh_border_case) @@ -567,6 +572,8 @@ namespace internal { || (vb == source(he, mesh_) && va == target(he, mesh_))); } } + PMP::remove_degenerate_faces(mesh_/*todo : add named parameters*/); + std::cout << "done. ("<< nb_flips << " flips)" << std::endl; #ifdef CGAL_PMP_REMESHING_DEBUG @@ -805,26 +812,33 @@ namespace internal { //move source at target put(vpmap_, vs, get(vpmap_, vt)); - typedef typename GeomTraits::Triangle_3 Triangle; - - Vector_3 normal = CGAL::NULL_VECTOR; - BOOST_FOREACH(halfedge_descriptor hd, halfedges_around_target(h, mesh_)) + //collect normals to faces around vs AND vt + //vertices are at the same location, but connectivity is still be same, + //with plenty of degenerate triangles (which are common to both stars) + std::vector normals; + BOOST_FOREACH(halfedge_descriptor hd, + halfedges_around_target(h, mesh_)) { - Triangle tr(get(vpmap_, target(hd, mesh_)), - get(vpmap_, target(next(hd, mesh_), mesh_)), - get(vpmap_, target(next(next(hd, mesh_), mesh_), mesh_))); - if (!tr.is_degenerate()) + Vector_3 n = compute_normal(face(hd, mesh_)); + if (n != CGAL::NULL_VECTOR) + normals.push_back(n); + } + BOOST_FOREACH(halfedge_descriptor hd, + halfedges_around_target(opposite(h, mesh_), mesh_)) + { + Vector_3 n = compute_normal(face(hd, mesh_)); + if (n != CGAL::NULL_VECTOR) + normals.push_back(n); + } + + //check all normals have same orientation + for(std::size_t i = 1; i < normals.size(); ++i)/*start at 1 on purpose*/ + { + if (normals[i-1] * normals[i] <= 0.) { - //Vector_3 nt = tr.supporting_plane().orthogonal_vector(); - Vector_3 nt = PMP::compute_face_normal(face(hd, mesh_), mesh_); - if (normal == CGAL::NULL_VECTOR) - normal = nt; - else if (normal * nt <= 0.) - { - //restore position - put(vpmap_, vs, ps); - return false; - } + //restore position + put(vpmap_, vs, ps); + return false; } } //restore position @@ -832,23 +846,18 @@ namespace internal { return true; } - bool has_consistent_orientation(const halfedge_descriptor& h) const + Vector_3 compute_normal(const face_descriptor& f) const { - Point p = get(vpmap_, source(h, mesh_)); - Point q = get(vpmap_, target(h, mesh_)); - Point r = get(vpmap_, target(next(h, mesh_), mesh_)); - Point r2 = get(vpmap_, target(next(opposite(h, mesh_), mesh_), mesh_)); + halfedge_descriptor hd = halfedge(f, mesh_); + typename GeomTraits::Triangle_3 + tr(get(vpmap_, target(hd, mesh_)), + get(vpmap_, target(next(hd, mesh_), mesh_)), + get(vpmap_, target(next(next(hd, mesh_), mesh_), mesh_))); - typedef GeomTraits GT; - Vector_3 rp = GT().construct_vector_3_object()(r, p); - Vector_3 rq = GT().construct_vector_3_object()(r, q); - Vector_3 r2p = GT().construct_vector_3_object()(r2, p); - Vector_3 r2q = GT().construct_vector_3_object()(r2, q); - - Vector_3 n1 = GT().construct_cross_product_vector_3_object()(rp, rq); - Vector_3 n2 = GT().construct_cross_product_vector_3_object()(r2q, r2p); - - return is_positive(GT().compute_scalar_product_3_object()(n1, n2)); + if (tr.is_degenerate()) + return CGAL::NULL_VECTOR; + else + return PMP::compute_face_normal(f, mesh_); } template @@ -1075,6 +1084,37 @@ namespace internal { std::cout << "done." << std::endl; } + void debug_self_intersections(const vertex_descriptor& v) const + { + std::cout << "Test self intersections..."; + std::vector > facets; + PMP::does_self_intersect( + faces_around_target(halfedge(v, mesh_), mesh_), + mesh_, + std::back_inserter(facets), + PMP::parameters::vertex_point_map(vpmap_)); + CGAL_assertion(facets.empty()); + std::cout << "done." << std::endl; + } + + void debug_normals(const vertex_descriptor& v) const + { + if (!is_on_patch(v)) + return;//not much to say if we are on a boundary/sharp edge + + std::vector normals; + BOOST_FOREACH(halfedge_descriptor hd, + halfedges_around_target(halfedge(v, mesh_), mesh_)) + { + Vector_3 n = compute_normal(face(hd, mesh_)); + if (n != CGAL::NULL_VECTOR) + normals.push_back(n); + } + //check all normals have same orientation + for (std::size_t i = 1; i < normals.size(); ++i)/*start at 1 on purpose*/ + CGAL_assertion(normals[i - 1] * normals[i] > 0.); + } + void debug_mesh_border() const { std::map mesh_border; From cfff71068d1d0db307b0a6fa277d07e42093f735 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Thu, 4 Jun 2015 11:34:27 +0200 Subject: [PATCH 072/217] add options and draft to the remeshing test --- .../remeshing_test.cpp | 67 +++++++++++++------ 1 file changed, 45 insertions(+), 22 deletions(-) diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp index fa5863d5579..faa8e3e9e09 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp @@ -1,5 +1,6 @@ -//#define CGAL_PMP_REMESHING_DEBUG +#define CGAL_PMP_REMESHING_DEBUG +#define CGAL_DUMP_REMESHING_STEPS #include #include @@ -7,6 +8,8 @@ #include #include +#include +#include #include #include @@ -74,7 +77,7 @@ std::set k_ring(vertex_descriptor v, } std::set collect_patch(const char* file, - const Mesh& m) + const Mesh& m) { std::set patch; std::ifstream in(file); @@ -95,7 +98,7 @@ std::set collect_patch(const char* file, std::istringstream facet_line(line); while (facet_line >> id) { if (id >= m.number_of_faces()) { return patch; } - patch.insert(Mesh::Face_index(id)); + patch.insert(Mesh::Face_index(Mesh::size_type(id))); } if (!std::getline(in, line)) { return patch; } @@ -109,11 +112,14 @@ std::set collect_patch(const char* file, return patch; } - int main(int argc, char* argv[]) { +#ifdef CGAL_PMP_REMESHING_DEBUG std::cout.precision(17); - const char* filename = (argc > 1) ? argv[1] : "data/U.off"; +#endif + + const char* filename = (argc > 1) ? argv[1] + : "data/joint_refined.off"; std::ifstream input(filename); Mesh m; @@ -122,8 +128,10 @@ int main(int argc, char* argv[]) return 1; } - double target_edge_length = (argc > 2) ? atof(argv[2]) : 0.01; - unsigned int nb_iter = (argc > 3) ? atoi(argv[3]) : 5; + double target_edge_length = (argc > 2) ? atof(argv[2]) + : 0.079; + unsigned int nb_iter = (argc > 3) ? atoi(argv[3]) + : 1; unsigned int center_id = 26; unsigned int i = 0; @@ -137,35 +145,50 @@ int main(int argc, char* argv[]) } } - const std::set& patch = + const char* selection_file = (argc > 4) ? argv[4] + : "data/joint-patch.selection.txt"; + const std::set& pre_patch = (argc > 4) - ? collect_patch(argv[4], m) + ? collect_patch(selection_file, m) : k_ring(patch_center, 3, m); - std::vector border; - PMP::get_border(m, patch, std::back_inserter(border)); - - CGAL::Polygon_mesh_processing::split_long_edges( - m, - border, - /*1.5 * */target_edge_length); + std::cout << "Test self intersections..."; + std::vector > facets; + PMP::self_intersections(pre_patch, + m, + std::back_inserter(facets)); + CGAL_assertion(facets.empty()); + std::cout << "done." << std::endl; + + //std::vector border; + //PMP::get_border(m, pre_patch, std::back_inserter(border)); + // + //PMP::split_long_edges(m, + // border, + // target_edge_length); + + + std::set patch; + std::copy(pre_patch.begin(), pre_patch.end(), + std::inserter(patch, patch.begin())); + + //PMP::connected_component(face(border.front(), m), + // m, + // std::inserter(patch, patch.begin())); CGAL::Timer t; t.start(); - CGAL::Polygon_mesh_processing::incremental_triangle_based_remeshing(m, + PMP::incremental_triangle_based_remeshing(m, patch, target_edge_length, - CGAL::Polygon_mesh_processing::parameters::number_of_iterations(nb_iter) - .protect_constraints(true) + PMP::parameters::number_of_iterations(nb_iter) + .protect_constraints(false) ); t.stop(); std::cout << "Remeshing took " << t.time() << std::endl; - //boost::property_map::const_type vpmap - // = boost::get(CGAL::vertex_point, m); - std::ofstream out("remeshed.off"); out << m; out.close(); From 2dd3ae2407fff8e23bbf105451b57738e11c721c Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Thu, 4 Jun 2015 12:11:06 +0200 Subject: [PATCH 073/217] fix remeshing of a patch WITH protection of constrained edges --- .../internal/remesh_impl.h | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 8d75a07bb0a..5e7404bf31e 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -244,7 +244,7 @@ namespace internal { double sqlen = eit->first; long_edges.right.erase(eit); - if (protect_constraints_ && !is_split_allowed(edge(he, mesh_))) + if (protect_constraints_ && !is_longest_on_faces(edge(he, mesh_))) continue; //split edge @@ -360,8 +360,6 @@ namespace internal { double sqlen = eit->first; short_edges.right.erase(eit); - CGAL_assertion(is_valid(he, mesh_)); - //handle the boundary case : //a PATCH_BORDER edge can be collapsed, //and an edge incident to PATCH_BORDER can be collapsed, @@ -712,7 +710,7 @@ namespace internal { void dump(const char* filename) const { std::ofstream out(filename); - out << mesh_; +// out << mesh_; out.close(); } @@ -755,6 +753,21 @@ namespace internal { && (plane1.oriented_side(p4) != plane2.oriented_side(p4)); } + bool is_longest_on_faces(const edge_descriptor& e) const + { + halfedge_descriptor h = halfedge(e, mesh_); + halfedge_descriptor hopp = opposite(h, mesh_); + + //check whether h is the longest edge in its associated face + //overwise refinement will go for an endless loop + double sqh = sqlength(h); + return sqh >= sqlength(next(h, mesh_)) + && sqh >= sqlength(next(next(h, mesh_), mesh_)) + //do the same for hopp + && sqh >= sqlength(next(hopp, mesh_)) + && sqh >= sqlength(next(next(hopp, mesh_), mesh_)); + } + bool is_split_allowed(const edge_descriptor& e) const { halfedge_descriptor h = halfedge(e, mesh_); @@ -762,19 +775,7 @@ namespace internal { if (protect_constraints_) { - if (!is_on_patch(h)) //PATCH are the only splittable edges - return false; - else //h and hopp are PATCH - { - //check whether h is the longest edge in its associated face - //overwise refinement will go for an endless loop - double sqh = sqlength(h); - return sqh >= sqlength(next(h, mesh_)) - && sqh >= sqlength(next(next(h, mesh_), mesh_)) - //do the same for hopp - && sqh >= sqlength(next(hopp, mesh_)) - && sqh >= sqlength(next(next(hopp, mesh_), mesh_)); - } + return is_on_patch(h); //PATCH are the only splittable edges } else //allow splitting constraints { From 4f58f5182e4d33f4d3fdac44bf98b35ea13c933e Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Thu, 4 Jun 2015 16:31:04 +0200 Subject: [PATCH 074/217] add debug code and fix constness --- .../internal/remesh_impl.h | 37 ++++++++++++++----- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 5e7404bf31e..6900d48a76f 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -65,11 +65,18 @@ namespace internal { BOOST_FOREACH(halfedge_descriptor h, border) border_edges[edge(h, pmesh_)] = true; } - friend bool get(Border_constraint_pmap map, - edge_descriptor e) + + friend bool get(const Border_constraint_pmap& map, + const edge_descriptor& e) { - return map.border_edges[e]; + CGAL_assertion(!map.border_edges.empty()); + typename std::map::const_iterator it + = map.border_edges.find(e); + + CGAL_assertion(it != map.border_edges.end()); + return it->second; } + }; template VNormalsMap; @@ -627,7 +644,6 @@ namespace internal { } // compute moves - //todo : iterate on barycenters instead. Would avoid retesting is_on_patch typedef typename std::map::value_type VP_pair; std::map new_locations; BOOST_FOREACH(const VP_pair& vp, barycenters) @@ -663,6 +679,7 @@ namespace internal { { //todo : handle the case of boundary vertices std::cout << "Project to surface..."; + std::cout.flush(); BOOST_FOREACH(vertex_descriptor v, vertices(mesh_)) { From 6e7f4f7b21d3dd19815b47270be7b4e95d85e9ff Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Thu, 4 Jun 2015 16:40:12 +0200 Subject: [PATCH 075/217] test code --- .../Polygon_mesh_processing/remeshing_test.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp index faa8e3e9e09..6fb9ea56eac 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp @@ -1,5 +1,5 @@ -#define CGAL_PMP_REMESHING_DEBUG +//#define CGAL_PMP_REMESHING_DEBUG #define CGAL_DUMP_REMESHING_STEPS #include @@ -157,8 +157,13 @@ int main(int argc, char* argv[]) PMP::self_intersections(pre_patch, m, std::back_inserter(facets)); - CGAL_assertion(facets.empty()); - std::cout << "done." << std::endl; + if(!facets.empty()) + { + std::cout << "Input is self intersecting. STOP" << std::endl; + return 0; + } + else + std::cout << "OK." << std::endl; //std::vector border; //PMP::get_border(m, pre_patch, std::back_inserter(border)); @@ -176,6 +181,9 @@ int main(int argc, char* argv[]) // m, // std::inserter(patch, patch.begin())); + std::cout << "Start remeshing of " << selection_file + << " (" << patch.size() << " faces)..." << std::endl; + CGAL::Timer t; t.start(); From 07820b8e0dd6f1c8bf0acd6fc3fca41f264c7c8e Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Thu, 4 Jun 2015 16:43:49 +0200 Subject: [PATCH 076/217] remove dump --- .../CGAL/Polygon_mesh_processing/internal/remesh_impl.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 6900d48a76f..d67551a8a7c 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -581,9 +581,6 @@ namespace internal { } } - std::setprecision(17); - dump("after-edge-flips.off"); - PMP::remove_degenerate_faces(mesh_ , PMP::parameters::vertex_point_map(vpmap_) .geom_traits(GeomTraits())); From df1985d296fdd715ee4c8c3d506fdd75d774397b Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Sat, 6 Jun 2015 12:31:30 +0200 Subject: [PATCH 077/217] use named parameters --- .../CGAL/Polygon_mesh_processing/internal/remesh_impl.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index d67551a8a7c..cae13d6ac0c 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -472,7 +472,9 @@ namespace internal { #ifdef CGAL_PMP_REMESHING_DEBUG debug_normals(vkept); - //PMP::remove_degenerate_faces(mesh_/*todo : add named parameters*/); + //PMP::remove_degenerate_faces(mesh_ + // , PMP::parameters::vertex_point_map(vpmap_) + // .geom_traits(GeomTraits())); //debug_self_intersections(vkept); #endif @@ -501,7 +503,9 @@ namespace internal { }//end if(collapse_ok) } - PMP::remove_degenerate_faces(mesh_/*todo : add named parameters*/); + PMP::remove_degenerate_faces(mesh_ + , PMP::parameters::vertex_point_map(vpmap_) + .geom_traits(GeomTraits())); std::cout << " done (" << nb_collapses << " collapses)." << std::endl; From 4e95d9cc05a126b76c02ee3381e58521f1c01910 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Sat, 6 Jun 2015 12:34:37 +0200 Subject: [PATCH 078/217] check that flip does not create a non-triangle face this can happen around sharp tips of the domain, when no incident edge is selected for protection --- .../internal/remesh_impl.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index cae13d6ac0c..c073769f59a 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -742,6 +742,11 @@ namespace internal { return (is_border(v, mesh_)) ? 4 : 6; } + bool is_on_triangle(const halfedge_descriptor& h) const + { + return h == next(next(next(h, mesh_), mesh_), mesh_); + } + bool is_flip_allowed(const edge_descriptor& e) const { //only the patch, and non-border edges are @@ -750,6 +755,16 @@ namespace internal { if (!is_on_patch(he)) return false; + //check that mesh does not become non-triangle + CGAL::Euler::flip_edge(he, mesh_); + if (!is_on_triangle(he) || !is_on_triangle(opposite(he, mesh_))) + { + CGAL::Euler::flip_edge(he, mesh_); + return false; + } + CGAL::Euler::flip_edge(he, mesh_); + + //check that we don't inverse a face Point p1 = get(vpmap_, target(he, mesh_)); Point p2 = get(vpmap_, source(he, mesh_)); Vector_3 normal(p1, p2); From dea8a59dbb087abc0634f9f3644546454e638ce9 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Sat, 6 Jun 2015 13:27:24 +0200 Subject: [PATCH 079/217] make flip_allowed test simpler, and reorganize flipping step to save useless operations --- .../internal/remesh_impl.h | 64 ++++++------------- 1 file changed, 20 insertions(+), 44 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index c073769f59a..16ea9c9a449 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -535,10 +535,11 @@ namespace internal { unsigned int nb_flips = 0; BOOST_FOREACH(edge_descriptor e, edges(mesh_)) { - if (!is_flip_allowed(e)) + //only the patch edges are allowed to be flipped + halfedge_descriptor he = halfedge(e, mesh_); + if (!is_on_patch(he)) continue; - halfedge_descriptor he = halfedge(e, mesh_); vertex_descriptor va = source(he, mesh_); vertex_descriptor vb = target(he, mesh_); vertex_descriptor vc = target(next(he, mesh_), mesh_); @@ -571,7 +572,13 @@ namespace internal { + CGAL::abs(valence(vc) - target_valence(vc)) + CGAL::abs(valence(vd) - target_valence(vd)); - if (deviation_pre < deviation_post) + //check that mesh does not become non-triangle, + //nor has inverted faces + if (deviation_pre < deviation_post + || !is_on_triangle(he) + || !is_on_triangle(opposite(he, mesh_)) + || !check_normals(target(he, mesh_)) + || !check_normals(source(he, mesh_))) { CGAL::Euler::flip_edge(he, mesh_); --nb_flips; @@ -747,45 +754,6 @@ namespace internal { return h == next(next(next(h, mesh_), mesh_), mesh_); } - bool is_flip_allowed(const edge_descriptor& e) const - { - //only the patch, and non-border edges are - //allowed to be flipped - halfedge_descriptor he = halfedge(e, mesh_); - if (!is_on_patch(he)) - return false; - - //check that mesh does not become non-triangle - CGAL::Euler::flip_edge(he, mesh_); - if (!is_on_triangle(he) || !is_on_triangle(opposite(he, mesh_))) - { - CGAL::Euler::flip_edge(he, mesh_); - return false; - } - CGAL::Euler::flip_edge(he, mesh_); - - //check that we don't inverse a face - Point p1 = get(vpmap_, target(he, mesh_)); - Point p2 = get(vpmap_, source(he, mesh_)); - Vector_3 normal(p1, p2); - - //construct planes passing through p1 and p2, - // and orthogonal to e - Plane_3 plane1(p1, normal); - Plane_3 plane2(p2, normal); - - CGAL_assertion(//check orientation is consistent - plane1.orthogonal_vector() * plane2.orthogonal_vector() > 0.); - - //get third points of triangles shared by e - Point p3 = get(vpmap_, target(next(he, mesh_), mesh_)); - Point p4 = get(vpmap_, target(next(opposite(he, mesh_), mesh_), mesh_)); - - //check whether p3 and p4 are between plane1 and plane2 - return (plane1.oriented_side(p3) != plane2.oriented_side(p3)) - && (plane1.oriented_side(p4) != plane2.oriented_side(p4)); - } - bool is_longest_on_faces(const edge_descriptor& e) const { halfedge_descriptor h = halfedge(e, mesh_); @@ -1132,9 +1100,14 @@ namespace internal { } void debug_normals(const vertex_descriptor& v) const + { + CGAL_assertion(check_normals(v)); + } + + bool check_normals(const vertex_descriptor& v) const { if (!is_on_patch(v)) - return;//not much to say if we are on a boundary/sharp edge + return true;//not much to say if we are on a boundary/sharp edge std::vector normals; BOOST_FOREACH(halfedge_descriptor hd, @@ -1146,7 +1119,10 @@ namespace internal { } //check all normals have same orientation for (std::size_t i = 1; i < normals.size(); ++i)/*start at 1 on purpose*/ - CGAL_assertion(normals[i - 1] * normals[i] > 0.); + if (normals[i - 1] * normals[i] <= 0.) + return false; + + return true; } void debug_mesh_border() const From 99e0a245a0e6a88adac79a65c728935068994ab6 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Sat, 6 Jun 2015 14:27:15 +0200 Subject: [PATCH 080/217] add macro for verbose mode --- .../internal/remesh_impl.h | 25 +++++++++++++++++++ ...hedron_demo_isotropic_remeshing_plugin.cpp | 2 ++ 2 files changed, 27 insertions(+) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 16ea9c9a449..da84831d528 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -154,7 +154,10 @@ namespace internal { boost::bimaps::multiset_of > > Boost_bimap; typedef typename Boost_bimap::value_type long_edge; +#ifdef CGAL_PMP_REMESHING_VERBOSE std::cout << "Split long edges (" << high << ")..."; + std::cout.flush(); +#endif double sq_high = high*high; //collect long edges @@ -210,7 +213,9 @@ namespace internal { = CGAL::Euler::split_face(prev(hnew_opp, mesh_), next(hnew_opp, mesh_), mesh_); } } +#ifdef CGAL_PMP_REMESHING_VERBOSE std::cout << " done (" << nb_splits << " splits)." << std::endl; +#endif #ifdef CGAL_DUMP_REMESHING_STEPS dump("0-border_split.off"); #endif @@ -227,8 +232,10 @@ namespace internal { boost::bimaps::multiset_of > > Boost_bimap; typedef typename Boost_bimap::value_type long_edge; +#ifdef CGAL_PMP_REMESHING_VERBOSE std::cout << "Split long edges (" << high << ")..."; std::cout.flush(); +#endif double sq_high = high*high; //collect long edges @@ -319,7 +326,9 @@ namespace internal { } } } +#ifdef CGAL_PMP_REMESHING_VERBOSE std::cout << " done ("<< nb_splits << " splits)." << std::endl; +#endif #ifdef CGAL_PMP_REMESHING_DEBUG CGAL_expensive_assertion(is_triangle_mesh(mesh_)); @@ -345,8 +354,10 @@ namespace internal { boost::bimaps::multiset_of > > Boost_bimap; typedef typename Boost_bimap::value_type short_edge; +#ifdef CGAL_PMP_REMESHING_VERBOSE std::cout << "Collapse short edges (" << low << ", " << high << ")..."; std::cout.flush(); +#endif double sq_low = low*low; double sq_high = high*high; @@ -507,7 +518,9 @@ namespace internal { , PMP::parameters::vertex_point_map(vpmap_) .geom_traits(GeomTraits())); +#ifdef CGAL_PMP_REMESHING_VERBOSE std::cout << " done (" << nb_collapses << " collapses)." << std::endl; +#endif #ifdef CGAL_DUMP_REMESHING_STEPS dump("2-edge_collapse.off"); @@ -530,8 +543,10 @@ namespace internal { // to the target valences decreases. If not, the edge is flipped back" void equalize_valences() { +#ifdef CGAL_PMP_REMESHING_VERBOSE std::cout << "Equalize valences..."; std::cout.flush(); +#endif unsigned int nb_flips = 0; BOOST_FOREACH(edge_descriptor e, edges(mesh_)) { @@ -596,7 +611,9 @@ namespace internal { , PMP::parameters::vertex_point_map(vpmap_) .geom_traits(GeomTraits())); +#ifdef CGAL_PMP_REMESHING_VERBOSE std::cout << "done. ("<< nb_flips << " flips)" << std::endl; +#endif #ifdef CGAL_PMP_REMESHING_DEBUG CGAL_assertion(nb_valid_halfedges() == halfedge_status_map_.size()); @@ -615,8 +632,10 @@ namespace internal { void tangential_relaxation() { //todo : move border vertices along 1-dimensional features +#ifdef CGAL_PMP_REMESHING_VERBOSE std::cout << "Tangential relaxation..."; std::cout.flush(); +#endif //todo : use boost::vector_property_map to improve computing time typedef std::map VNormalsMap; @@ -673,7 +692,9 @@ namespace internal { CGAL_assertion(is_valid(mesh_)); CGAL_assertion(is_triangle_mesh(mesh_)); +#ifdef CGAL_PMP_REMESHING_VERBOSE std::cout << "done." << std::endl; +#endif #ifdef CGAL_DUMP_REMESHING_STEPS dump("4-relaxation.off"); @@ -686,8 +707,10 @@ namespace internal { void project_to_surface() { //todo : handle the case of boundary vertices +#ifdef CGAL_PMP_REMESHING_VERBOSE std::cout << "Project to surface..."; std::cout.flush(); +#endif BOOST_FOREACH(vertex_descriptor v, vertices(mesh_)) { @@ -699,7 +722,9 @@ namespace internal { CGAL_assertion(is_valid(mesh_)); CGAL_assertion(is_triangle_mesh(mesh_)); +#ifdef CGAL_PMP_REMESHING_VERBOSE std::cout << "done." << std::endl; +#endif #ifdef CGAL_DUMP_REMESHING_STEPS dump("5-project.off"); diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp index bf1f0aad970..4173840fa15 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp @@ -23,6 +23,8 @@ #include "ui_Polyhedron_demo_isotropic_remeshing_dialog.h" +#define CGAL_PMP_REMESHING_VERBOSE + class Polyhedron_demo_isotropic_remeshing_plugin : public QObject, public Polyhedron_demo_plugin_helper From 7da4b81a190ebad812df1a78922b760c6528b9ef Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Sat, 6 Jun 2015 14:40:47 +0200 Subject: [PATCH 081/217] add very verbose mode --- .../Polygon_mesh_processing/internal/remesh_impl.h | 13 +++++++++++++ .../Polyhedron_demo_isotropic_remeshing_plugin.cpp | 5 +++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index da84831d528..0aa9b0965e3 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -29,6 +29,11 @@ #include #endif +#ifdef CGAL_PMP_REMESHING_VERY_VERBOSE +#define CGAL_PMP_REMESHING_VERBOSE +#endif + + namespace PMP = CGAL::Polygon_mesh_processing; @@ -188,6 +193,11 @@ namespace internal { //move refinement point vertex_descriptor vnew = target(hnew, mesh_); put(vpmap_, vnew, refinement_point); +#ifdef CGAL_PMP_REMESHING_VERY_VERBOSE + std::cout << " * status(hnew) : " << status(hnew) << std::endl; + std::cout << " status(hnew_opp) : " << status(opposite(hnew, mesh_)) << std::endl; + std::cout << " refinement point : " << refinement_point << std::endl; +#endif //check sub-edges double sqlen_new = 0.25 * sqlen; @@ -271,6 +281,9 @@ namespace internal { //move refinement point vertex_descriptor vnew = target(hnew, mesh_); put(vpmap_, vnew, refinement_point); +#ifdef CGAL_PMP_REMESHING_VERY_VERBOSE + std::cout << " Refinement point : " << refinement_point << std::endl; +#endif //after splitting halfedge_descriptor hnew_opp = opposite(hnew, mesh_); diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp index 4173840fa15..5c415ebd306 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp @@ -1,3 +1,6 @@ +#define CGAL_PMP_REMESHING_VERBOSE +#define CGAL_PMP_REMESHING_VERY_VERBOSE + #include #include "Scene_polyhedron_item.h" @@ -23,8 +26,6 @@ #include "ui_Polyhedron_demo_isotropic_remeshing_dialog.h" -#define CGAL_PMP_REMESHING_VERBOSE - class Polyhedron_demo_isotropic_remeshing_plugin : public QObject, public Polyhedron_demo_plugin_helper From 2c3c2e0c5857ca959d5ec52cc55dc5eec3302feb Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Sat, 6 Jun 2015 15:18:47 +0200 Subject: [PATCH 082/217] fix the use of selected facets with no selected edges --- ...hedron_demo_isotropic_remeshing_plugin.cpp | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp index 5c415ebd306..aa766c29da4 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp @@ -130,6 +130,7 @@ public Q_SLOTS: typedef boost::graph_traits::edge_descriptor edge_descriptor; typedef boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef boost::graph_traits::face_descriptor face_descriptor; if (selection_item) { if (edges_only) @@ -144,6 +145,15 @@ public Q_SLOTS: != selection_item->selected_facets.end()) edges.push_back(e); } + BOOST_FOREACH(face_descriptor f, selection_item->selected_facets) + { + BOOST_FOREACH(halfedge_descriptor he, halfedges_around_face(halfedge(f, pmesh), pmesh)) + { + if (selection_item->selected_facets.find(face(opposite(he, pmesh), pmesh)) + == selection_item->selected_facets.end()) + edges.push_back(edge(he, pmesh)); + } + } CGAL::Polygon_mesh_processing::split_long_edges( *selection_item->polyhedron() , edges @@ -155,13 +165,23 @@ public Q_SLOTS: selection_item->polyhedron()->size_of_halfedges()/2, false); + if (selection_item->selected_edges.empty()) + CGAL::Polygon_mesh_processing::incremental_triangle_based_remeshing( + *selection_item->polyhedron() + , selection_item->selected_facets + , target_length + , CGAL::Polygon_mesh_processing::parameters::number_of_iterations(nb_iter) + .protect_constraints(protect)); + else CGAL::Polygon_mesh_processing::incremental_triangle_based_remeshing( *selection_item->polyhedron() , selection_item->selected_facets , target_length , CGAL::Polygon_mesh_processing::parameters::number_of_iterations(nb_iter) + .protect_constraints(protect) .edge_is_constrained_map(selection_item->selected_edges_pmap(selected)) - .protect_constraints(protect)); + ); + } selection_item->poly_item_changed(); selection_item->clear_all(); From e3121567fa15ccb9f16ce8a0cc9ad6b59b67ea6e Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Sat, 6 Jun 2015 16:38:05 +0200 Subject: [PATCH 083/217] automatically re-select border of selection after refining only border --- .../internal/remesh_impl.h | 17 ++++++++--- .../CGAL/Polygon_mesh_processing/remesh.h | 29 ++++++++++++++++++- ...hedron_demo_isotropic_remeshing_plugin.cpp | 7 ++++- 3 files changed, 47 insertions(+), 6 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 0aa9b0965e3..f79b63182e5 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -150,9 +151,10 @@ namespace internal { } // split edges of edge_range that have their length > high - template + template void split_long_edges(const EdgeRange& edge_range, - const double& high) + const double& high, + OutputIterator out)//new edges, replacing edge_range { typedef boost::bimap< boost::bimaps::set_of, @@ -172,6 +174,8 @@ namespace internal { double sqlen = sqlength(e); if (sqlen > sq_high) long_edges.insert(long_edge(halfedge(e, mesh_), sqlen)); + else + *out++ = e; } //split long edges @@ -194,8 +198,6 @@ namespace internal { vertex_descriptor vnew = target(hnew, mesh_); put(vpmap_, vnew, refinement_point); #ifdef CGAL_PMP_REMESHING_VERY_VERBOSE - std::cout << " * status(hnew) : " << status(hnew) << std::endl; - std::cout << " status(hnew_opp) : " << status(opposite(hnew, mesh_)) << std::endl; std::cout << " refinement point : " << refinement_point << std::endl; #endif @@ -207,6 +209,11 @@ namespace internal { long_edges.insert(long_edge(hnew, sqlen_new)); long_edges.insert(long_edge(next(hnew, mesh_), sqlen_new)); } + else + { + *out++ = edge(hnew, mesh_); + *out++ = edge(next(hnew, mesh_), mesh_); + } //insert new edges to keep triangular faces, and update long_edges if (!is_border(hnew, mesh_)) @@ -951,6 +958,8 @@ namespace internal { { typename std::map < halfedge_descriptor, Halfedge_status >::const_iterator it = halfedge_status_map_.find(h); + if (it == halfedge_status_map_.end()) + std::cout << "stop" << std::endl; CGAL_assertion(it != halfedge_status_map_.end()); return it->second; } diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h index fb054794d7b..22d240e6c31 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h @@ -163,7 +163,7 @@ void split_long_edges(PolygonMesh& pmesh typename internal::Incremental_remesher remesher(pmesh, vpmap, false/*protect constraints*/); - remesher.split_long_edges(edge_range, max_length); + remesher.split_long_edges(edge_range, max_length, Emptyset_iterator()); } template @@ -177,6 +177,33 @@ void split_long_edges(PolygonMesh& pmesh parameters::all_default()); } +//used in the Polyhedron demo +template +void split_long_edges(PolygonMesh& pmesh + , EdgeRange& edge_range + , const double& max_length + , OutputIterator out//edges after splitting, all shorter than target_length + , const NamedParameters& np) +{ + typedef PolygonMesh PM; + using boost::choose_pmap; + using boost::get_param; + + typedef typename GetGeomTraits::type GT; + typedef typename GetVertexPointMap::type VPMap; + VPMap vpmap = choose_pmap(get_param(np, boost::vertex_point), + pmesh, + boost::vertex_point); + + typename internal::Incremental_remesher + remesher(pmesh, vpmap, false/*protect constraints*/); + + remesher.split_long_edges(edge_range, max_length, out); +} + } //end namespace Polygon_mesh_processing } //end namespace CGAL diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp index aa766c29da4..f0c3036cf86 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp @@ -133,6 +133,7 @@ public Q_SLOTS: typedef boost::graph_traits::face_descriptor face_descriptor; if (selection_item) { + std::vector updated_selected_edges; if (edges_only) { const Polyhedron& pmesh = *selection_item->polyhedron(); @@ -157,7 +158,9 @@ public Q_SLOTS: CGAL::Polygon_mesh_processing::split_long_edges( *selection_item->polyhedron() , edges - , target_length); + , target_length + , std::back_inserter(updated_selected_edges) + , PMP::parameters::geom_traits(Kernel())); } else { @@ -185,6 +188,8 @@ public Q_SLOTS: } selection_item->poly_item_changed(); selection_item->clear_all(); + selection_item->selected_edges.insert(updated_selected_edges.begin(), + updated_selected_edges.end()); selection_item->changed_with_poly_item(); } else if (poly_item) From 4f5be714bbdcba64a02f1a342771fa06a5df588b Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Sat, 6 Jun 2015 17:27:29 +0200 Subject: [PATCH 084/217] add warning code --- .../Polygon_mesh_processing/internal/remesh_impl.h | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index f79b63182e5..fa7d46006d6 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -534,9 +534,11 @@ namespace internal { }//end if(collapse_ok) } - PMP::remove_degenerate_faces(mesh_ + std::size_t n = PMP::remove_degenerate_faces(mesh_ , PMP::parameters::vertex_point_map(vpmap_) - .geom_traits(GeomTraits())); + .geom_traits(GeomTraits())); + if (n > 0) + std::cout << "Warning : tags should maybe be fixed" << std::endl; #ifdef CGAL_PMP_REMESHING_VERBOSE std::cout << " done (" << nb_collapses << " collapses)." << std::endl; @@ -627,9 +629,11 @@ namespace internal { } } - PMP::remove_degenerate_faces(mesh_ + std::size_t n = PMP::remove_degenerate_faces(mesh_ , PMP::parameters::vertex_point_map(vpmap_) - .geom_traits(GeomTraits())); + .geom_traits(GeomTraits())); + if (n > 0) + std::cout << "Warning : tags should maybe be fixed" << std::endl; #ifdef CGAL_PMP_REMESHING_VERBOSE std::cout << "done. ("<< nb_flips << " flips)" << std::endl; @@ -959,7 +963,7 @@ namespace internal { typename std::map < halfedge_descriptor, Halfedge_status >::const_iterator it = halfedge_status_map_.find(h); if (it == halfedge_status_map_.end()) - std::cout << "stop" << std::endl; + std::cout << "stop " << std::endl; CGAL_assertion(it != halfedge_status_map_.end()); return it->second; } From 6214feaaf13309abe633d457c8a3c8cec2e57d72 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Mon, 8 Jun 2015 14:19:07 +0200 Subject: [PATCH 085/217] add stuff for verbose mode --- .../internal/remesh_impl.h | 73 +++++++------------ .../remeshing_test.cpp | 20 ++--- 2 files changed, 36 insertions(+), 57 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index fa7d46006d6..cb7b5b50048 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -250,8 +250,7 @@ namespace internal { typedef typename Boost_bimap::value_type long_edge; #ifdef CGAL_PMP_REMESHING_VERBOSE - std::cout << "Split long edges (" << high << ")..."; - std::cout.flush(); + std::cout << "Split long edges (" << high << ")..." << std::endl; #endif double sq_high = high*high; @@ -276,6 +275,12 @@ namespace internal { double sqlen = eit->first; long_edges.right.erase(eit); +#ifdef CGAL_PMP_REMESHING_VERBOSE + std::cout << "\r\t(" << long_edges.left.size() << " long edges, "; + std::cout << nb_splits << " splits)"; + std::cout.flush(); +#endif + if (protect_constraints_ && !is_longest_on_faces(edge(he, mesh_))) continue; @@ -354,7 +359,6 @@ namespace internal { CGAL_expensive_assertion(is_triangle_mesh(mesh_)); CGAL_assertion(halfedge_status_map_.size() == nb_valid_halfedges()); debug_status_map(); - debug_patch_border(); debug_mesh_border(); #endif @@ -375,8 +379,8 @@ namespace internal { typedef typename Boost_bimap::value_type short_edge; #ifdef CGAL_PMP_REMESHING_VERBOSE - std::cout << "Collapse short edges (" << low << ", " << high << ")..."; - std::cout.flush(); + std::cout << "Collapse short edges (" << low << ", " << high << ")..." + << std::endl; #endif double sq_low = low*low; double sq_high = high*high; @@ -400,6 +404,12 @@ namespace internal { double sqlen = eit->first; short_edges.right.erase(eit); +#ifdef CGAL_PMP_REMESHING_VERBOSE + std::cout << "\r\t(" << short_edges.left.size() << " short edges, "; + std::cout << nb_collapses << " collapses)"; + std::cout.flush(); +#endif + //handle the boundary case : //a PATCH_BORDER edge can be collapsed, //and an edge incident to PATCH_BORDER can be collapsed, @@ -501,14 +511,6 @@ namespace internal { put(vpmap_, vkept, target_point); ++nb_collapses; -#ifdef CGAL_PMP_REMESHING_DEBUG - debug_normals(vkept); - //PMP::remove_degenerate_faces(mesh_ - // , PMP::parameters::vertex_point_map(vpmap_) - // .geom_traits(GeomTraits())); - //debug_self_intersections(vkept); -#endif - // merge halfedge_status to keep the more important on both sides merge_status(en, s_epo, s_ep); if (!mesh_border_case) @@ -519,7 +521,6 @@ namespace internal { CGAL_assertion(nbb == halfedge_status_map_.size()); CGAL_assertion(source(en, mesh_) == source(en_p, mesh_)); debug_status_map(); - debug_patch_border(); #endif //insert new/remaining short edges @@ -538,8 +539,15 @@ namespace internal { , PMP::parameters::vertex_point_map(vpmap_) .geom_traits(GeomTraits())); if (n > 0) + { std::cout << "Warning : tags should maybe be fixed" << std::endl; - + unsigned int nbb = nb_valid_halfedges(); + CGAL_assertion(nbb == halfedge_status_map_.size()); + } +#ifdef CGAL_PMP_REMESHING_EXPENSIVE_DEBUG + BOOST_FOREACH(vertex_descriptor v, vertices(mesh_)) + debug_normals(v); +#endif #ifdef CGAL_PMP_REMESHING_VERBOSE std::cout << " done (" << nb_collapses << " collapses)." << std::endl; #endif @@ -552,7 +560,6 @@ namespace internal { CGAL_assertion(nb_valid_halfedges() == halfedge_status_map_.size()); CGAL_expensive_assertion(is_triangle_mesh(mesh_)); debug_status_map(); - debug_patch_border(); debug_mesh_border(); debug_self_intersections(); #endif @@ -952,10 +959,7 @@ namespace internal { } } -#ifdef CGAL_PMP_REMESHING_DEBUG CGAL_assertion(halfedge_status_map_.size() == nb_valid_halfedges()); - debug_patch_border(); -#endif } Halfedge_status status(const halfedge_descriptor& h) const @@ -1098,33 +1102,6 @@ namespace internal { } } - void debug_patch_border() const - { - std::map patch_border; - typedef typename std::map::value_type - HD_pair; - BOOST_FOREACH(const HD_pair& hs, halfedge_status_map_) - { - if (is_on_patch_border(hs.first)) - { - if (patch_border.find(target(hs.first, mesh_)) != patch_border.end()) - patch_border[target(hs.first, mesh_)]++; - else - patch_border[target(hs.first, mesh_)] = 1; - - if (patch_border.find(source(hs.first, mesh_)) != patch_border.end()) - patch_border[source(hs.first, mesh_)]++; - else - patch_border[source(hs.first, mesh_)] = 1; - } - } - //check we found each vertex exactly twice - typedef typename std::map::value_type - V_pair; - BOOST_FOREACH(const V_pair& v, patch_border) - CGAL_assertion(v.second == 2); - } - void debug_self_intersections() const { std::cout << "Test self intersections..."; @@ -1165,8 +1142,8 @@ namespace internal { halfedges_around_target(halfedge(v, mesh_), mesh_)) { Vector_3 n = compute_normal(face(hd, mesh_)); - if (n != CGAL::NULL_VECTOR) - normals.push_back(n); + normals.push_back(n); + CGAL_assertion(n != CGAL::NULL_VECTOR); } //check all normals have same orientation for (std::size_t i = 1; i < normals.size(); ++i)/*start at 1 on purpose*/ diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp index 6fb9ea56eac..4d6c8869e7b 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp @@ -1,6 +1,8 @@ -//#define CGAL_PMP_REMESHING_DEBUG +#define CGAL_PMP_REMESHING_DEBUG #define CGAL_DUMP_REMESHING_STEPS +#define CGAL_PMP_REMESHING_VERBOSE +#define CGAL_PMP_REMESHING_EXPENSIVE_DEBUG #include #include @@ -165,13 +167,13 @@ int main(int argc, char* argv[]) else std::cout << "OK." << std::endl; - //std::vector border; - //PMP::get_border(m, pre_patch, std::back_inserter(border)); - // - //PMP::split_long_edges(m, - // border, - // target_edge_length); - + std::cout << "Split border..."; + std::vector border; + PMP::get_border(m, pre_patch, std::back_inserter(border)); + PMP::split_long_edges(m, + border, + target_edge_length); + std::cout << "done." << std::endl; std::set patch; std::copy(pre_patch.begin(), pre_patch.end(), @@ -191,7 +193,7 @@ int main(int argc, char* argv[]) patch, target_edge_length, PMP::parameters::number_of_iterations(nb_iter) - .protect_constraints(false) + .protect_constraints(true) ); t.stop(); From 237c20321fd92998b659fa5bb2a01ff219860b40 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Mon, 8 Jun 2015 16:12:34 +0200 Subject: [PATCH 086/217] deal with degenerate faces better --- .../internal/remesh_impl.h | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index cb7b5b50048..7eea0cbe47e 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -877,16 +877,22 @@ namespace internal { BOOST_FOREACH(halfedge_descriptor hd, halfedges_around_target(h, mesh_)) { + if (source(hd, mesh_) == vs + || target(next(hd, mesh_), mesh_) == vs) //degenerate face + continue; Vector_3 n = compute_normal(face(hd, mesh_)); - if (n != CGAL::NULL_VECTOR) - normals.push_back(n); + CGAL_assertion(n != CGAL::NULL_VECTOR); + normals.push_back(n); } BOOST_FOREACH(halfedge_descriptor hd, halfedges_around_target(opposite(h, mesh_), mesh_)) { + if (source(hd, mesh_) == vt + || target(next(hd, mesh_), mesh_) == vt) //degenerate face + continue; Vector_3 n = compute_normal(face(hd, mesh_)); - if (n != CGAL::NULL_VECTOR) - normals.push_back(n); + CGAL_assertion(n != CGAL::NULL_VECTOR); + normals.push_back(n); } //check all normals have same orientation @@ -1129,14 +1135,14 @@ namespace internal { void debug_normals(const vertex_descriptor& v) const { + if (!is_on_patch(v)) + return;//not much to say if we are on a boundary/sharp edge CGAL_assertion(check_normals(v)); } bool check_normals(const vertex_descriptor& v) const { - if (!is_on_patch(v)) - return true;//not much to say if we are on a boundary/sharp edge - + //assume we are on a patch without checking it std::vector normals; BOOST_FOREACH(halfedge_descriptor hd, halfedges_around_target(halfedge(v, mesh_), mesh_)) @@ -1147,9 +1153,11 @@ namespace internal { } //check all normals have same orientation for (std::size_t i = 1; i < normals.size(); ++i)/*start at 1 on purpose*/ - if (normals[i - 1] * normals[i] <= 0.) + { + double dot = normals[i - 1] * normals[i]; + if(dot <= 0.) return false; - + } return true; } From f8eb659abd9100247d5274ba2f88194993d1c4cf Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Mon, 8 Jun 2015 16:17:53 +0200 Subject: [PATCH 087/217] remove debug_mesh_border since it has become wrong when we have 2 adjacent patches with a constrained polyline separating them the same vertex can appear more than twice --- .../internal/remesh_impl.h | 29 ------------------- 1 file changed, 29 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 7eea0cbe47e..2032395c5b8 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -359,7 +359,6 @@ namespace internal { CGAL_expensive_assertion(is_triangle_mesh(mesh_)); CGAL_assertion(halfedge_status_map_.size() == nb_valid_halfedges()); debug_status_map(); - debug_mesh_border(); #endif #ifdef CGAL_DUMP_REMESHING_STEPS @@ -560,7 +559,6 @@ namespace internal { CGAL_assertion(nb_valid_halfedges() == halfedge_status_map_.size()); CGAL_expensive_assertion(is_triangle_mesh(mesh_)); debug_status_map(); - debug_mesh_border(); debug_self_intersections(); #endif } @@ -1161,33 +1159,6 @@ namespace internal { return true; } - void debug_mesh_border() const - { - std::map mesh_border; - typedef typename std::map::value_type - HD_pair; - BOOST_FOREACH(const HD_pair& hs, halfedge_status_map_) - { - if (is_on_border(hs.first)) - { - if (mesh_border.find(target(hs.first, mesh_)) != mesh_border.end()) - mesh_border[target(hs.first, mesh_)]++; - else - mesh_border[target(hs.first, mesh_)] = 1; - - if (mesh_border.find(source(hs.first, mesh_)) != mesh_border.end()) - mesh_border[source(hs.first, mesh_)]++; - else - mesh_border[source(hs.first, mesh_)] = 1; - } - } - //check we found each vertex exactly twice - typedef typename std::map::value_type - V_pair; - BOOST_FOREACH(const V_pair& v, mesh_border) - CGAL_assertion(v.second == 2); - } - private: PolygonMesh& mesh_; VertexPointMap& vpmap_; From ef124155fe38b31cd773e55ba58ccf48f1afd5fd Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Mon, 8 Jun 2015 16:18:54 +0200 Subject: [PATCH 088/217] macros --- .../Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp index f0c3036cf86..f53ffb0e23b 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp @@ -1,5 +1,6 @@ #define CGAL_PMP_REMESHING_VERBOSE -#define CGAL_PMP_REMESHING_VERY_VERBOSE +//#define CGAL_PMP_REMESHING_DEBUG +//#define CGAL_PMP_REMESHING_VERY_VERBOSE #include From 4ba9dbd71b68ac2fe4461964f869eb5cba88ec1f Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Thu, 11 Jun 2015 15:06:41 +0200 Subject: [PATCH 089/217] fix constness --- BGL/include/CGAL/boost/graph/graph_traits_Surface_mesh.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BGL/include/CGAL/boost/graph/graph_traits_Surface_mesh.h b/BGL/include/CGAL/boost/graph/graph_traits_Surface_mesh.h index 101d30fae9d..4022c520239 100644 --- a/BGL/include/CGAL/boost/graph/graph_traits_Surface_mesh.h +++ b/BGL/include/CGAL/boost/graph/graph_traits_Surface_mesh.h @@ -522,7 +522,7 @@ add_face(InputIterator begin, InputIterator end, CGAL::Surface_mesh

& sm) } template -bool is_valid(CGAL::Surface_mesh

& sm, bool verbose = false) +bool is_valid(const CGAL::Surface_mesh

& sm, bool verbose = false) { return sm.is_valid(verbose); } From 4b7a997df00f129a864f33d9e54ccab1cd4a748c Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Thu, 11 Jun 2015 15:08:33 +0200 Subject: [PATCH 090/217] add the ability to use a Visitor for a BGL graph using an overload of graph_traits TODO : is_valid(mesh) does not compile on msvc. To be fixed --- BGL/include/CGAL/boost/graph/visitor.h | 648 ++++++++++++++++++ .../internal/remesh_impl.h | 33 +- 2 files changed, 678 insertions(+), 3 deletions(-) create mode 100644 BGL/include/CGAL/boost/graph/visitor.h diff --git a/BGL/include/CGAL/boost/graph/visitor.h b/BGL/include/CGAL/boost/graph/visitor.h new file mode 100644 index 00000000000..b00f7a5a425 --- /dev/null +++ b/BGL/include/CGAL/boost/graph/visitor.h @@ -0,0 +1,648 @@ +#ifndef CGAL_BOOST_GRAPH_VISITOR_H +#define CGAL_BOOST_GRAPH_VISITOR_H + +#include +#include +#include + +namespace boost +{ + template + struct boost::graph_traits< + boost::tuple, boost::reference_wrapper > > + : boost::graph_traits< Graph > + { + typedef boost::graph_traits Base; + typedef typename Base::vertex_property_type vertex_property_type; + }; + + template + struct boost::graph_traits< + boost::tuple, boost::reference_wrapper > const > + : boost::graph_traits< Graph > + {}; + + template + struct property_map< + boost::tuple, boost::reference_wrapper >, + PropertyTag> + : public property_map + {}; + + template + struct property_map< + const boost::tuple, boost::reference_wrapper >, + PropertyTag> + : public property_map + {}; + +} // namespace boost + +namespace CGAL +{ +template +boost::tuple, + boost::reference_wrapper > +make_graph_with_visitor(V& v, Graph& g) +{ + return boost::make_tuple(boost::ref(v), boost::ref(g)); +} + +template +class Visitor_base +{ +public: + typedef typename boost::graph_traits gt; + typedef typename gt::halfedge_descriptor halfedge_descriptor; + typedef typename gt::edge_descriptor edge_descriptor; + typedef typename gt::vertex_descriptor vertex_descriptor; + + +}; + + +//// OVERLOADS FOR Visitor + +template +void num_vertices(Visitor_base& w) +{} +template +void num_edges(Visitor_base& w) +{} +template +void degree(typename boost::graph_traits::vertex_descriptor v + , const Visitor_base& w) +{} +template +void out_degree(typename boost::graph_traits::vertex_descriptor v + , const Visitor_base& w) +{} +template +void in_degree(typename boost::graph_traits::vertex_descriptor v + , const Visitor_base& w) +{} +template +void source(typename boost::graph_traits::edge_descriptor e + , const Visitor_base & w) +{} +template +void target(typename boost::graph_traits::edge_descriptor e + , const Visitor_base & w) +{} +template +void edge(typename boost::graph_traits::vertex_descriptor u + , typename boost::graph_traits::vertex_descriptor v + , const Visitor_base & w) +{} +template +inline void vertices(const Visitor_base & w) +{} +template +inline void edges(const Visitor_base & w) +{} +template +inline void in_edges(typename boost::graph_traits::vertex_descriptor u + , const Visitor_base & w) +{} +template +inline void out_edges(typename boost::graph_traits::vertex_descriptor u + , const Visitor_base & w) +{} + +// +// MutableHalfedgeGraph +// +template +void add_vertex(Visitor_base & w) +{} +template +void add_vertex(const typename boost::graph_traits::vertex_property_type& p + , Visitor_base & w) +{} +template +void remove_vertex(typename boost::graph_traits< Graph >::vertex_descriptor v + , Visitor_base & w) +{} +template +void add_edge(Visitor_base & w) +{} +template +void remove_edge(typename boost::graph_traits< Graph >::edge_descriptor e + , Visitor_base & w) +{} +template +void set_target(typename boost::graph_traits< Graph >::halfedge_descriptor h1 + , typename boost::graph_traits< Graph >::vertex_descriptor v + , Visitor_base & w) +{} +template +void set_next(typename boost::graph_traits< Graph >::halfedge_descriptor h1 + , typename boost::graph_traits< Graph >::halfedge_descriptor h2 + , Visitor_base & w) +{} + +// +// MutableFaceGraph +// +template +void add_face(Visitor_base & w) +{} +template +void add_face(InputIterator begin, InputIterator end, + Visitor_base & w) +{} +template +void remove_face(typename boost::graph_traits< Graph >::face_descriptor f + , Visitor_base & w) +{} +template +void set_face(typename boost::graph_traits< Graph >::halfedge_descriptor h + , typename boost::graph_traits< Graph >::face_descriptor f + , const Visitor_base & w) +{} +template +void set_halfedge(typename boost::graph_traits< Graph >::face_descriptor f + , typename boost::graph_traits< Graph >::halfedge_descriptor h + , Visitor_base & w) +{} +template +void set_halfedge(typename boost::graph_traits< Graph >::vertex_descriptor v + , typename boost::graph_traits< Graph >::halfedge_descriptor h + , const Visitor_base & w) +{} + +// +// HalfedgeGraph +// +template +void edge(typename boost::graph_traits< Graph >::halfedge_descriptor h + , const Visitor_base & w) +{} +template +void halfedge(typename boost::graph_traits< Graph >::edge_descriptor e + , const Visitor_base & w) +{} +template +void halfedge(typename boost::graph_traits< Graph >::vertex_descriptor v + , const Visitor_base & w) +{} +template +void halfedge(typename boost::graph_traits< Graph >::vertex_descriptor u + , typename boost::graph_traits< Graph >::vertex_descriptor v + , const Visitor_base & w) +{} +template +void opposite(typename boost::graph_traits< Graph >::halfedge_descriptor h + , const Visitor_base & w) +{} +template +void source(typename boost::graph_traits< Graph >::halfedge_descriptor h + , const Visitor_base & w) +{} +template +void target(typename boost::graph_traits< Graph >::halfedge_descriptor h + , const Visitor_base & w) +{} +template +void next(typename boost::graph_traits< Graph >::halfedge_descriptor outedge + , const Visitor_base & w) +{} +template +void prev(typename boost::graph_traits< Graph >::halfedge_descriptor outedge + , const Visitor_base & w) +{} + +// +// HalfedgeListGraph +// +template +void halfedges(const Visitor_base & w) +{} +template +void num_halfedges(const Visitor_base & w) +{} + +// Graph +template +void face(typename boost::graph_traits< Graph >::halfedge_descriptor h + , const Visitor_base & w) +{} +template +void halfedge(typename boost::graph_traits< Graph >::face_descriptor f + , const Visitor_base & w) +{} +template +void faces(const Visitor_base & w) +{} +template +void num_faces(const Visitor_base & w) +{} +template +void is_valid(const Visitor_base & w, bool verbose = false) +{} +template +void get(PropertyTag ptag, const Visitor_base& w) +{} + + +//// OVERLOADS FOR TUPLE + +template +typename boost::graph_traits::vertices_size_type +num_vertices(const boost::tuple, + boost::reference_wrapper >& w) +{ + num_vertices(boost::unwrap_ref(w.get<0>())); + return num_vertices(boost::unwrap_ref(w.get<1>())); +} + +template +typename boost::graph_traits::edges_size_type +num_edges(const boost::tuple, + boost::reference_wrapper >& w) +{ + num_edges(boost::unwrap_ref(w.get<0>())); + return num_edges(boost::unwrap_ref(w.get<1>())); +} + +template +typename boost::graph_traits::degree_size_type +degree(typename boost::graph_traits::vertex_descriptor v + , const boost::tuple, + boost::reference_wrapper >& w) +{ + degree(v, boost::unwrap_ref(w.get<0>())); + return degree(v, boost::unwrap_ref(w.get<1>())); +} + +template +typename boost::graph_traits::degree_size_type +out_degree(typename boost::graph_traits::vertex_descriptor v + , const boost::tuple, + boost::reference_wrapper >& w) +{ + out_degree(v, boost::unwrap_ref(w.get<0>())); + return out_degree(v, boost::unwrap_ref(w.get<1>())); +} + +template +typename boost::graph_traits::degree_size_type +in_degree(typename boost::graph_traits::vertex_descriptor v + , const boost::tuple, + boost::reference_wrapper >& w) +{ + in_degree(v, boost::unwrap_ref(w.get<0>())); + return in_degree(v, boost::unwrap_ref(w.get<1>())); +} + +template +typename boost::graph_traits::vertex_descriptor +source(typename boost::graph_traits::edge_descriptor e + , const boost::tuple, + boost::reference_wrapper > & w) +{ + source(e, boost::unwrap_ref(w.get<0>())); + return source(e, boost::unwrap_ref(w.get<1>())); +} + +template +typename boost::graph_traits::vertex_descriptor +target(typename boost::graph_traits::edge_descriptor e + , const boost::tuple, + boost::reference_wrapper > & w) +{ + target(e, boost::unwrap_ref(w.get<0>())); + return target(e, boost::unwrap_ref(w.get<1>())); +} + +template +std::pair::edge_descriptor, bool> +edge(typename boost::graph_traits::vertex_descriptor u + , typename boost::graph_traits::vertex_descriptor v + , const boost::tuple, + boost::reference_wrapper > & w) +{ + return edge(u, v, boost::unwrap_ref(w.get<1>())); +} + +template +inline CGAL::Iterator_range::vertex_iterator> +vertices(const boost::tuple, + boost::reference_wrapper >& w) +{ + return vertices(boost::unwrap_ref(w.get<1>())); +} + +template +inline CGAL::Iterator_range::edge_iterator> +edges(const boost::tuple, + boost::reference_wrapper >& w) +{ + return edges(boost::unwrap_ref(w.get<1>())); +} + +template +inline CGAL::Iterator_range::in_edge_iterator> +in_edges(typename boost::graph_traits::vertex_descriptor u + , const boost::tuple, + boost::reference_wrapper >& w) +{ + return in_edges(u, boost::unwrap_ref(w.get<1>())); +} + +template +inline CGAL::Iterator_range::out_edge_iterator> +out_edges(typename boost::graph_traits::vertex_descriptor u + , const boost::tuple, + boost::reference_wrapper >& w) +{ + return out_edges(u, boost::unwrap_ref(w.get<1>())); +} + +// +// MutableHalfedgeGraph +// + +template +typename boost::graph_traits< Graph >::vertex_descriptor +add_vertex(boost::tuple, + boost::reference_wrapper >& w) +{ + return add_vertex(boost::unwrap_ref(w.get<1>())); +} + + +template +typename boost::graph_traits< Graph >::vertex_descriptor +add_vertex(const typename boost::graph_traits::vertex_property_type& p +, boost::tuple, + boost::reference_wrapper >& w) +{ + return add_vertex(p, boost::unwrap_ref(w.get<1>())); +} + +template +void +remove_vertex(typename boost::graph_traits< Graph >::vertex_descriptor v +, boost::tuple, + boost::reference_wrapper >& w) +{ + remove_vertex(v, boost::unwrap_ref(w.get<1>())); +} + +template +typename boost::graph_traits< Graph >::edge_descriptor +add_edge(boost::tuple, + boost::reference_wrapper >& w) +{ + return add_edge(boost::unwrap_ref(w.get<1>())); +} + +template +void +remove_edge(typename boost::graph_traits< Graph >::edge_descriptor e +, boost::tuple, + boost::reference_wrapper >& w) +{ + remove_edge(e, boost::unwrap_ref(w.get<1>())); +} + + +template +void +set_target(typename boost::graph_traits< Graph >::halfedge_descriptor h1 +, typename boost::graph_traits< Graph >::vertex_descriptor v +, boost::tuple, + boost::reference_wrapper >& w) +{ + set_target(h1, v, boost::unwrap_ref(w.get<1>())); +} + +template +void +set_next(typename boost::graph_traits< Graph >::halfedge_descriptor h1 + , typename boost::graph_traits< Graph >::halfedge_descriptor h2 + , boost::tuple, + boost::reference_wrapper >& w) +{ + set_next(h1, h2, boost::unwrap_ref(w.get<1>())); +} + +// +// MutableFaceGraph +// + +template +typename boost::graph_traits< Graph >::face_descriptor +add_face(boost::tuple, +boost::reference_wrapper >& w) +{ + return add_face(boost::unwrap_ref(w.get<1>())); +} + +template +typename boost::graph_traits< Graph >::face_descriptor +add_face(InputIterator begin, + InputIterator end, + boost::tuple, + boost::reference_wrapper >& w) +{ + return add_face(begin, end, boost::unwrap_ref(w.get<1>())); +} + +template +void +remove_face(typename boost::graph_traits< Graph >::face_descriptor f +, boost::tuple, +boost::reference_wrapper >& w) +{ + return remove_face(f, boost::unwrap_ref(w.get<1>())); +} + +template +void +set_face(typename boost::graph_traits< Graph >::halfedge_descriptor h +, typename boost::graph_traits< Graph >::face_descriptor f +, const boost::tuple, +boost::reference_wrapper >& w) +{ + set_face(h, f, boost::unwrap_ref(w.get<1>())); +} + +template +void +set_halfedge(typename boost::graph_traits< Graph >::face_descriptor f +, typename boost::graph_traits< Graph >::halfedge_descriptor h +, boost::tuple, +boost::reference_wrapper >& w) +{ + set_halfedge(f, h, boost::unwrap_ref(w.get<1>())); +} + +template +void +set_halfedge(typename boost::graph_traits< Graph >::vertex_descriptor v +, typename boost::graph_traits< Graph >::halfedge_descriptor h +, const boost::tuple, +boost::reference_wrapper >& w) +{ + set_halfedge(v, h, boost::unwrap_ref(w.get<1>())); +} + + +// +// HalfedgeGraph +// +template +typename boost::graph_traits< Graph >::edge_descriptor +edge(typename boost::graph_traits< Graph >::halfedge_descriptor h +, const boost::tuple, + boost::reference_wrapper >& w) +{ + return edge(h, boost::unwrap_ref(w.get<1>())); +} + +template +typename boost::graph_traits< Graph >::halfedge_descriptor +halfedge(typename boost::graph_traits< Graph >::edge_descriptor e +, const boost::tuple, + boost::reference_wrapper >& w) +{ + return halfedge(e, boost::unwrap_ref(w.get<1>())); +} + +template +typename boost::graph_traits< Graph >::halfedge_descriptor +halfedge(typename boost::graph_traits< Graph >::vertex_descriptor v +, const boost::tuple, + boost::reference_wrapper >& w) +{ + return halfedge(v, boost::unwrap_ref(w.get<1>())); +} + +template +std::pair< typename boost::graph_traits< Graph >::halfedge_descriptor + , bool> + halfedge(typename boost::graph_traits< Graph >::vertex_descriptor u + , typename boost::graph_traits< Graph >::vertex_descriptor v + , const boost::tuple, + boost::reference_wrapper >& w) +{ + return halfedge(u, v, boost::unwrap_ref(w.get<1>())); +} + +template +typename boost::graph_traits< Graph >::halfedge_descriptor +opposite(typename boost::graph_traits< Graph >::halfedge_descriptor h +, const boost::tuple, + boost::reference_wrapper >& w) +{ + return opposite(h, boost::unwrap_ref(w.get<1>())); +} + +template +typename boost::graph_traits< Graph >::vertex_descriptor +source(typename boost::graph_traits< Graph >::halfedge_descriptor h +, const boost::tuple, + boost::reference_wrapper >& w) +{ + return source(h, boost::unwrap_ref(w.get<1>())); +} + +template +typename boost::graph_traits< Graph >::vertex_descriptor +target(typename boost::graph_traits< Graph >::halfedge_descriptor h +, const boost::tuple, boost::reference_wrapper >& w) +{ + return target(h, boost::unwrap_ref(w.get<1>())); +} + +template +typename boost::graph_traits< Graph >::halfedge_descriptor +next(typename boost::graph_traits< Graph >::halfedge_descriptor outedge +, const boost::tuple, boost::reference_wrapper >& w) +{ + return next(outedge, boost::unwrap_ref(w.get<1>())); +} + +template +typename boost::graph_traits< Graph >::halfedge_descriptor +prev(typename boost::graph_traits< Graph >::halfedge_descriptor outedge +, const boost::tuple, boost::reference_wrapper >& w) +{ + return prev(outedge, boost::unwrap_ref(w.get<1>())); +} + + +// +// HalfedgeListGraph +// + +template +CGAL::Iterator_range::halfedge_iterator> +halfedges(const boost::tuple, boost::reference_wrapper >& w) +{ + return halfedges(boost::unwrap_ref(w.get<1>())); +} + +template +typename boost::graph_traits< Graph >::halfedges_size_type +num_halfedges(const boost::tuple, boost::reference_wrapper >& w) +{ + return num_halfedges(boost::unwrap_ref(w.get<1>())); +} + +// Graph +template +typename boost::graph_traits< Graph >::face_descriptor +face(typename boost::graph_traits< Graph >::halfedge_descriptor h +, const boost::tuple, boost::reference_wrapper >& w) +{ + return face(h, boost::unwrap_ref(w.get<1>())); +} + +template +typename boost::graph_traits< Graph >::halfedge_descriptor +halfedge(typename boost::graph_traits< Graph >::face_descriptor f +, const boost::tuple, boost::reference_wrapper >& w) +{ + return halfedge(f, boost::unwrap_ref(w.get<1>())); +} + +template +inline CGAL::Iterator_range::face_iterator > +faces(const boost::tuple, boost::reference_wrapper >& w) +{ + return faces(boost::unwrap_ref(w.get<1>())); +} + +template +typename boost::graph_traits::faces_size_type +num_faces(const boost::tuple, + boost::reference_wrapper >& w) +{ + return num_faces(boost::unwrap_ref(w.get<1>())); +} + +template +bool is_valid(const boost::tuple, + boost::reference_wrapper >& w + , bool verbose = false) +{ + Graph& g = boost::unwrap_ref(w.get<1>()); + std::cout << typeid(g).name() << std::endl; + return is_valid(g, verbose); +} + +template +typename boost::property_map< Graph, PropertyTag >::type +get(PropertyTag ptag, + const boost::tuple, + boost::reference_wrapper >& w) +{ + return get(ptag, boost::unwrap_ref(w.get<1>())); +} + +}//end namespace CGAL + +#endif //CGAL_BOOST_GRAPH_VISITOR_H diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 2032395c5b8..b2330a1d22d 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -85,6 +86,22 @@ namespace internal { }; + template + class Status_map_visitor + : public Visitor_base + { + typedef Visitor_base Base; + typedef typename Base::halfedge_descriptor halfedge_descriptor; + + std::map& halfedge_status_map_; + + public: + Status_map_visitor(std::map& hsmap) + : halfedge_status_map_(hsmap) + {} + + }; + template Traits; typedef CGAL::AABB_tree AABB_tree; + typedef Status_map_visitor Status_visitor; + public: Incremental_remesher(PolygonMesh& pmesh , VertexPointMap& vpmap @@ -377,6 +396,13 @@ namespace internal { boost::bimaps::multiset_of > > Boost_bimap; typedef typename Boost_bimap::value_type short_edge; + //Status_visitor visitor2(halfedge_status_map_); + //std::cout << "Valid : " + // << is_valid(mesh_) + // << "\t" + // << is_valid(CGAL::make_graph_with_visitor(visitor2, mesh_)) + // << std::endl; + #ifdef CGAL_PMP_REMESHING_VERBOSE std::cout << "Collapse short edges (" << low << ", " << high << ")..." << std::endl; @@ -534,9 +560,12 @@ namespace internal { }//end if(collapse_ok) } - std::size_t n = PMP::remove_degenerate_faces(mesh_ + Status_visitor visitor(halfedge_status_map_); + std::size_t n = PMP::remove_degenerate_faces( + CGAL::make_graph_with_visitor(visitor, mesh_) , PMP::parameters::vertex_point_map(vpmap_) .geom_traits(GeomTraits())); + if (n > 0) { std::cout << "Warning : tags should maybe be fixed" << std::endl; @@ -970,8 +999,6 @@ namespace internal { { typename std::map < halfedge_descriptor, Halfedge_status >::const_iterator it = halfedge_status_map_.find(h); - if (it == halfedge_status_map_.end()) - std::cout << "stop " << std::endl; CGAL_assertion(it != halfedge_status_map_.end()); return it->second; } From 6303dbeb7d1e8c16c2e4ff85f05fa273716d9ee6 Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Thu, 11 Jun 2015 15:26:52 +0200 Subject: [PATCH 091/217] Fix a syntax error not detected my MSVC --- BGL/include/CGAL/boost/graph/visitor.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BGL/include/CGAL/boost/graph/visitor.h b/BGL/include/CGAL/boost/graph/visitor.h index b00f7a5a425..13c19b78e08 100644 --- a/BGL/include/CGAL/boost/graph/visitor.h +++ b/BGL/include/CGAL/boost/graph/visitor.h @@ -8,7 +8,7 @@ namespace boost { template - struct boost::graph_traits< + struct graph_traits< boost::tuple, boost::reference_wrapper > > : boost::graph_traits< Graph > { @@ -17,7 +17,7 @@ namespace boost }; template - struct boost::graph_traits< + struct graph_traits< boost::tuple, boost::reference_wrapper > const > : boost::graph_traits< Graph > {}; From 7a7c4fa44727f04b60e1bf1333436dd126e2907f Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Thu, 11 Jun 2015 15:27:20 +0200 Subject: [PATCH 092/217] appeared in Boost-1.56 The compatibility path is . --- BGL/include/CGAL/boost/graph/visitor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BGL/include/CGAL/boost/graph/visitor.h b/BGL/include/CGAL/boost/graph/visitor.h index 13c19b78e08..57198651dac 100644 --- a/BGL/include/CGAL/boost/graph/visitor.h +++ b/BGL/include/CGAL/boost/graph/visitor.h @@ -3,7 +3,7 @@ #include #include -#include +#include namespace boost { From b639f7d05184fcdbef490e44452b54ee91b37431 Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Thu, 11 Jun 2015 15:54:15 +0200 Subject: [PATCH 093/217] Fix a compilation error One cannot bind a temporary object to a non-const reference. --- .../CGAL/Polygon_mesh_processing/internal/remesh_impl.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index b2330a1d22d..7866bf6abb6 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -26,6 +26,7 @@ #include #include #include +#include #ifdef CGAL_PMP_REMESHING_DEBUG #include @@ -561,8 +562,13 @@ namespace internal { } Status_visitor visitor(halfedge_status_map_); + + boost::tuple, + boost::reference_wrapper > g_with_visitor = + CGAL::make_graph_with_visitor(visitor, mesh_); + std::size_t n = PMP::remove_degenerate_faces( - CGAL::make_graph_with_visitor(visitor, mesh_) + g_with_visitor , PMP::parameters::vertex_point_map(vpmap_) .geom_traits(GeomTraits())); From 817d28515c058a0340ab09014544f163692d9bc5 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Thu, 11 Jun 2015 16:53:10 +0200 Subject: [PATCH 094/217] duplicate every function in the overload for tuple --- BGL/include/CGAL/boost/graph/visitor.h | 55 +++++++++++++++++++------- 1 file changed, 41 insertions(+), 14 deletions(-) diff --git a/BGL/include/CGAL/boost/graph/visitor.h b/BGL/include/CGAL/boost/graph/visitor.h index 57198651dac..dc138d5fe80 100644 --- a/BGL/include/CGAL/boost/graph/visitor.h +++ b/BGL/include/CGAL/boost/graph/visitor.h @@ -322,6 +322,7 @@ edge(typename boost::graph_traits::vertex_descriptor u , const boost::tuple, boost::reference_wrapper > & w) { + edge(u, v, boost::unwrap_ref(w.get<0>())); return edge(u, v, boost::unwrap_ref(w.get<1>())); } @@ -330,6 +331,7 @@ inline CGAL::Iterator_range::vertex_iterator vertices(const boost::tuple, boost::reference_wrapper >& w) { + vertices(boost::unwrap_ref(w.get<0>())); return vertices(boost::unwrap_ref(w.get<1>())); } @@ -338,6 +340,7 @@ inline CGAL::Iterator_range::edge_iterator> edges(const boost::tuple, boost::reference_wrapper >& w) { + edges(boost::unwrap_ref(w.get<0>())); return edges(boost::unwrap_ref(w.get<1>())); } @@ -347,6 +350,7 @@ in_edges(typename boost::graph_traits::vertex_descriptor u , const boost::tuple, boost::reference_wrapper >& w) { + in_edges(u, boost::unwrap_ref(w.get<0>())); return in_edges(u, boost::unwrap_ref(w.get<1>())); } @@ -356,6 +360,7 @@ out_edges(typename boost::graph_traits::vertex_descriptor u , const boost::tuple, boost::reference_wrapper >& w) { + out_edges(u, boost::unwrap_ref(w.get<0>())); return out_edges(u, boost::unwrap_ref(w.get<1>())); } @@ -368,25 +373,27 @@ typename boost::graph_traits< Graph >::vertex_descriptor add_vertex(boost::tuple, boost::reference_wrapper >& w) { + add_vertex(boost::unwrap_ref(w.get<0>())); return add_vertex(boost::unwrap_ref(w.get<1>())); } - template typename boost::graph_traits< Graph >::vertex_descriptor add_vertex(const typename boost::graph_traits::vertex_property_type& p -, boost::tuple, - boost::reference_wrapper >& w) + , boost::tuple, + boost::reference_wrapper >& w) { + add_vertex(p, boost::unwrap_ref(w.get<0>())); return add_vertex(p, boost::unwrap_ref(w.get<1>())); } template void remove_vertex(typename boost::graph_traits< Graph >::vertex_descriptor v -, boost::tuple, - boost::reference_wrapper >& w) + , boost::tuple, + boost::reference_wrapper >& w) { + remove_vertex(v, boost::unwrap_ref(w.get<0>())); remove_vertex(v, boost::unwrap_ref(w.get<1>())); } @@ -395,6 +402,7 @@ typename boost::graph_traits< Graph >::edge_descriptor add_edge(boost::tuple, boost::reference_wrapper >& w) { + add_edge(boost::unwrap_ref(w.get<0>())); return add_edge(boost::unwrap_ref(w.get<1>())); } @@ -404,10 +412,10 @@ remove_edge(typename boost::graph_traits< Graph >::edge_descriptor e , boost::tuple, boost::reference_wrapper >& w) { + remove_edge(e, boost::unwrap_ref(w.get<0>())); remove_edge(e, boost::unwrap_ref(w.get<1>())); } - template void set_target(typename boost::graph_traits< Graph >::halfedge_descriptor h1 @@ -415,6 +423,7 @@ set_target(typename boost::graph_traits< Graph >::halfedge_descriptor h1 , boost::tuple, boost::reference_wrapper >& w) { + set_target(h1, v, boost::unwrap_ref(w.get<0>())); set_target(h1, v, boost::unwrap_ref(w.get<1>())); } @@ -425,18 +434,19 @@ set_next(typename boost::graph_traits< Graph >::halfedge_descriptor h1 , boost::tuple, boost::reference_wrapper >& w) { + set_next(h1, h2, boost::unwrap_ref(w.get<0>())); set_next(h1, h2, boost::unwrap_ref(w.get<1>())); } // // MutableFaceGraph // - template typename boost::graph_traits< Graph >::face_descriptor add_face(boost::tuple, -boost::reference_wrapper >& w) + boost::reference_wrapper >& w) { + add_face(boost::unwrap_ref(w.get<0>())); return add_face(boost::unwrap_ref(w.get<1>())); } @@ -447,6 +457,7 @@ add_face(InputIterator begin, boost::tuple, boost::reference_wrapper >& w) { + add_face(begin, end, boost::unwrap_ref(w.get<0>())); return add_face(begin, end, boost::unwrap_ref(w.get<1>())); } @@ -456,6 +467,7 @@ remove_face(typename boost::graph_traits< Graph >::face_descriptor f , boost::tuple, boost::reference_wrapper >& w) { + remove_face(f, boost::unwrap_ref(w.get<0>())); return remove_face(f, boost::unwrap_ref(w.get<1>())); } @@ -466,6 +478,7 @@ set_face(typename boost::graph_traits< Graph >::halfedge_descriptor h , const boost::tuple, boost::reference_wrapper >& w) { + set_face(h, f, boost::unwrap_ref(w.get<0>())); set_face(h, f, boost::unwrap_ref(w.get<1>())); } @@ -476,6 +489,7 @@ set_halfedge(typename boost::graph_traits< Graph >::face_descriptor f , boost::tuple, boost::reference_wrapper >& w) { + set_halfedge(f, h, boost::unwrap_ref(w.get<0>())); set_halfedge(f, h, boost::unwrap_ref(w.get<1>())); } @@ -486,10 +500,10 @@ set_halfedge(typename boost::graph_traits< Graph >::vertex_descriptor v , const boost::tuple, boost::reference_wrapper >& w) { + set_halfedge(v, h, boost::unwrap_ref(w.get<0>())); set_halfedge(v, h, boost::unwrap_ref(w.get<1>())); } - // // HalfedgeGraph // @@ -499,6 +513,7 @@ edge(typename boost::graph_traits< Graph >::halfedge_descriptor h , const boost::tuple, boost::reference_wrapper >& w) { + edge(h, boost::unwrap_ref(w.get<0>())); return edge(h, boost::unwrap_ref(w.get<1>())); } @@ -508,6 +523,7 @@ halfedge(typename boost::graph_traits< Graph >::edge_descriptor e , const boost::tuple, boost::reference_wrapper >& w) { + halfedge(e, boost::unwrap_ref(w.get<0>())); return halfedge(e, boost::unwrap_ref(w.get<1>())); } @@ -517,6 +533,7 @@ halfedge(typename boost::graph_traits< Graph >::vertex_descriptor v , const boost::tuple, boost::reference_wrapper >& w) { + halfedge(v, boost::unwrap_ref(w.get<0>())); return halfedge(v, boost::unwrap_ref(w.get<1>())); } @@ -528,6 +545,7 @@ std::pair< typename boost::graph_traits< Graph >::halfedge_descriptor , const boost::tuple, boost::reference_wrapper >& w) { + halfedge(u, v, boost::unwrap_ref(w.get<0>())); return halfedge(u, v, boost::unwrap_ref(w.get<1>())); } @@ -537,6 +555,7 @@ opposite(typename boost::graph_traits< Graph >::halfedge_descriptor h , const boost::tuple, boost::reference_wrapper >& w) { + opposite(h, boost::unwrap_ref(w.get<0>())); return opposite(h, boost::unwrap_ref(w.get<1>())); } @@ -546,6 +565,7 @@ source(typename boost::graph_traits< Graph >::halfedge_descriptor h , const boost::tuple, boost::reference_wrapper >& w) { + source(h, boost::unwrap_ref(w.get<0>())); return source(h, boost::unwrap_ref(w.get<1>())); } @@ -554,6 +574,7 @@ typename boost::graph_traits< Graph >::vertex_descriptor target(typename boost::graph_traits< Graph >::halfedge_descriptor h , const boost::tuple, boost::reference_wrapper >& w) { + target(h, boost::unwrap_ref(w.get<0>())); return target(h, boost::unwrap_ref(w.get<1>())); } @@ -562,6 +583,7 @@ typename boost::graph_traits< Graph >::halfedge_descriptor next(typename boost::graph_traits< Graph >::halfedge_descriptor outedge , const boost::tuple, boost::reference_wrapper >& w) { + next(outedge, boost::unwrap_ref(w.get<0>())); return next(outedge, boost::unwrap_ref(w.get<1>())); } @@ -570,18 +592,18 @@ typename boost::graph_traits< Graph >::halfedge_descriptor prev(typename boost::graph_traits< Graph >::halfedge_descriptor outedge , const boost::tuple, boost::reference_wrapper >& w) { + prev(outedge, boost::unwrap_ref(w.get<0>())); return prev(outedge, boost::unwrap_ref(w.get<1>())); } - // // HalfedgeListGraph // - template CGAL::Iterator_range::halfedge_iterator> halfedges(const boost::tuple, boost::reference_wrapper >& w) { + halfedges(boost::unwrap_ref(w.get<0>())); return halfedges(boost::unwrap_ref(w.get<1>())); } @@ -589,6 +611,7 @@ template typename boost::graph_traits< Graph >::halfedges_size_type num_halfedges(const boost::tuple, boost::reference_wrapper >& w) { + num_halfedges(boost::unwrap_ref(w.get<0>())); return num_halfedges(boost::unwrap_ref(w.get<1>())); } @@ -598,6 +621,7 @@ typename boost::graph_traits< Graph >::face_descriptor face(typename boost::graph_traits< Graph >::halfedge_descriptor h , const boost::tuple, boost::reference_wrapper >& w) { + face(h, boost::unwrap_ref(w.get<0>())); return face(h, boost::unwrap_ref(w.get<1>())); } @@ -606,6 +630,7 @@ typename boost::graph_traits< Graph >::halfedge_descriptor halfedge(typename boost::graph_traits< Graph >::face_descriptor f , const boost::tuple, boost::reference_wrapper >& w) { + halfedge(f, boost::unwrap_ref(w.get<0>())); return halfedge(f, boost::unwrap_ref(w.get<1>())); } @@ -613,6 +638,7 @@ template inline CGAL::Iterator_range::face_iterator > faces(const boost::tuple, boost::reference_wrapper >& w) { + faces(boost::unwrap_ref(w.get<0>())); return faces(boost::unwrap_ref(w.get<1>())); } @@ -621,6 +647,7 @@ typename boost::graph_traits::faces_size_type num_faces(const boost::tuple, boost::reference_wrapper >& w) { + num_faces(boost::unwrap_ref(w.get<0>())); return num_faces(boost::unwrap_ref(w.get<1>())); } @@ -629,9 +656,8 @@ bool is_valid(const boost::tuple, boost::reference_wrapper >& w , bool verbose = false) { - Graph& g = boost::unwrap_ref(w.get<1>()); - std::cout << typeid(g).name() << std::endl; - return is_valid(g, verbose); + is_valid(boost::unwrap_ref(w.get<0>()), verbose); + return is_valid(boost::unwrap_ref(w.get<1>()), verbose); } template @@ -640,6 +666,7 @@ get(PropertyTag ptag, const boost::tuple, boost::reference_wrapper >& w) { + get(ptag, boost::unwrap_ref(w.get<0>())); return get(ptag, boost::unwrap_ref(w.get<1>())); } From b7c0acae5624e4cfe7cf13f758ffbac47e9f92fe Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Thu, 11 Jun 2015 17:27:04 +0200 Subject: [PATCH 095/217] first operations for visitor that deals with status map --- .../internal/remesh_impl.h | 42 +++++++++++++------ 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 7866bf6abb6..b5c61922f7d 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -87,22 +87,46 @@ namespace internal { }; + ///////////// Visitor dealing with status map //////////////// + template class Status_map_visitor : public Visitor_base { + typedef PolygonMesh Graph; typedef Visitor_base Base; - typedef typename Base::halfedge_descriptor halfedge_descriptor; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename boost::graph_traits::face_descriptor face_descriptor; std::map& halfedge_status_map_; + PolygonMesh& pmesh_; public: - Status_map_visitor(std::map& hsmap) + Status_map_visitor(std::map& hsmap, + PolygonMesh& pmesh) : halfedge_status_map_(hsmap) + , pmesh_(pmesh) {} + void remove_halfedges(const face_descriptor& f) + { + halfedge_descriptor h = halfedge(f, pmesh_); + halfedge_status_map_.erase(h); + halfedge_status_map_.erase(next(h, pmesh_)); + halfedge_status_map_.erase(next(next(h, pmesh_), pmesh_)); + } + }; + template + void remove_face(typename boost::graph_traits::face_descriptor f + , Status_map_visitor & w) + { + w.remove_halfedges(f); + } + + ////////// End of visitor //////////////// + template > > Boost_bimap; typedef typename Boost_bimap::value_type short_edge; - //Status_visitor visitor2(halfedge_status_map_); - //std::cout << "Valid : " - // << is_valid(mesh_) - // << "\t" - // << is_valid(CGAL::make_graph_with_visitor(visitor2, mesh_)) - // << std::endl; - #ifdef CGAL_PMP_REMESHING_VERBOSE std::cout << "Collapse short edges (" << low << ", " << high << ")..." << std::endl; @@ -561,11 +578,10 @@ namespace internal { }//end if(collapse_ok) } - Status_visitor visitor(halfedge_status_map_); - + Status_visitor visitor(halfedge_status_map_, mesh_); boost::tuple, - boost::reference_wrapper > g_with_visitor = - CGAL::make_graph_with_visitor(visitor, mesh_); + boost::reference_wrapper > + g_with_visitor = CGAL::make_graph_with_visitor(visitor, mesh_); std::size_t n = PMP::remove_degenerate_faces( g_with_visitor From ab1ddcac2571016bb59eff840200b479da8a66d4 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 12 Jun 2015 10:36:23 +0200 Subject: [PATCH 096/217] fix non-inversion test --- .../internal/remesh_impl.h | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index b5c61922f7d..0936c75ad0b 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -926,37 +926,33 @@ namespace internal { BOOST_FOREACH(halfedge_descriptor hd, halfedges_around_target(h, mesh_)) { - if (source(hd, mesh_) == vs - || target(next(hd, mesh_), mesh_) == vs) //degenerate face - continue; Vector_3 n = compute_normal(face(hd, mesh_)); - CGAL_assertion(n != CGAL::NULL_VECTOR); - normals.push_back(n); + //n can be 0 in the splitting step because we remove degenerate faces + //only at the end of the splitting step + if(n != CGAL::NULL_VECTOR) + normals.push_back(n); } BOOST_FOREACH(halfedge_descriptor hd, halfedges_around_target(opposite(h, mesh_), mesh_)) { - if (source(hd, mesh_) == vt - || target(next(hd, mesh_), mesh_) == vt) //degenerate face - continue; Vector_3 n = compute_normal(face(hd, mesh_)); - CGAL_assertion(n != CGAL::NULL_VECTOR); - normals.push_back(n); + if(n != CGAL::NULL_VECTOR) + normals.push_back(n); } //check all normals have same orientation + bool res = true; for(std::size_t i = 1; i < normals.size(); ++i)/*start at 1 on purpose*/ { if (normals[i-1] * normals[i] <= 0.) { - //restore position - put(vpmap_, vs, ps); - return false; + res = false; + break; } } //restore position put(vpmap_, vs, ps); - return true; + return res; } Vector_3 compute_normal(const face_descriptor& f) const From e87c65bd3ddcddfecfb56683b18c2562654ea413 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Thu, 18 Jun 2015 10:54:25 +0200 Subject: [PATCH 097/217] rename variable for consistency --- .../Polygon_mesh_processing/internal/remesh_impl.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 0936c75ad0b..ac7ee3c647a 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -99,21 +99,21 @@ namespace internal { typedef typename boost::graph_traits::face_descriptor face_descriptor; std::map& halfedge_status_map_; - PolygonMesh& pmesh_; + PolygonMesh& mesh_; public: Status_map_visitor(std::map& hsmap, PolygonMesh& pmesh) : halfedge_status_map_(hsmap) - , pmesh_(pmesh) + , mesh_(pmesh) {} void remove_halfedges(const face_descriptor& f) { - halfedge_descriptor h = halfedge(f, pmesh_); + halfedge_descriptor h = halfedge(f, mesh_); halfedge_status_map_.erase(h); - halfedge_status_map_.erase(next(h, pmesh_)); - halfedge_status_map_.erase(next(next(h, pmesh_), pmesh_)); + halfedge_status_map_.erase(next(h, mesh_)); + halfedge_status_map_.erase(next(next(h, mesh_), mesh_)); } }; From 7ad049d14c4e26fc7f2aad9bda4feab4df5be62c Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Thu, 18 Jun 2015 11:00:08 +0200 Subject: [PATCH 098/217] don't use status visitor, it is not enough to keep halfedges status up-to-date --- .../CGAL/Polygon_mesh_processing/internal/remesh_impl.h | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index ac7ee3c647a..3e1eb259c23 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -150,8 +150,6 @@ namespace internal { typedef CGAL::AABB_traits Traits; typedef CGAL::AABB_tree AABB_tree; - typedef Status_map_visitor Status_visitor; - public: Incremental_remesher(PolygonMesh& pmesh , VertexPointMap& vpmap @@ -578,13 +576,8 @@ namespace internal { }//end if(collapse_ok) } - Status_visitor visitor(halfedge_status_map_, mesh_); - boost::tuple, - boost::reference_wrapper > - g_with_visitor = CGAL::make_graph_with_visitor(visitor, mesh_); - std::size_t n = PMP::remove_degenerate_faces( - g_with_visitor + mesh_ , PMP::parameters::vertex_point_map(vpmap_) .geom_traits(GeomTraits())); From bfa1dfea2c7e972bd6c5122118e31b4a27e07cea Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Thu, 18 Jun 2015 11:03:23 +0200 Subject: [PATCH 099/217] add code to remove degenerate faces after each edge collapse --- .../internal/remesh_impl.h | 94 ++++++++++++++++--- 1 file changed, 83 insertions(+), 11 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 3e1eb259c23..44413d7a501 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -557,10 +557,11 @@ namespace internal { if (!mesh_border_case) merge_status(en_p, s_epo_p, s_ep_p); + fix_degenerate_faces(vkept, short_edges, sq_low); + #ifdef CGAL_PMP_REMESHING_DEBUG unsigned int nbb = nb_valid_halfedges(); CGAL_assertion(nbb == halfedge_status_map_.size()); - CGAL_assertion(source(en, mesh_) == source(en_p, mesh_)); debug_status_map(); #endif @@ -576,17 +577,8 @@ namespace internal { }//end if(collapse_ok) } - std::size_t n = PMP::remove_degenerate_faces( - mesh_ - , PMP::parameters::vertex_point_map(vpmap_) - .geom_traits(GeomTraits())); + debug_status_map(); - if (n > 0) - { - std::cout << "Warning : tags should maybe be fixed" << std::endl; - unsigned int nbb = nb_valid_halfedges(); - CGAL_assertion(nbb == halfedge_status_map_.size()); - } #ifdef CGAL_PMP_REMESHING_EXPENSIVE_DEBUG BOOST_FOREACH(vertex_descriptor v, vertices(mesh_)) debug_normals(v); @@ -1036,6 +1028,86 @@ namespace internal { // else keep current status for en and eno } + template + void fix_degenerate_faces(const vertex_descriptor& v, + Bimap& short_edges, + const double& sq_low) + { + CGAL_assertion_code(std::size_t nb_done = 0); + std::vector degenerate_faces; + BOOST_FOREACH(halfedge_descriptor h, + halfedges_around_target(halfedge(v, mesh_), mesh_)) + { + if (PMP::is_degenerated(h, mesh_, vpmap_, GeomTraits())) + degenerate_faces.push_back(h); + } + BOOST_FOREACH(halfedge_descriptor h, degenerate_faces) + { + BOOST_FOREACH(halfedge_descriptor hf, + halfedges_around_face(h, mesh_)) + { + vertex_descriptor vc = target(hf, mesh_); + vertex_descriptor va = target(next(hf, mesh_), mesh_); + vertex_descriptor vb = target(next(next(hf, mesh_), mesh_), mesh_); + Vector_3 ab(vpmap_[va], vpmap_[vb]); + Vector_3 ac(vpmap_[va], vpmap_[vc]); + if (ab * ac < 0) + { + halfedge_descriptor hfo = opposite(hf, mesh_); + halfedge_descriptor h_ab = prev(hf, mesh_); + halfedge_descriptor h_ca = next(hf, mesh_); + + short_edges.left.erase(hf); + short_edges.left.erase(hfo); + + CGAL::Euler::flip_edge(hf, mesh_); + CGAL_assertion_code(++nb_done); + + //update halfedge_status_map_ + halfedge_status_map_[h_ab] = merge_status(h_ab, hf, hfo); + halfedge_status_map_[h_ca] = merge_status(h_ca, hf, hfo); + halfedge_status_map_[hf] = + (is_on_patch(h_ca) || is_on_patch_border(h_ca)) + ? PATCH + : MESH; + halfedge_status_map_[hfo] = status(hf); + debug_status_map(); + + //insert new edges in 'short_edges' + if (is_collapse_allowed(hf)) + { + double sqlen = sqlength(hf); + if (sqlen < sq_low) + short_edges.insert(typename Bimap::value_type(hf, sqlen)); + } + break; + } + } + } + CGAL_assertion(degenerate_faces.size() == nb_done); +#ifdef CGAL_PMP_REMESHING_DEBUG + debug_status_map(); +#endif + } + + Halfedge_status merge_status(const halfedge_descriptor& h1, + const halfedge_descriptor& h2, + const halfedge_descriptor& h3) + { + Halfedge_status s1 = status(h1); + if (s1 == MESH_BORDER) return s1; + Halfedge_status s2 = status(h2); + if (s2 == MESH_BORDER) return s2; + Halfedge_status s3 = status(h3); + if (s3 == MESH_BORDER) return s3; + else if (s1 == PATCH_BORDER) return s1; + else if (s2 == PATCH_BORDER) return s2; + else if (s3 == PATCH_BORDER) return s3; + + CGAL_assertion(s1 == s2 && s1 == s3); + return s1; + } + bool is_on_patch(const halfedge_descriptor& h) const { bool res =(status(h) == PATCH); From a603d5a7058e67a3a859c79f065733afe9a884d8 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Thu, 18 Jun 2015 17:32:06 +0200 Subject: [PATCH 100/217] fix collapse_short_edges now there are degenerate faces in equalize_valences --- .../internal/remesh_impl.h | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 44413d7a501..71c181f461a 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -401,6 +401,7 @@ namespace internal { CGAL_expensive_assertion(is_triangle_mesh(mesh_)); CGAL_assertion(halfedge_status_map_.size() == nb_valid_halfedges()); debug_status_map(); + debug_self_intersections(); #endif #ifdef CGAL_DUMP_REMESHING_STEPS @@ -563,6 +564,12 @@ namespace internal { unsigned int nbb = nb_valid_halfedges(); CGAL_assertion(nbb == halfedge_status_map_.size()); debug_status_map(); + BOOST_FOREACH(halfedge_descriptor hv, + halfedges_around_target(halfedge(vkept, mesh_), mesh_)) + { + CGAL_assertion(!PMP::is_degenerated(hv, mesh_, vpmap_, GeomTraits())); + } + debug_normals(vkept); #endif //insert new/remaining short edges @@ -596,6 +603,8 @@ namespace internal { CGAL_expensive_assertion(is_triangle_mesh(mesh_)); debug_status_map(); debug_self_intersections(); + CGAL_expensive_assertion(0 == PMP::remove_degenerate_faces(mesh_, + PMP::parameters::vertex_point_map(vpmap_).geom_traits(GeomTraits()))); #endif } @@ -1041,8 +1050,13 @@ namespace internal { if (PMP::is_degenerated(h, mesh_, vpmap_, GeomTraits())) degenerate_faces.push_back(h); } - BOOST_FOREACH(halfedge_descriptor h, degenerate_faces) + while(!degenerate_faces.empty()) { + halfedge_descriptor h = degenerate_faces.back(); + degenerate_faces.pop_back(); + + CGAL_assertion(PMP::is_degenerated(h, mesh_, vpmap_, GeomTraits())); + BOOST_FOREACH(halfedge_descriptor hf, halfedges_around_face(h, mesh_)) { @@ -1080,11 +1094,16 @@ namespace internal { if (sqlen < sq_low) short_edges.insert(typename Bimap::value_type(hf, sqlen)); } + + if (PMP::is_degenerated(hf, mesh_, vpmap_, GeomTraits())) + degenerate_faces.push_back(hf); + if (PMP::is_degenerated(hfo, mesh_, vpmap_, GeomTraits())) + degenerate_faces.push_back(hfo); + break; } } } - CGAL_assertion(degenerate_faces.size() == nb_done); #ifdef CGAL_PMP_REMESHING_DEBUG debug_status_map(); #endif @@ -1243,14 +1262,14 @@ namespace internal { void debug_normals(const vertex_descriptor& v) const { - if (!is_on_patch(v)) - return;//not much to say if we are on a boundary/sharp edge CGAL_assertion(check_normals(v)); } bool check_normals(const vertex_descriptor& v) const { - //assume we are on a patch without checking it + if (!is_on_patch(v)) + return true;//not much to say if we are on a boundary/sharp edge + std::vector normals; BOOST_FOREACH(halfedge_descriptor hd, halfedges_around_target(halfedge(v, mesh_), mesh_)) From 8950cef41411f6f1a3255b9982e767fc1b93b5d7 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Thu, 18 Jun 2015 17:41:53 +0200 Subject: [PATCH 101/217] add degeneracy test --- .../internal/remesh_impl.h | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 71c181f461a..5965847c746 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -603,7 +603,7 @@ namespace internal { CGAL_expensive_assertion(is_triangle_mesh(mesh_)); debug_status_map(); debug_self_intersections(); - CGAL_expensive_assertion(0 == PMP::remove_degenerate_faces(mesh_, + CGAL_assertion(0 == PMP::remove_degenerate_faces(mesh_, PMP::parameters::vertex_point_map(vpmap_).geom_traits(GeomTraits()))); #endif } @@ -642,7 +642,7 @@ namespace internal { CGAL::Euler::flip_edge(he, mesh_); ++nb_flips; - + CGAL_assertion_code(Halfedge_status s2 = status(he)); CGAL_assertion_code(Halfedge_status s2o = status(opposite(he, mesh_))); CGAL_assertion(s1 == s2 && s1 == PATCH); @@ -662,6 +662,8 @@ namespace internal { //check that mesh does not become non-triangle, //nor has inverted faces if (deviation_pre < deviation_post + || incident_to_degenerate(he) + || incident_to_degenerate(opposite(he, mesh_)) || !is_on_triangle(he) || !is_on_triangle(opposite(he, mesh_)) || !check_normals(target(he, mesh_)) @@ -1109,6 +1111,17 @@ namespace internal { #endif } + bool incident_to_degenerate(const halfedge_descriptor& he) + { + BOOST_FOREACH(halfedge_descriptor h, + halfedges_around_target(he, mesh_)) + { + if (PMP::is_degenerated(h, mesh_, vpmap_, GeomTraits())) + return true; + } + return false; + } + Halfedge_status merge_status(const halfedge_descriptor& h1, const halfedge_descriptor& h2, const halfedge_descriptor& h3) From e7b8734306ec8edcba40305a563100f4bab76945 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 19 Jun 2015 10:10:29 +0200 Subject: [PATCH 102/217] fix compilation for Polyhedron --- .../include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 5965847c746..40e9c508f8c 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -1090,7 +1090,7 @@ namespace internal { debug_status_map(); //insert new edges in 'short_edges' - if (is_collapse_allowed(hf)) + if (is_collapse_allowed(edge(hf, mesh_))) { double sqlen = sqlength(hf); if (sqlen < sq_low) From 77529d985d3fd607f79ccb32bf7d43d621988127 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 19 Jun 2015 11:23:30 +0200 Subject: [PATCH 103/217] move debug code to debug macro --- .../CGAL/Polygon_mesh_processing/internal/remesh_impl.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 40e9c508f8c..b5c0746bd96 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -584,7 +584,9 @@ namespace internal { }//end if(collapse_ok) } +#ifdef CGAL_PMP_REMESHING_DEBUG debug_status_map(); +#endif #ifdef CGAL_PMP_REMESHING_EXPENSIVE_DEBUG BOOST_FOREACH(vertex_descriptor v, vertices(mesh_)) @@ -1087,7 +1089,9 @@ namespace internal { ? PATCH : MESH; halfedge_status_map_[hfo] = status(hf); +#ifdef CGAL_PMP_REMESHING_DEBUG debug_status_map(); +#endif //insert new edges in 'short_edges' if (is_collapse_allowed(edge(hf, mesh_))) From ed9276295d9be8f02cd4f326a75a868c2a52fcba Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 19 Jun 2015 11:27:23 +0200 Subject: [PATCH 104/217] add stuff to verbose mode --- .../include/CGAL/Polygon_mesh_processing/remesh.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h index 22d240e6c31..d7495c2fa92 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h @@ -112,14 +112,19 @@ void incremental_triangle_based_remeshing(PolygonMesh& pmesh double low = 4. / 5. * target_edge_length; double high = 4. / 3. * target_edge_length; +#ifdef CGAL_PMP_REMESHING_VERBOSE + std::cout << "Remeshing..."; +#endif for (unsigned int i = 0; i < nb_iterations; ++i) { +#ifdef CGAL_PMP_REMESHING_VERBOSE + std::cout << "* Iteration " << (i + 1) << "*" << std::endl; +#endif remesher.split_long_edges(high); remesher.collapse_short_edges(low, high); remesher.equalize_valences(); remesher.tangential_relaxation(); remesher.project_to_surface(); - std::cout << std::endl; } } From a1056c57dcf08e1ada3ab5dc58bc7fc9074bd1e5 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 19 Jun 2015 11:42:56 +0200 Subject: [PATCH 105/217] little cleaning --- .../CGAL/Polygon_mesh_processing/internal/remesh_impl.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index b5c0746bd96..1f7ffc7f15a 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -260,16 +260,14 @@ namespace internal { //insert new edges to keep triangular faces, and update long_edges if (!is_border(hnew, mesh_)) { - halfedge_descriptor hnew2 - = CGAL::Euler::split_face(hnew, next(next(hnew, mesh_), mesh_), mesh_); + CGAL::Euler::split_face(hnew, next(next(hnew, mesh_), mesh_), mesh_); } //do it again on the other side if we're not on boundary halfedge_descriptor hnew_opp = opposite(hnew, mesh_); if (!is_border(hnew_opp, mesh_)) { - halfedge_descriptor hnew2 - = CGAL::Euler::split_face(prev(hnew_opp, mesh_), next(hnew_opp, mesh_), mesh_); + CGAL::Euler::split_face(prev(hnew_opp, mesh_), next(hnew_opp, mesh_), mesh_); } } #ifdef CGAL_PMP_REMESHING_VERBOSE @@ -535,7 +533,6 @@ namespace internal { halfedge_descriptor en = next(he, mesh_); halfedge_descriptor en_p = next(opposite(he, mesh_), mesh_); Halfedge_status s_ep_p = status(ep_p); - Halfedge_status s_en_p = status(en_p); Halfedge_status s_epo_p = status(epo_p); Halfedge_status s_ep = status(prev(he, mesh_)); Halfedge_status s_epo = status(opposite(prev(he, mesh_), mesh_)); From d423378321701da89501436dd2fefb28af2ea696 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 19 Jun 2015 11:44:11 +0200 Subject: [PATCH 106/217] remove visitor (became useless) --- .../internal/remesh_impl.h | 41 ------------------- 1 file changed, 41 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 1f7ffc7f15a..3dd200fb8dc 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -12,7 +12,6 @@ #include #include -#include #include #include @@ -87,46 +86,6 @@ namespace internal { }; - ///////////// Visitor dealing with status map //////////////// - - template - class Status_map_visitor - : public Visitor_base - { - typedef PolygonMesh Graph; - typedef Visitor_base Base; - typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; - typedef typename boost::graph_traits::face_descriptor face_descriptor; - - std::map& halfedge_status_map_; - PolygonMesh& mesh_; - - public: - Status_map_visitor(std::map& hsmap, - PolygonMesh& pmesh) - : halfedge_status_map_(hsmap) - , mesh_(pmesh) - {} - - void remove_halfedges(const face_descriptor& f) - { - halfedge_descriptor h = halfedge(f, mesh_); - halfedge_status_map_.erase(h); - halfedge_status_map_.erase(next(h, mesh_)); - halfedge_status_map_.erase(next(next(h, mesh_), mesh_)); - } - - }; - - template - void remove_face(typename boost::graph_traits::face_descriptor f - , Status_map_visitor & w) - { - w.remove_halfedges(f); - } - - ////////// End of visitor //////////////// - template Date: Fri, 19 Jun 2015 11:54:44 +0200 Subject: [PATCH 107/217] more verbosity --- .../include/CGAL/Polygon_mesh_processing/remesh.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h index d7495c2fa92..51438302ab4 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h @@ -113,12 +113,14 @@ void incremental_triangle_based_remeshing(PolygonMesh& pmesh double high = 4. / 3. * target_edge_length; #ifdef CGAL_PMP_REMESHING_VERBOSE - std::cout << "Remeshing..."; + std::cout << "Remeshing (size = " << target_edge_length; + std::cout << ", #iter = " << nb_iterations << ")..." << std::endl; #endif + for (unsigned int i = 0; i < nb_iterations; ++i) { #ifdef CGAL_PMP_REMESHING_VERBOSE - std::cout << "* Iteration " << (i + 1) << "*" << std::endl; + std::cout << " * Iteration " << (i + 1) << "*" << std::endl; #endif remesher.split_long_edges(high); remesher.collapse_short_edges(low, high); @@ -126,6 +128,11 @@ void incremental_triangle_based_remeshing(PolygonMesh& pmesh remesher.tangential_relaxation(); remesher.project_to_surface(); } + +#ifdef CGAL_PMP_REMESHING_VERBOSE + std::cout << "Remeshing done (size = " << target_edge_length; + std::cout << ", #iter = " << nb_iterations << ")." << std::endl; +#endif } template Date: Fri, 19 Jun 2015 13:58:26 +0200 Subject: [PATCH 108/217] verbose mode --- .../include/CGAL/Polygon_mesh_processing/remesh.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h index 51438302ab4..4fa578a50cf 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h @@ -113,6 +113,7 @@ void incremental_triangle_based_remeshing(PolygonMesh& pmesh double high = 4. / 3. * target_edge_length; #ifdef CGAL_PMP_REMESHING_VERBOSE + std::cout << std::endl; std::cout << "Remeshing (size = " << target_edge_length; std::cout << ", #iter = " << nb_iterations << ")..." << std::endl; #endif @@ -122,11 +123,16 @@ void incremental_triangle_based_remeshing(PolygonMesh& pmesh #ifdef CGAL_PMP_REMESHING_VERBOSE std::cout << " * Iteration " << (i + 1) << "*" << std::endl; #endif + remesher.split_long_edges(high); remesher.collapse_short_edges(low, high); remesher.equalize_valences(); remesher.tangential_relaxation(); remesher.project_to_surface(); + +#ifdef CGAL_PMP_REMESHING_VERBOSE + std::cout << std::endl; +#endif } #ifdef CGAL_PMP_REMESHING_VERBOSE From 0ef807ac063aae8d5b2cf57d3d1d3264e31ca8d6 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 19 Jun 2015 16:37:50 +0200 Subject: [PATCH 109/217] missing space in verbose mode --- .../internal/remesh_impl.h | 29 ++++++++----------- .../CGAL/Polygon_mesh_processing/remesh.h | 2 +- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 3dd200fb8dc..38ce74f098b 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -520,11 +520,7 @@ namespace internal { unsigned int nbb = nb_valid_halfedges(); CGAL_assertion(nbb == halfedge_status_map_.size()); debug_status_map(); - BOOST_FOREACH(halfedge_descriptor hv, - halfedges_around_target(halfedge(vkept, mesh_), mesh_)) - { - CGAL_assertion(!PMP::is_degenerated(hv, mesh_, vpmap_, GeomTraits())); - } + CGAL_assertion(!incident_to_degenerate(halfedge(vkept, mesh_))); debug_normals(vkept); #endif @@ -540,10 +536,6 @@ namespace internal { }//end if(collapse_ok) } -#ifdef CGAL_PMP_REMESHING_DEBUG - debug_status_map(); -#endif - #ifdef CGAL_PMP_REMESHING_EXPENSIVE_DEBUG BOOST_FOREACH(vertex_descriptor v, vertices(mesh_)) debug_normals(v); @@ -639,12 +631,6 @@ namespace internal { } } - std::size_t n = PMP::remove_degenerate_faces(mesh_ - , PMP::parameters::vertex_point_map(vpmap_) - .geom_traits(GeomTraits())); - if (n > 0) - std::cout << "Warning : tags should maybe be fixed" << std::endl; - #ifdef CGAL_PMP_REMESHING_VERBOSE std::cout << "done. ("<< nb_flips << " flips)" << std::endl; #endif @@ -652,6 +638,10 @@ namespace internal { #ifdef CGAL_PMP_REMESHING_DEBUG CGAL_assertion(nb_valid_halfedges() == halfedge_status_map_.size()); debug_status_map(); + CGAL_assertion(0 == PMP::remove_degenerate_faces(mesh_ + , PMP::parameters::vertex_point_map(vpmap_) + .geom_traits(GeomTraits()))); + debug_self_intersections(); #endif #ifdef CGAL_DUMP_REMESHING_STEPS @@ -724,12 +714,14 @@ namespace internal { } CGAL_assertion(is_valid(mesh_)); - CGAL_assertion(is_triangle_mesh(mesh_)); + CGAL_assertion(is_triangle_mesh(mesh_)); +#ifdef CGAL_PMP_REMESHING_DEBUG + debug_self_intersections(); +#endif #ifdef CGAL_PMP_REMESHING_VERBOSE std::cout << "done." << std::endl; #endif - #ifdef CGAL_DUMP_REMESHING_STEPS dump("4-relaxation.off"); #endif @@ -756,6 +748,9 @@ namespace internal { CGAL_assertion(is_valid(mesh_)); CGAL_assertion(is_triangle_mesh(mesh_)); +#ifdef CGAL_PMP_REMESHING_DEBUG + debug_self_intersections(); +#endif #ifdef CGAL_PMP_REMESHING_VERBOSE std::cout << "done." << std::endl; #endif diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h index 4fa578a50cf..1878aeb6391 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h @@ -121,7 +121,7 @@ void incremental_triangle_based_remeshing(PolygonMesh& pmesh for (unsigned int i = 0; i < nb_iterations; ++i) { #ifdef CGAL_PMP_REMESHING_VERBOSE - std::cout << " * Iteration " << (i + 1) << "*" << std::endl; + std::cout << " * Iteration " << (i + 1) << " *" << std::endl; #endif remesher.split_long_edges(high); From 4b85ca54608cf86cdb26b9d40614a622ceeead52 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 19 Jun 2015 16:42:56 +0200 Subject: [PATCH 110/217] add assertions --- .../include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 38ce74f098b..a4bb76f29e7 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -589,6 +589,8 @@ namespace internal { CGAL_assertion_code(Halfedge_status s1 = status(he)); CGAL_assertion_code(Halfedge_status s1o = status(opposite(he, mesh_))); + CGAL_assertion(!incident_to_degenerate(he)); + CGAL_assertion(!incident_to_degenerate(opposite(he, mesh_))); CGAL::Euler::flip_edge(he, mesh_); ++nb_flips; From 2b0061d5119ed4c9bcb0a22641b4a0c71957cd73 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 19 Jun 2015 16:46:52 +0200 Subject: [PATCH 111/217] fix inversion of faces in equalize_valences when endpoints of the halfedge being flipped belong to something else than PATCH --- .../Polygon_mesh_processing/internal/remesh_impl.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index a4bb76f29e7..973ff78b4cc 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -614,6 +614,7 @@ namespace internal { //check that mesh does not become non-triangle, //nor has inverted faces if (deviation_pre < deviation_post + || !check_normals(he) || incident_to_degenerate(he) || incident_to_degenerate(opposite(he, mesh_)) || !is_on_triangle(he) @@ -1258,6 +1259,15 @@ namespace internal { return true; } + bool check_normals(const halfedge_descriptor& h) const + { + if (!is_on_patch(h)) + return true;//nothing to say + Vector_3 n = compute_normal(face(h, mesh_)); + Vector_3 no = compute_normal(face(opposite(h, mesh_), mesh_)); + return n * no > 0.; + } + private: PolygonMesh& mesh_; VertexPointMap& vpmap_; From 08e06531f3bb406d88c9a32a927eb34c719dc752 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Thu, 25 Jun 2015 14:11:40 +0200 Subject: [PATCH 112/217] add test data --- .../data/joint-patch.selection.txt | 3 + .../data/joint_refined.off | 917 ++++++++++++++++++ 2 files changed, 920 insertions(+) create mode 100644 Polygon_mesh_processing/test/Polygon_mesh_processing/data/joint-patch.selection.txt create mode 100644 Polygon_mesh_processing/test/Polygon_mesh_processing/data/joint_refined.off diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/data/joint-patch.selection.txt b/Polygon_mesh_processing/test/Polygon_mesh_processing/data/joint-patch.selection.txt new file mode 100644 index 00000000000..9df43e3290f --- /dev/null +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/data/joint-patch.selection.txt @@ -0,0 +1,3 @@ + +608 604 602 596 594 593 600 591 587 581 579 577 585 575 571 569 567 583 563 512 510 509 589 565 503 573 501 507 505 499 497 470 468 467 465 606 461 451 449 516 514 495 463 168 598 167 +913 905 903 899 893 890 884 875 867 861 848 845 842 833 830 827 824 819 816 813 807 804 801 798 795 792 789 786 783 777 774 771 768 765 762 759 756 753 748 745 743 741 738 729 724 703 700 688 677 653 646 642 634 709 619 650 610 600 715 517 514 513 511 509 896 507 503 499 495 735 493 491 489 751 487 483 480 478 476 472 466 464 697 474 462 459 457 810 455 453 449 694 447 438 434 432 427 878 423 430 421 436 419 417 414 836 412 732 404 402 400 398 396 851 394 391 389 387 385 721 383 910 691 381 379 377 375 712 373 371 363 361 359 355 353 348 346 485 344 686 341 337 333 332 330 327 324 319 682 318 316 313 312 311 858 302 887 299 780 291 369 289 321 297 288 286 284 497 280 470 277 410 275 367 271 269 267 853 263 261 259 255 864 252 248 246 244 242 240 357 234 226 224 217 204 195 440 176 169 165 282 161 156 146 144 640 406 140 138 135 718 445 294 133 131 873 129 250 127 125 123 727 121 236 119 117 238 115 111 109 107 105 365 103 101 99 193 97 95 93 91 87 85 83 608 305 81 426 79 501 77 75 821 73 443 71 69 67 622 65 468 63 61 59 706 57 55 505 53 51 49 47 881 231 45 451 43 142 41 39 37 113 35 89 32 855 30 606 301 28 350 25 839 23 870 408 21 19 17 15 13 11 9 7 5 3 0 diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/data/joint_refined.off b/Polygon_mesh_processing/test/Polygon_mesh_processing/data/joint_refined.off new file mode 100644 index 00000000000..8f0907a1c0e --- /dev/null +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/data/joint_refined.off @@ -0,0 +1,917 @@ +OFF +303 610 0 + +0.18987 0.5 0.0145757 +0.18987 -0.5 0.0145757 +0.160511 -0.5 0.0325677 +0.160511 0.5 0.0325677 +0.128697 -0.5 0.0457447 +0.128697 0.5 0.0457447 +0.0952137 -0.5 0.0537838 +0.0952137 0.5 0.0537838 +0.0608858 -0.5 0.0564848 +0.0608858 0.5 0.0564848 +0.0265575 -0.5 0.0537838 +0.0265575 0.5 0.0537838 +-0.0069256 -0.5 0.0457447 +-0.0069256 0.5 0.0457447 +-0.038739 -0.5 0.0325677 +-0.038739 0.5 0.0325677 +-0.0680987 -0.5 0.0145757 +-0.0680987 0.5 0.0145757 +-0.0942827 -0.5 -0.00778743 +-0.0942827 0.5 -0.00778743 +-0.116646 -0.5 -0.0339725 +-0.116646 0.5 -0.0339725 +-0.134639 -0.5 -0.0633324 +-0.134639 0.5 -0.0633324 +-0.147815 -0.5 -0.0951457 +-0.147815 0.5 -0.0951457 +-0.155855 -0.5 -0.128628 +-0.155855 0.5 -0.128628 +-0.158556 -0.5 -0.162956 +-0.158556 0.5 -0.162956 +-0.155855 -0.5 -0.197285 +-0.155855 0.5 -0.197285 +-0.147815 -0.5 -0.230768 +-0.147815 0.5 -0.230768 +-0.134639 -0.5 -0.262581 +-0.134639 0.5 -0.262581 +-0.116646 -0.5 -0.291941 +-0.116646 0.5 -0.291941 +-0.0942827 -0.5 -0.318125 +-0.0942827 0.5 -0.318125 +-0.0680987 -0.5 -0.340488 +-0.0680987 0.5 -0.340488 +-0.038739 -0.5 -0.358481 +-0.038739 0.5 -0.358481 +-0.0069256 -0.5 -0.371658 +-0.0069256 0.5 -0.371658 +0.0265574 -0.5 -0.379697 +0.0265574 0.5 -0.379697 +0.0608857 -0.5 -0.382398 +0.0608857 0.5 -0.382398 +0.0952137 -0.5 -0.379697 +0.0952137 0.5 -0.379697 +0.128696 -0.5 -0.371658 +0.128696 0.5 -0.371658 +0.16051 -0.5 -0.358481 +0.16051 0.5 -0.358481 +0.18987 -0.5 -0.340488 +0.18987 0.5 -0.340488 +0.216054 -0.5 -0.318125 +0.216054 0.5 -0.318125 +0.238418 -0.5 -0.291941 +0.238418 0.5 -0.291941 +0.25641 -0.5 -0.262581 +0.25641 0.5 -0.262581 +0.269587 -0.5 -0.230768 +0.269587 0.5 -0.230768 +0.277626 -0.5 -0.197285 +0.277626 0.5 -0.197285 +0.280327 -0.5 -0.162956 +0.280327 0.5 -0.162956 +0.277626 -0.5 -0.128628 +0.277626 0.5 -0.128628 +0.269587 -0.5 -0.0951457 +0.269587 0.5 -0.0951457 +0.25641 -0.5 -0.0633324 +0.25641 0.5 -0.0633324 +0.238418 -0.5 -0.0339725 +0.238418 0.5 -0.0339725 +0.216054 -0.5 -0.00778851 +0.216054 0.5 -0.00778851 +0.157965 -0.5 -0.461734 +0.203507 -0.5 -0.442869 +0.24554 -0.5 -0.417111 +0.283026 -0.5 -0.385097 +0.315041 -0.5 -0.347611 +0.340798 -0.5 -0.305579 +0.359662 -0.5 -0.260035 +0.371171 -0.5 -0.212101 +0.375039 -0.5 -0.162956 +0.371171 -0.5 -0.113812 +0.359662 -0.5 -0.0658783 +0.340799 -0.5 -0.0203345 +0.315041 -0.5 0.0216976 +0.283026 -0.5 0.0591838 +0.245541 -0.5 0.0911989 +0.203508 -0.5 0.116956 +0.157965 -0.5 0.13582 +0.11003 -0.5 0.147329 +0.0608858 -0.5 0.151196 +-0.375039 -0.5 -0.162956 +0.0608858 -0.5 -0.47711 +0.11003 -0.5 -0.473241 +0.203508 0.5 0.116956 +0.245541 0.5 0.0911989 +0.283026 0.5 0.0591838 +0.315041 0.5 0.0216986 +0.340799 0.5 -0.0203345 +0.359662 0.5 -0.0658783 +0.371171 0.5 -0.113812 +0.375039 0.5 -0.162956 +0.371171 0.5 -0.212101 +0.359662 0.5 -0.260035 +0.340798 0.5 -0.305579 +0.315041 0.5 -0.347611 +0.283026 0.5 -0.385097 +0.24554 0.5 -0.417111 +0.203507 0.5 -0.442869 +0.157965 0.5 -0.461734 +0.11003 0.5 -0.473241 +0.0608858 0.5 -0.47711 +-0.375039 0.5 -0.162956 +0.0608858 0.5 0.151196 +0.11003 0.5 0.147329 +0.157965 0.5 0.13582 +-0.375039 -0.5 -0.47711 +-0.157078 -0.5 0.151196 +-0.375039 -0.5 0.151196 +-0.375039 0.5 -0.47711 +-0.375039 -0.185847 0.47711 +-0.157078 -0.185847 0.47711 +-0.157078 0.5 0.47711 +-0.375039 0.5 0.47711 +-0.375039 0.5 0.151196 +-0.157078 0.5 0.151196 +-0.375039 -0.185847 0.151196 +-0.375039 -0.5 0.47711 +-0.157078 -0.5 0.47711 +0.0608859 -0.5 0.47711 +0.0608859 -0.185847 0.47711 +-0.157078 -0.185847 0.151196 +0.0608858 -0.185847 0.151196 +-0.375039 -0.315312 0.400904 +-0.375039 -0.329311 0.404264 +-0.375039 -0.343663 0.405393 +-0.375039 -0.358016 0.404264 +-0.375039 -0.372015 0.400904 +-0.375039 -0.385316 0.395395 +-0.375039 -0.397591 0.387872 +-0.375039 -0.408538 0.378521 +-0.375039 -0.417888 0.367575 +-0.375039 -0.42541 0.355299 +-0.375039 -0.43092 0.341999 +-0.375039 -0.434281 0.328 +-0.375039 -0.43541 0.313648 +-0.375039 -0.434281 0.299295 +-0.375039 -0.43092 0.285296 +-0.375039 -0.42541 0.271996 +-0.375039 -0.417888 0.25972 +-0.375039 -0.408538 0.248773 +-0.375039 -0.397591 0.239422 +-0.375039 -0.385316 0.2319 +-0.375039 -0.372015 0.22639 +-0.375039 -0.358016 0.223031 +-0.375039 -0.343663 0.221901 +-0.375039 -0.329311 0.223031 +-0.375039 -0.315312 0.22639 +-0.375039 -0.302011 0.2319 +-0.375039 -0.289736 0.239422 +-0.375039 -0.278789 0.248773 +-0.375039 -0.269439 0.25972 +-0.375039 -0.261916 0.271996 +-0.375039 -0.256407 0.285296 +-0.375039 -0.253046 0.299295 +-0.375039 -0.251917 0.313648 +-0.375039 -0.253046 0.328 +-0.375039 -0.256407 0.341999 +-0.375039 -0.261916 0.355299 +-0.375039 -0.269439 0.367575 +-0.375039 -0.278789 0.378521 +-0.375039 -0.289736 0.387872 +-0.375039 -0.302011 0.395395 +0.0608859 -0.302011 0.395395 +0.0608859 -0.289736 0.387872 +0.0608859 -0.278789 0.378521 +0.0608859 -0.269439 0.367575 +0.0608859 -0.261916 0.355299 +0.0608859 -0.256407 0.341999 +0.0608859 -0.253046 0.328 +0.0608859 -0.251917 0.313648 +0.0608859 -0.253046 0.299295 +0.0608859 -0.256407 0.285296 +0.0608859 -0.261916 0.271996 +0.0608859 -0.269439 0.25972 +0.0608859 -0.278789 0.248773 +0.0608859 -0.289736 0.239422 +0.0608859 -0.302011 0.2319 +0.0608859 -0.315312 0.22639 +0.0608859 -0.329311 0.223031 +0.0608859 -0.343663 0.221901 +0.0608859 -0.358016 0.223031 +0.0608859 -0.372015 0.22639 +0.0608859 -0.385316 0.2319 +0.0608859 -0.397591 0.239422 +0.0608859 -0.408538 0.248773 +0.0608859 -0.417888 0.25972 +0.0608859 -0.42541 0.271996 +0.0608859 -0.43092 0.285296 +0.0608859 -0.434281 0.299295 +0.0608859 -0.43541 0.313648 +0.0608859 -0.434281 0.328 +0.0608859 -0.43092 0.341999 +0.0608859 -0.42541 0.355299 +0.0608859 -0.417888 0.367575 +0.0608859 -0.408538 0.378521 +0.0608859 -0.397591 0.387872 +0.0608859 -0.385316 0.395395 +0.0608859 -0.372015 0.400904 +0.0608859 -0.358016 0.404264 +0.0608859 -0.343663 0.405393 +0.0608859 -0.329311 0.404264 +0.0608859 -0.315312 0.400904 +-0.375039 0 -0.47711 +-0.157078 0.1570765 0.47711 +-0.157078 0.1570765 0.151196 +-0.375039 -0.25 -0.47711 +-0.375039 0.25 -0.47711 +-0.1570766 -0.5 -0.47711 +-0.1570766 0.5 -0.47711 +-0.157078 -0.01438525 0.47711 +-0.157078 0.32853825 0.47711 +-0.157078 0.32853825 0.151196 +-0.157078 -0.01438525 0.151196 +-0.157078 0.5 0.314153 +-0.157078 -0.185847 0.314153 +0.0608858 -0.3429235 0.151196 +-0.375039 -0.375 -0.47711 +-0.375039 -0.125 -0.47711 +-0.375039 0.125 -0.47711 +-0.375039 0.375 -0.47711 +-0.0480961 -0.185847 0.151196 +-0.0480961 0.5 0.151196 +-0.0480954 -0.5 -0.47711 +-0.2660578 -0.5 -0.47711 +-0.2660578 0.5 -0.47711 +-0.0480954 0.5 -0.47711 +-0.157078 -0.100116125 0.47711 +-0.157078 0.071345625 0.47711 +-0.157078 0.242807375 0.47711 +-0.157078 0.414269125 0.47711 +-0.157078 0.414269125 0.151196 +-0.157078 0.242807375 0.151196 +-0.157078 0.071345625 0.151196 +-0.157078 -0.100116125 0.151196 +-0.157078 0.5 0.2326745 +-0.157078 0.5 0.3956315 +-0.157078 -0.185847 0.3956315 +-0.157078 -0.185847 0.2326745 +0.0608858 -0.42146175 0.151196 +0.0608858 -0.26438525 0.151196 +-0.375039 -0.4375 -0.47711 +-0.375039 -0.3125 -0.47711 +-0.375039 -0.1875 -0.47711 +-0.375039 -0.0625 -0.47711 +-0.375039 0.0625 -0.47711 +-0.375039 0.1875 -0.47711 +-0.375039 0.3125 -0.47711 +-0.375039 0.4375 -0.47711 +0.00639485 -0.185847 0.151196 +-0.10258705 -0.185847 0.151196 +-0.10258705 0.5 0.151196 +0.00639485 0.5 0.151196 +0.0063952 -0.5 -0.47711 +-0.102586 -0.5 -0.47711 +-0.2115672 -0.5 -0.47711 +-0.3205484 -0.5 -0.47711 +-0.3205484 0.5 -0.47711 +-0.2115672 0.5 -0.47711 +-0.102586 0.5 -0.47711 +0.0063952 0.5 -0.47711 +-0.157078 -0.1429815625 0.47711 +-0.157078 -0.0572506875 0.47711 +-0.157078 0.0284801875 0.47711 +-0.157078 0.1142110625 0.47711 +-0.157078 0.1999419375 0.47711 +-0.157078 0.2856728125 0.47711 +-0.157078 0.3714036875 0.47711 +-0.157078 0.4571345625 0.47711 +-0.157078 0.4571345625 0.151196 +-0.157078 0.3714036875 0.151196 +-0.157078 0.2856728125 0.151196 +-0.157078 0.1999419375 0.151196 +-0.157078 0.1142110625 0.151196 +-0.157078 0.0284801875 0.151196 +-0.157078 -0.0572506875 0.151196 +-0.157078 -0.1429815625 0.151196 +-0.157078 0.5 0.19193525 +-0.157078 0.5 0.27341375 +-0.157078 0.5 0.35489225 +-0.157078 0.5 0.43637075 +-0.157078 -0.185847 0.43637075 +-0.157078 -0.185847 0.35489225 +-0.157078 -0.185847 0.27341375 +-0.157078 -0.185847 0.19193525 +3 3 0 1 +3 3 1 2 +3 5 3 2 +3 5 2 4 +3 7 5 4 +3 7 4 6 +3 9 7 6 +3 9 6 8 +3 11 9 8 +3 11 8 10 +3 13 11 10 +3 13 10 12 +3 15 13 12 +3 17 14 16 +3 19 17 16 +3 23 21 20 +3 23 20 22 +3 25 23 22 +3 25 22 24 +3 27 25 24 +3 27 24 26 +3 29 27 26 +3 29 26 28 +3 31 29 28 +3 31 28 30 +3 33 31 30 +3 33 30 32 +3 35 33 32 +3 35 32 34 +3 37 35 34 +3 37 34 36 +3 39 37 36 +3 39 36 38 +3 41 39 38 +3 41 38 40 +3 43 41 40 +3 43 40 42 +3 45 43 42 +3 45 42 44 +3 47 45 44 +3 47 44 46 +3 49 47 46 +3 49 46 48 +3 51 49 48 +3 51 48 50 +3 53 51 50 +3 53 50 52 +3 55 53 52 +3 55 52 54 +3 57 55 54 +3 57 54 56 +3 59 57 56 +3 59 56 58 +3 61 59 58 +3 61 58 60 +3 63 61 60 +3 63 60 62 +3 65 63 62 +3 65 62 64 +3 67 65 64 +3 67 64 66 +3 69 67 66 +3 69 66 68 +3 71 69 68 +3 71 68 70 +3 73 71 70 +3 77 75 74 +3 77 74 76 +3 79 77 76 +3 79 76 78 +3 0 79 78 +3 0 78 1 +3 99 28 26 +3 30 28 99 +3 99 26 24 +3 32 30 99 +3 99 24 22 +3 34 32 99 +3 80 52 101 +3 83 60 58 +3 90 70 89 +3 99 22 20 +3 36 34 99 +3 20 126 99 +3 124 38 36 +3 10 97 98 +3 97 8 6 +3 97 6 4 +3 96 2 95 +3 89 70 68 +3 87 66 64 +3 101 52 50 +3 101 50 48 +3 100 48 46 +3 120 29 31 +3 27 29 120 +3 120 31 33 +3 25 27 120 +3 120 33 35 +3 23 25 120 +3 123 95 102 +3 55 115 116 +3 120 35 37 +3 103 79 0 +3 113 59 61 +3 37 39 127 +3 19 21 120 +3 118 49 51 +3 118 51 53 +3 118 53 55 +3 111 61 63 +3 111 63 65 +3 123 0 3 +3 123 3 5 +3 122 123 5 +3 122 5 7 +3 122 7 9 +3 122 9 11 +3 122 11 13 +3 13 133 269 +3 15 17 133 +3 133 17 19 +3 88 109 108 +3 88 108 89 +3 87 110 109 +3 87 109 88 +3 86 111 110 +3 86 110 87 +3 85 112 111 +3 85 111 86 +3 84 113 112 +3 84 112 85 +3 83 113 84 +3 82 114 83 +3 81 116 115 +3 81 115 82 +3 80 116 81 +3 101 118 117 +3 101 117 80 +3 100 119 118 +3 100 118 101 +3 97 122 121 +3 96 123 122 +3 96 122 97 +3 95 123 96 +3 92 105 104 +3 92 104 93 +3 91 106 105 +3 91 105 92 +3 90 107 106 +3 90 106 91 +3 89 108 107 +3 89 107 90 +3 131 128 129 +3 131 129 279 +3 119 124 259 +3 119 100 271 +3 120 127 266 +3 120 124 99 +3 120 99 126 +3 120 126 134 +3 120 134 132 +3 128 135 136 +3 128 136 129 +3 129 136 137 +3 129 137 138 +3 230 121 270 +3 231 129 299 +3 229 133 295 +3 132 130 298 +3 130 132 131 +3 131 132 134 +3 172 128 131 +3 135 126 125 +3 135 125 136 +3 167 168 134 +3 134 168 169 +3 166 167 134 +3 134 169 170 +3 165 166 134 +3 165 134 126 +3 164 165 126 +3 163 164 126 +3 162 163 126 +3 161 162 126 +3 160 161 126 +3 159 160 126 +3 158 159 126 +3 157 158 126 +3 156 157 126 +3 134 170 171 +3 134 171 172 +3 128 172 173 +3 128 173 174 +3 128 174 175 +3 128 175 176 +3 128 176 177 +3 128 177 178 +3 128 178 179 +3 128 179 180 +3 128 180 141 +3 135 128 141 +3 135 141 142 +3 135 142 143 +3 135 143 144 +3 135 144 145 +3 135 145 146 +3 135 146 147 +3 135 147 148 +3 135 148 149 +3 135 149 150 +3 135 150 151 +3 155 156 126 +3 155 126 135 +3 154 155 135 +3 153 154 135 +3 152 153 135 +3 135 151 152 +3 136 125 98 +3 136 98 137 +3 202 203 98 +3 98 203 204 +3 201 202 98 +3 98 204 205 +3 200 201 98 +3 200 98 257 +3 199 200 140 +3 198 199 140 +3 197 198 140 +3 196 197 140 +3 195 196 140 +3 194 195 140 +3 193 194 140 +3 192 193 140 +3 191 192 140 +3 98 205 206 +3 137 98 206 +3 137 206 207 +3 137 207 208 +3 137 208 209 +3 137 209 210 +3 137 210 211 +3 137 211 212 +3 137 212 213 +3 137 213 214 +3 137 214 215 +3 137 215 216 +3 138 137 216 +3 138 216 217 +3 138 217 218 +3 138 218 219 +3 138 219 220 +3 138 220 181 +3 138 181 182 +3 138 182 183 +3 138 183 184 +3 138 184 185 +3 138 185 186 +3 190 191 140 +3 190 140 138 +3 189 190 138 +3 188 189 138 +3 187 188 138 +3 138 186 187 +3 138 140 267 +3 138 139 302 +3 184 183 178 +3 184 178 177 +3 183 182 179 +3 183 179 178 +3 182 181 180 +3 182 180 179 +3 181 220 141 +3 181 141 180 +3 220 219 142 +3 220 142 141 +3 219 218 143 +3 219 143 142 +3 218 217 144 +3 218 144 143 +3 217 216 145 +3 217 145 144 +3 216 215 146 +3 216 146 145 +3 215 214 147 +3 215 147 146 +3 214 213 148 +3 214 148 147 +3 213 212 149 +3 213 149 148 +3 212 211 150 +3 212 150 149 +3 211 210 151 +3 211 151 150 +3 210 209 152 +3 210 152 151 +3 209 208 153 +3 209 153 152 +3 208 207 154 +3 208 154 153 +3 207 206 155 +3 207 155 154 +3 206 205 156 +3 206 156 155 +3 205 204 157 +3 205 157 156 +3 204 203 158 +3 204 158 157 +3 203 202 159 +3 203 159 158 +3 202 201 160 +3 202 160 159 +3 201 200 161 +3 201 161 160 +3 200 199 162 +3 200 162 161 +3 199 198 163 +3 199 163 162 +3 198 197 164 +3 198 164 163 +3 197 196 165 +3 197 165 164 +3 196 195 166 +3 196 166 165 +3 195 194 167 +3 195 167 166 +3 194 193 168 +3 194 168 167 +3 193 192 169 +3 193 169 168 +3 192 191 170 +3 192 170 169 +3 191 190 171 +3 191 171 170 +3 190 189 172 +3 190 172 171 +3 189 188 173 +3 189 173 172 +3 188 187 174 +3 188 174 173 +3 187 186 175 +3 187 175 174 +3 186 185 176 +3 186 176 175 +3 185 184 177 +3 185 177 176 +3 121 139 268 +3 97 121 140 +3 115 55 57 +3 115 57 59 +3 113 83 114 +3 59 113 114 +3 114 82 115 +3 114 115 59 +3 117 118 55 +3 116 80 117 +3 116 117 55 +3 132 133 19 +3 127 41 43 +3 39 41 127 +3 105 75 77 +3 105 77 79 +3 103 93 104 +3 79 103 104 +3 104 105 79 +3 106 73 75 +3 65 67 110 +3 61 111 112 +3 112 113 61 +3 110 67 69 +3 69 71 109 +3 109 110 69 +3 108 109 71 +3 71 73 107 +3 106 107 73 +3 75 105 106 +3 13 15 133 +3 121 122 13 +3 102 103 0 +3 0 123 102 +3 45 47 119 +3 49 118 119 +3 47 49 119 +3 127 43 45 +3 45 119 278 +3 97 140 258 +3 125 16 14 +3 14 12 98 +3 15 12 14 +3 127 120 37 +3 110 111 65 +3 107 108 71 +3 98 125 14 +3 131 134 172 +3 94 93 103 +3 94 102 95 +3 95 1 94 +3 93 1 78 +3 1 93 94 +3 1 95 2 +3 4 96 97 +3 2 96 4 +3 78 92 93 +3 92 78 76 +3 91 76 74 +3 74 90 91 +3 88 68 66 +3 86 64 62 +3 85 62 60 +3 85 60 84 +3 82 58 56 +3 81 56 54 +3 80 54 52 +3 124 36 99 +3 10 98 12 +3 60 83 84 +3 46 124 274 +3 44 124 46 +3 42 124 44 +3 40 124 42 +3 38 124 40 +3 97 10 8 +3 66 87 88 +3 48 100 101 +3 102 94 103 +3 76 91 92 +3 72 74 75 +3 68 88 89 +3 64 86 87 +3 62 85 86 +3 58 82 83 +3 56 81 82 +3 54 80 81 +3 126 16 125 +3 17 15 14 +3 120 132 19 +3 21 19 20 +3 23 120 21 +3 16 18 19 +3 19 18 20 +3 20 18 126 +3 16 126 18 +3 90 74 72 +3 73 70 72 +3 72 70 90 +3 72 75 73 +3 119 221 263 +3 120 221 262 +3 131 222 283 +3 133 222 282 +3 121 223 291 +3 129 223 290 +3 119 224 261 +3 120 224 260 +3 227 225 265 +3 120 225 264 +3 119 226 273 +3 46 226 272 +3 225 227 277 +3 45 227 276 +3 131 228 281 +3 133 228 280 +3 131 229 285 +3 133 229 284 +3 121 230 289 +3 129 230 288 +3 121 231 293 +3 129 231 292 +3 248 232 297 +3 132 232 296 +3 252 233 301 +3 138 233 300 +3 200 234 258 +3 97 234 257 +3 119 235 260 +3 120 235 259 +3 119 236 262 +3 120 236 261 +3 119 237 264 +3 120 237 263 +3 243 238 266 +3 120 238 265 +3 138 239 268 +3 121 239 267 +3 13 240 270 +3 249 240 269 +3 119 241 272 +3 46 241 271 +3 119 242 274 +3 46 242 273 +3 238 243 276 +3 45 243 275 +3 225 244 278 +3 45 244 277 +3 131 245 280 +3 133 245 279 +3 131 246 282 +3 133 246 281 +3 131 247 284 +3 133 247 283 +3 131 248 286 +3 232 248 285 +3 240 249 288 +3 129 249 287 +3 121 250 290 +3 129 250 289 +3 121 251 292 +3 129 251 291 +3 121 252 294 +3 233 252 293 +3 229 253 296 +3 132 253 295 +3 286 254 298 +3 132 254 297 +3 231 255 300 +3 138 255 299 +3 294 256 302 +3 138 256 301 +3 257 234 200 +3 257 98 97 +3 258 140 200 +3 258 234 97 +3 259 235 119 +3 259 124 120 +3 260 224 119 +3 260 235 120 +3 261 236 119 +3 261 224 120 +3 262 221 119 +3 262 236 120 +3 263 237 119 +3 263 221 120 +3 264 225 119 +3 264 237 120 +3 265 238 227 +3 265 225 120 +3 266 127 275 +3 266 238 120 +3 267 239 138 +3 267 140 121 +3 268 139 138 +3 268 239 121 +3 269 240 13 +3 269 133 287 +3 270 121 13 +3 270 240 230 +3 271 241 119 +3 271 100 46 +3 272 226 119 +3 272 241 46 +3 273 242 119 +3 273 226 46 +3 274 124 119 +3 274 242 46 +3 275 243 266 +3 275 127 45 +3 276 227 238 +3 276 243 45 +3 277 244 225 +3 277 227 45 +3 278 119 225 +3 278 244 45 +3 279 245 131 +3 279 129 133 +3 280 228 131 +3 280 245 133 +3 281 246 131 +3 281 228 133 +3 282 222 131 +3 282 246 133 +3 283 247 131 +3 283 222 133 +3 284 229 131 +3 284 247 133 +3 285 248 131 +3 285 229 232 +3 286 130 131 +3 286 248 254 +3 287 249 269 +3 287 133 129 +3 288 230 240 +3 288 249 129 +3 289 250 121 +3 289 230 129 +3 290 223 121 +3 290 250 129 +3 291 251 121 +3 291 223 129 +3 292 231 121 +3 292 251 129 +3 293 252 121 +3 293 231 233 +3 294 139 121 +3 294 252 256 +3 295 253 229 +3 295 133 132 +3 296 232 229 +3 296 253 132 +3 297 254 248 +3 297 232 132 +3 298 130 286 +3 298 254 132 +3 299 255 231 +3 299 129 138 +3 300 233 231 +3 300 255 138 +3 301 256 252 +3 301 233 138 +3 302 139 294 +3 302 256 138 + From 8e44b5d77ab207db726e9d1fe81363d4f7b199c7 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 30 Jun 2015 12:17:31 +0200 Subject: [PATCH 113/217] fix remeshing test --- .../remeshing_test.cpp | 104 +++--------------- 1 file changed, 17 insertions(+), 87 deletions(-) diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp index 4d6c8869e7b..80e0b15e9d5 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp @@ -1,3 +1,4 @@ +// data/joint_refined.off 0.1 5 data/joint-patch.selection.txt #define CGAL_PMP_REMESHING_DEBUG #define CGAL_DUMP_REMESHING_STEPS @@ -27,91 +28,40 @@ typedef boost::graph_traits::edge_descriptor edge_descriptor; typedef boost::graph_traits::vertex_descriptor vertex_descriptor; typedef boost::graph_traits::face_descriptor face_descriptor; -// extract vertices which are at most k (inclusive) far from vertex v -std::vector extract_k_ring(vertex_descriptor v, - int k, - const Mesh& m) + +void collect_patch(const char* file, + const Mesh& m, + std::set& patch) { - vertex_descriptor vv = v; - - std::map D; - std::vector Q; - Q.push_back(vv); - D[vv] = 0; - - std::size_t current_index = 0; - int dist_v; - while (current_index < Q.size() && (dist_v = D[Q[current_index]]) < k) - { - vv = Q[current_index++]; - BOOST_FOREACH(halfedge_descriptor he, - halfedges_around_target(halfedge(vv,m), m)) - { - vertex_descriptor new_v = source(he, m); - if (D.insert(std::make_pair(new_v, dist_v + 1)).second) { - Q.push_back(new_v); - } - } - } - return Q; -} - -std::set k_ring(vertex_descriptor v, - int k, - const Mesh& m) -{ - std::vector vring - = extract_k_ring(v, k - 1, m); - - std::set kring; - BOOST_FOREACH(vertex_descriptor vd, vring) - { - BOOST_FOREACH(face_descriptor f, - faces_around_target(halfedge(vd, m), m)) - { - if (f == boost::graph_traits::null_face()) - continue; - if (kring.find(f) == kring.end()) - kring.insert(f); - } - } - return kring; -} - -std::set collect_patch(const char* file, - const Mesh& m) -{ - std::set patch; std::ifstream in(file); if (!in.is_open()) - return patch; + return; std::string line; std::size_t id; - if (!std::getline(in, line)) { return patch; } + if (!std::getline(in, line)) { return ; } std::istringstream vertex_line(line); while (vertex_line >> id) { - if (id >= m.number_of_vertices()) { return patch; } + if (id >= m.number_of_vertices()) { return ; } //do nothing with vertices } - if (!std::getline(in, line)) { return patch; } + if (!std::getline(in, line)) { return ; } std::istringstream facet_line(line); while (facet_line >> id) { - if (id >= m.number_of_faces()) { return patch; } + if (id >= m.number_of_faces()) { return ; } patch.insert(Mesh::Face_index(Mesh::size_type(id))); } - if (!std::getline(in, line)) { return patch; } + if (!std::getline(in, line)) { return ; } std::istringstream edge_line(line); while (edge_line >> id) { - if (id >= m.number_of_edges()) { return patch; } + if (id >= m.number_of_edges()) { return ; } //do nothing with edges } in.close(); - return patch; } int main(int argc, char* argv[]) @@ -130,29 +80,13 @@ int main(int argc, char* argv[]) return 1; } - double target_edge_length = (argc > 2) ? atof(argv[2]) - : 0.079; - unsigned int nb_iter = (argc > 3) ? atoi(argv[3]) - : 1; - - unsigned int center_id = 26; - unsigned int i = 0; - vertex_descriptor patch_center; - BOOST_FOREACH(vertex_descriptor v, vertices(m)) - { - if (i++ == center_id) - { - patch_center = v; - break; - } - } - + double target_edge_length = (argc > 2) ? atof(argv[2]) : 0.079; + unsigned int nb_iter = (argc > 3) ? atoi(argv[3]) : 1; const char* selection_file = (argc > 4) ? argv[4] : "data/joint-patch.selection.txt"; - const std::set& pre_patch = - (argc > 4) - ? collect_patch(selection_file, m) - : k_ring(patch_center, 3, m); + + std::set pre_patch; + collect_patch(selection_file, m, pre_patch); std::cout << "Test self intersections..."; std::vector > facets; @@ -179,10 +113,6 @@ int main(int argc, char* argv[]) std::copy(pre_patch.begin(), pre_patch.end(), std::inserter(patch, patch.begin())); - //PMP::connected_component(face(border.front(), m), - // m, - // std::inserter(patch, patch.begin())); - std::cout << "Start remeshing of " << selection_file << " (" << patch.size() << " faces)..." << std::endl; From 9b0cd59255a0fef4a53f1de9994dc7767ea0e1d8 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 30 Jun 2015 12:20:02 +0200 Subject: [PATCH 114/217] add debugging code --- .../internal/remesh_impl.h | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 973ff78b4cc..82eb9fe17be 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -149,6 +149,12 @@ namespace internal { , const EdgeIsConstrainedMap& ecmap) { tag_halfedges_status(face_range, ecmap); + +#ifdef CGAL_PMP_REMESHING_EXPENSIVE_DEBUG + BOOST_FOREACH(vertex_descriptor v, vertices(mesh_)) + debug_normals(v); +#endif + } // split edges of edge_range that have their length > high @@ -360,6 +366,10 @@ namespace internal { debug_status_map(); debug_self_intersections(); #endif +#ifdef CGAL_PMP_REMESHING_EXPENSIVE_DEBUG + BOOST_FOREACH(vertex_descriptor v, vertices(mesh_)) + debug_normals(v); +#endif #ifdef CGAL_DUMP_REMESHING_STEPS dump("1-edge_split.off"); @@ -956,7 +966,8 @@ namespace internal { halfedge_descriptor h = halfedge(e, mesh_); if (halfedge_status_map_[h] == PATCH) halfedge_status_map_[h] = PATCH_BORDER; - halfedge_descriptor hopp = opposite(halfedge(e, mesh_), mesh_); + + halfedge_descriptor hopp = opposite(h, mesh_); if (halfedge_status_map_[hopp] == PATCH) halfedge_status_map_[hopp] = PATCH_BORDER; } @@ -1195,14 +1206,20 @@ namespace internal { void debug_status_map() const { + unsigned int nb_border = 0; + unsigned int nb_mesh = 0; + unsigned int nb_patch = 0; + unsigned int nb_patch_border = 0; + typedef typename std::map::value_type HD_pair; BOOST_FOREACH(const HD_pair& hs, halfedge_status_map_) { - bool b1 = is_on_patch(hs.first); - bool b2 = is_on_patch_border(hs.first); - bool b3 = is_on_mesh(hs.first); - bool b4 = is_on_border(hs.first); + if(is_on_patch(hs.first)) nb_patch++; + else if(is_on_patch_border(hs.first)) nb_patch_border++; + else if(is_on_mesh(hs.first)) nb_mesh++; + else if(is_on_border(hs.first)) nb_border++; + else CGAL_assertion(false); } } From fdf53b2e47c68f4dcef93d50c0624a4093b5260b Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 30 Jun 2015 15:49:29 +0200 Subject: [PATCH 115/217] comment verbose mode macro --- .../Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp index f53ffb0e23b..35973d42021 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp @@ -1,4 +1,4 @@ -#define CGAL_PMP_REMESHING_VERBOSE +//#define CGAL_PMP_REMESHING_VERBOSE //#define CGAL_PMP_REMESHING_DEBUG //#define CGAL_PMP_REMESHING_VERY_VERBOSE From 45b1f593fcacdf075fdbbef8559ea69c2ede9816 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 13 Jul 2015 11:01:52 +0200 Subject: [PATCH 116/217] protect debug function by debug macro --- .../include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 82eb9fe17be..2c71c2ea925 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -1223,6 +1223,7 @@ namespace internal { } } +#ifdef CGAL_PMP_REMESHING_DEBUG void debug_self_intersections() const { std::cout << "Test self intersections..."; @@ -1247,6 +1248,7 @@ namespace internal { CGAL_assertion(facets.empty()); std::cout << "done." << std::endl; } +#endif void debug_normals(const vertex_descriptor& v) const { From b5cf4426535941967f5e7a2227a151afd859ec45 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 24 Jul 2015 10:05:02 +0200 Subject: [PATCH 117/217] make plugins valid for Qt5 --- .../internal/named_function_params.h | 14 +++--- Polyhedron/demo/Polyhedron/CMakeLists.txt | 2 +- ...yhedron_demo_detect_sharp_edges_plugin.cpp | 4 +- ...hedron_demo_isotropic_remeshing_plugin.cpp | 6 ++- .../demo/Polyhedron/Scene_polyhedron_item.cpp | 43 +++++++++++++------ .../Scene_polyhedron_selection_item.h | 23 ++++------ 6 files changed, 55 insertions(+), 37 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/named_function_params.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/named_function_params.h index 43c9161eabe..752827eb97d 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/named_function_params.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/named_function_params.h @@ -131,10 +131,11 @@ namespace CGAL{ return Params(n, *this); } - pmp_bgl_named_params - protect_constraints(const bool& b) const + template + pmp_bgl_named_params + protect_constraints(const Boolean b) const { - typedef pmp_bgl_named_params Params; + typedef pmp_bgl_named_params Params; return Params(b, *this); } @@ -260,10 +261,11 @@ namespace parameters{ return Params(n); } - pmp_bgl_named_params - protect_constraints(const bool& b) + template + pmp_bgl_named_params + protect_constraints(const Boolean b) { - typedef pmp_bgl_named_params Params; + typedef pmp_bgl_named_params Params; return Params(b); } diff --git a/Polyhedron/demo/Polyhedron/CMakeLists.txt b/Polyhedron/demo/Polyhedron/CMakeLists.txt index 341592c3a38..4c497ee3d9c 100644 --- a/Polyhedron/demo/Polyhedron/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/CMakeLists.txt @@ -89,7 +89,7 @@ if(CGAL_Qt5_FOUND AND Qt5_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND) qt5_wrap_ui( Mean_curvature_flow_skeleton_pluginUI_FILES Mean_curvature_flow_skeleton_plugin.ui) qt5_wrap_ui( meshingUI_FILES Meshing_dialog.ui ) qt5_wrap_ui( cameraUI_FILES Camera_positions_list.ui ) - qt4_wrap_ui( isotropicRemeshingUI_FILES Polyhedron_demo_isotropic_remeshing_dialog.ui) + qt5_wrap_ui( isotropicRemeshingUI_FILES Polyhedron_demo_isotropic_remeshing_dialog.ui) qt5_wrap_ui( PreferencesUI_FILES Preferences.ui ) qt5_wrap_ui( point_inside_polyhedronUI_FILES Point_inside_polyhedron_widget.ui) qt5_wrap_ui( polyhedron_slicerUI_FILES Polyhedron_slicer_widget.ui) diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_detect_sharp_edges_plugin.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_detect_sharp_edges_plugin.cpp index 386799bfb7a..3cabdc34699 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_demo_detect_sharp_edges_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_detect_sharp_edges_plugin.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "Scene_polyhedron_item.h" #include "Scene_polygon_soup_item.h" @@ -18,6 +19,7 @@ class Polyhedron_demo_detect_sharp_edges_plugin : { Q_OBJECT Q_INTERFACES(Polyhedron_demo_plugin_interface) + Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.PluginInterface/1.0") public: void init(QMainWindow* mainWindow, Scene_interface* scene_interface) { @@ -114,6 +116,6 @@ void Polyhedron_demo_detect_sharp_edges_plugin::detectSharpEdges(bool input_dial QApplication::restoreOverrideCursor(); } -Q_EXPORT_PLUGIN2(Polyhedron_demo_detect_sharp_edges_plugin, Polyhedron_demo_detect_sharp_edges_plugin) +//Q_EXPORT_PLUGIN2(Polyhedron_demo_detect_sharp_edges_plugin, Polyhedron_demo_detect_sharp_edges_plugin) #include "Polyhedron_demo_detect_sharp_edges_plugin.moc" diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp index 35973d42021..1587a8751aa 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -33,6 +34,7 @@ class Polyhedron_demo_isotropic_remeshing_plugin : { Q_OBJECT Q_INTERFACES(Polyhedron_demo_plugin_interface) + Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.PluginInterface/1.0") public: void init(QMainWindow* mainWindow, Scene_interface* scene_interface) @@ -236,7 +238,7 @@ private: }; // end Polyhedron_demo_isotropic_remeshing_plugin -Q_EXPORT_PLUGIN2(Polyhedron_demo_isotropic_remeshing_plugin, - Polyhedron_demo_isotropic_remeshing_plugin) +//Q_EXPORT_PLUGIN2(Polyhedron_demo_isotropic_remeshing_plugin, +// Polyhedron_demo_isotropic_remeshing_plugin) #include "Polyhedron_demo_isotropic_remeshing_plugin.moc" diff --git a/Polyhedron/demo/Polyhedron/Scene_polyhedron_item.cpp b/Polyhedron/demo/Polyhedron/Scene_polyhedron_item.cpp index 4a3cd950a16..1285274f193 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polyhedron_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_polyhedron_item.cpp @@ -636,11 +636,11 @@ Scene_polyhedron_item::Scene_polyhedron_item() : Scene_item(10,4), is_Triangle(true), poly(new Polyhedron), - show_only_feature_edges_m(false), - show_feature_edges_m(false), - facet_picking_m(false), - erase_next_picked_facet_m(false), - plugin_has_set_color_vector_m(false) + show_only_feature_edges_m(false), + show_feature_edges_m(false), + facet_picking_m(false), + erase_next_picked_facet_m(false), + plugin_has_set_color_vector_m(false) { cur_shading=FlatPlusEdges; is_selected = true; @@ -653,6 +653,7 @@ Scene_polyhedron_item::Scene_polyhedron_item(Polyhedron* const p) is_Triangle(true), poly(p), show_only_feature_edges_m(false), + show_feature_edges_m(false), facet_picking_m(false), erase_next_picked_facet_m(false), plugin_has_set_color_vector_m(false) @@ -668,6 +669,7 @@ Scene_polyhedron_item::Scene_polyhedron_item(const Polyhedron& p) is_Triangle(true), poly(new Polyhedron(p)), show_only_feature_edges_m(false), + show_feature_edges_m(false), facet_picking_m(false), erase_next_picked_facet_m(false), plugin_has_set_color_vector_m(false) @@ -891,14 +893,25 @@ void Scene_polyhedron_item::draw(Viewer_interface* viewer) const { } // Points/Wireframe/Flat/Gouraud OpenGL drawing in a display list -void Scene_polyhedron_item::draw_edges(Viewer_interface* viewer) const { +void Scene_polyhedron_item::draw_edges(Viewer_interface* viewer) const +{ + typedef Kernel::Point_3 Point; + typedef Polyhedron::Edge_iterator Edge_iterator; - if(!is_selected) - { - vaos[1]->bind(); + ::glBegin(GL_LINES); + Edge_iterator he; + if (!show_only_feature_edges_m) { + for (he = poly->edges_begin(); + he != poly->edges_end(); + he++) + { + if (he->is_feature_edge()) continue; + const Point& a = he->vertex()->point(); + const Point& b = he->opposite()->vertex()->point(); + ::glVertex3d(a.x(), a.y(), a.z()); + ::glVertex3d(b.x(), b.y(), b.z()); + } } - } - if (show_feature_edges_m) ::glColor3d(1.0, 0.0, 0.0); for(he = poly->edges_begin(); @@ -911,7 +924,13 @@ void Scene_polyhedron_item::draw_edges(Viewer_interface* viewer) const { ::glVertex3d(a.x(),a.y(),a.z()); ::glVertex3d(b.x(),b.y(),b.z()); } - else + ::glEnd(); + + if (!is_selected) + { + vaos[1]->bind(); + } + else { vaos[3]->bind(); } diff --git a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h index e2b9775f2ec..f488c1ac522 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h +++ b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h @@ -256,18 +256,11 @@ public: } // drawing - void draw() const { - draw_selected_vertices(); - draw_selected_facets(); - draw_selected_edges(); - } - void draw_edges() const { } - - using Scene_polyhedron_item_decorator::draw; - virtual void draw(Viewer_interface*) const; - virtual void draw_edges() const { } - virtual void draw_edges(Viewer_interface*) const; - virtual void draw_points(Viewer_interface*) const; + using Scene_polyhedron_item_decorator::draw; + virtual void draw(Viewer_interface*) const; + virtual void draw_edges() const { } + virtual void draw_edges(Viewer_interface*) const; + virtual void draw_points(Viewer_interface*) const; bool supportsRenderingMode(RenderingMode m) const { return (m==Flat); } @@ -761,13 +754,13 @@ protected: Selection_traits tr(this); bool any_change = false; - if (is_insert) { + if(is_insert) { BOOST_FOREACH(HandleType h, selection) any_change |= tr.container().insert(h).second; } else{ BOOST_FOREACH(HandleType h, selection) - any_change |= (tr.container().erase(h) != 0); + any_change |= (tr.container().erase(h)!=0); } return any_change; } @@ -818,7 +811,7 @@ public: selected_edges_pmap(std::vector& mark) { Selection_traits tr(this); + Scene_polyhedron_selection_item> tr(this); tr.update_indices(); for (unsigned int i = 0; i < mark.size(); ++i) From 87759f9ca819ed9173fbd582a6f41351d3b3dcd8 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 24 Jul 2015 12:09:04 +0200 Subject: [PATCH 118/217] use get() instead of operator[] for vertex point map --- .../include/CGAL/Polygon_mesh_processing/compute_normal.h | 6 +++--- .../CGAL/Polygon_mesh_processing/internal/remesh_impl.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/compute_normal.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/compute_normal.h index f85400054d6..d2ffc2b40e5 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/compute_normal.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/compute_normal.h @@ -47,9 +47,9 @@ void sum_normals(const PM& pmesh, halfedge_descriptor end = he; do { - const Point& prv = vpmap[target(prev(he, pmesh), pmesh)]; - const Point& curr = vpmap[target(he, pmesh)]; - const Point& nxt = vpmap[target(next(he, pmesh), pmesh)]; + const Point& prv = get(vpmap, target(prev(he, pmesh), pmesh)); + const Point& curr = get(vpmap, target(he, pmesh)); + const Point& nxt = get(vpmap, target(next(he, pmesh), pmesh)); Vector n = CGAL::cross_product(nxt - curr, prv - curr); sum = sum + n; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 2c71c2ea925..992f4f90413 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -1032,8 +1032,8 @@ namespace internal { vertex_descriptor vc = target(hf, mesh_); vertex_descriptor va = target(next(hf, mesh_), mesh_); vertex_descriptor vb = target(next(next(hf, mesh_), mesh_), mesh_); - Vector_3 ab(vpmap_[va], vpmap_[vb]); - Vector_3 ac(vpmap_[va], vpmap_[vc]); + Vector_3 ab(get(vpmap_,va), get(vpmap_,vb)); + Vector_3 ac(get(vpmap_,va), get(vpmap_,vc)); if (ab * ac < 0) { halfedge_descriptor hfo = opposite(hf, mesh_); From b8d81cb8f6f2e82c21e2d2b29a070e2921c6ed8c Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 24 Jul 2015 12:09:50 +0200 Subject: [PATCH 119/217] add todo --- .../include/CGAL/Polygon_mesh_processing/remesh.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h index 1878aeb6391..b1408b00f34 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h @@ -71,6 +71,7 @@ namespace Polygon_mesh_processing { * *@todo we suppose `faces` describe only one patch. Handle several patches. *@todo document `number_of_iterations` +*@todo add possibility to provide a functor that projects to a prescribed surface */ template Date: Fri, 24 Jul 2015 12:23:32 +0200 Subject: [PATCH 120/217] fix the use of does_self_intersect --- .../include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h | 1 - 1 file changed, 1 deletion(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 992f4f90413..f6c1ed16c73 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -1230,7 +1230,6 @@ namespace internal { std::vector > facets; PMP::does_self_intersect( mesh_, - std::back_inserter(facets), PMP::parameters::vertex_point_map(vpmap_)); CGAL_assertion(facets.empty()); std::cout << "done." << std::endl; From c37ed37c4c79a8cc326a705bfb841cc89c3c08eb Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 24 Jul 2015 12:31:50 +0200 Subject: [PATCH 121/217] use get() instead of [] to access vertex point map --- .../self_intersections.h | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/self_intersections.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/self_intersections.h index 47c281b3f4e..9fc381ae2c0 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/self_intersections.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/self_intersections.h @@ -142,17 +142,17 @@ struct Intersect_facets // found shared vertex: CGAL_assertion(target(h,m_tmesh) == target(v,m_tmesh)); // geometric check if the opposite segments intersect the triangles - Triangle t1 = triangle_functor( m_vpmap[target(h,m_tmesh)], - m_vpmap[target(next(h,m_tmesh),m_tmesh)], - m_vpmap[target(next(next(h,m_tmesh),m_tmesh),m_tmesh)]); - Triangle t2 = triangle_functor( m_vpmap[target(v,m_tmesh)], - m_vpmap[target(next(v,m_tmesh),m_tmesh)], - m_vpmap[target(next(next(v,m_tmesh),m_tmesh),m_tmesh)]); + Triangle t1 = triangle_functor( get(m_vpmap,target(h,m_tmesh)), + get(m_vpmap, target(next(h,m_tmesh),m_tmesh)), + get(m_vpmap, target(next(next(h,m_tmesh),m_tmesh),m_tmesh))); + Triangle t2 = triangle_functor( get(m_vpmap, target(v,m_tmesh)), + get(m_vpmap, target(next(v,m_tmesh),m_tmesh)), + get(m_vpmap, target(next(next(v,m_tmesh),m_tmesh),m_tmesh))); - Segment s1 = segment_functor( m_vpmap[target(next(h,m_tmesh),m_tmesh)], - m_vpmap[target(next(next(h,m_tmesh),m_tmesh),m_tmesh)]); - Segment s2 = segment_functor( m_vpmap[target(next(v,m_tmesh),m_tmesh)], - m_vpmap[target(next(next(v,m_tmesh),m_tmesh),m_tmesh)]); + Segment s1 = segment_functor( get(m_vpmap, target(next(h,m_tmesh),m_tmesh)), + get(m_vpmap, target(next(next(h,m_tmesh),m_tmesh),m_tmesh))); + Segment s2 = segment_functor( get(m_vpmap, target(next(v,m_tmesh),m_tmesh)), + get(m_vpmap, target(next(next(v,m_tmesh),m_tmesh),m_tmesh))); if(do_intersect_3_functor(t1,s2)){ *m_iterator_wrapper++ = std::make_pair(b->info(), c->info()); @@ -163,12 +163,12 @@ struct Intersect_facets } // check for geometric intersection - Triangle t1 = triangle_functor( m_vpmap[target(h,m_tmesh)], - m_vpmap[target(next(h,m_tmesh),m_tmesh)], - m_vpmap[target(next(next(h,m_tmesh),m_tmesh),m_tmesh)]); - Triangle t2 = triangle_functor( m_vpmap[target(g,m_tmesh)], - m_vpmap[target(next(g,m_tmesh),m_tmesh)], - m_vpmap[target(next(next(g,m_tmesh),m_tmesh),m_tmesh)]); + Triangle t1 = triangle_functor( get(m_vpmap, target(h,m_tmesh)), + get(m_vpmap, target(next(h,m_tmesh),m_tmesh)), + get(m_vpmap, target(next(next(h,m_tmesh),m_tmesh),m_tmesh))); + Triangle t2 = triangle_functor( get(m_vpmap, target(g,m_tmesh)), + get(m_vpmap, target(next(g,m_tmesh),m_tmesh)), + get(m_vpmap, target(next(next(g,m_tmesh),m_tmesh),m_tmesh))); if(do_intersect_3_functor(t1, t2)){ *m_iterator_wrapper++ = std::make_pair(b->info(), c->info()); } @@ -312,9 +312,9 @@ self_intersections( const FaceRange& face_range, BOOST_FOREACH(face_descriptor f, face_range) { - boxes.push_back(Box( vpmap[target(halfedge(f,tmesh),tmesh)].bbox() - + vpmap[target(next(halfedge(f, tmesh), tmesh), tmesh)].bbox() - + vpmap[target(next(next(halfedge(f, tmesh), tmesh), tmesh), tmesh)].bbox(), + boxes.push_back(Box( get(vpmap, target(halfedge(f,tmesh),tmesh)).bbox() + + get(vpmap, target(next(halfedge(f, tmesh), tmesh), tmesh)).bbox() + + get(vpmap, target(next(next(halfedge(f, tmesh), tmesh), tmesh), tmesh)).bbox(), f)); } // generate box pointers From 98fecc9a1252637a677ad458886fe2b5433a819f Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 24 Jul 2015 12:33:27 +0200 Subject: [PATCH 122/217] fix documentation this template parameter is not needed! --- .../include/CGAL/Polygon_mesh_processing/self_intersections.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/self_intersections.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/self_intersections.h index 9fc381ae2c0..528b21c468c 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/self_intersections.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/self_intersections.h @@ -357,8 +357,6 @@ OutputIterator self_intersections(const FaceRange& face_range, * * @tparam TriangleMesh a model of `FaceListGraph` that has an internal property map * for `CGAL::vertex_point_t` - * @tparam OutputIterator a model of `OutputIterator` holding objects of type - * `std::pair::%face_descriptor, boost::graph_traits::%face_descriptor>` * @tparam NamedParameters a sequence of \ref namedparameters * * @param tmesh the triangulated surface mesh to be tested From 8e94e438ffa2a65ce95b159caab3cddc207a4566 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 24 Jul 2015 16:12:22 +0200 Subject: [PATCH 123/217] introduce remeshing that happens after deformation (1st shot : update of display is broken for now) --- Polyhedron/demo/Polyhedron/Deform_mesh.ui | 33 ++++- .../Polyhedron/Scene_edit_polyhedron_item.cpp | 124 +++++++++++++----- .../Polyhedron/Scene_edit_polyhedron_item.h | 31 +++-- 3 files changed, 148 insertions(+), 40 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Deform_mesh.ui b/Polyhedron/demo/Polyhedron/Deform_mesh.ui index 72f24642fe4..9eea6307818 100644 --- a/Polyhedron/demo/Polyhedron/Deform_mesh.ui +++ b/Polyhedron/demo/Polyhedron/Deform_mesh.ui @@ -6,8 +6,8 @@ 0 0 - 357 - 491 + 438 + 732 @@ -178,6 +178,35 @@ + + + + Qt::DefaultContextMenu + + + Remeshing + + + false + + + + + + + + Qt::LeftToRight + + + Remesh after deformation + + + + + + + + diff --git a/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.cpp b/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.cpp index eeb7137985a..a7c7f13520f 100644 --- a/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.cpp @@ -1,3 +1,5 @@ +#define CGAL_PMP_REMESHING_VERBOSE + #include "opengl_tools.h" #include "Scene_edit_polyhedron_item.h" #include @@ -55,36 +57,8 @@ Scene_edit_polyhedron_item::Scene_edit_polyhedron_item startTimer(0); // Required for drawing functionality - positions.resize(num_vertices(*polyhedron())*3); - normals.resize(positions.size()); - Polyhedron::Vertex_iterator vb, ve; - std::size_t counter = 0; - for(vb=polyhedron()->vertices_begin(), ve = polyhedron()->vertices_end();vb != ve; ++vb, ++counter) { - positions[counter*3] = vb->point().x(); - positions[counter*3+1] = vb->point().y(); - positions[counter*3+2] = vb->point().z(); + reset_drawing_data(); - const Polyhedron::Traits::Vector_3& n = - CGAL::Polygon_mesh_processing::compute_vertex_normal(vb, deform_mesh.halfedge_graph()); - - normals[counter*3] = n.x(); - normals[counter*3+1] = n.y(); - normals[counter*3+2] = n.z(); - } - tris.resize(polyhedron()->size_of_facets()*3); - counter = 0; - for(Polyhedron::Facet_handle fb = polyhedron()->facets_begin(); fb != polyhedron()->facets_end(); ++fb, ++counter) { - tris[counter*3] = static_cast(fb->halfedge()->vertex()->id()); - tris[counter*3+1] = static_cast(fb->halfedge()->next()->vertex()->id()); - tris[counter*3+2] = static_cast(fb->halfedge()->prev()->vertex()->id()); - } - - edges.resize(polyhedron()->size_of_halfedges()); - counter = 0; - for(Polyhedron::Edge_iterator eb = polyhedron()->edges_begin(); eb != polyhedron()->edges_end(); ++eb, ++counter) { - edges[counter*2] = static_cast(eb->vertex()->id()); - edges[counter*2+1] = static_cast(eb->opposite()->vertex()->id()); - } qFunc.initializeOpenGLFunctions(); //Generates an integer which will be used as ID for each buffer @@ -343,6 +317,52 @@ void Scene_edit_polyhedron_item::initialize_buffers(Viewer_interface *viewer =0) are_buffers_filled = true; } +void Scene_edit_polyhedron_item::reset_drawing_data() +{ + positions.clear(); + positions.resize(num_vertices(*polyhedron()) * 3); + + normals.clear(); + normals.resize(positions.size()); + + std::size_t counter = 0; + BOOST_FOREACH(vertex_descriptor vb, vertices(*polyhedron())) + { + positions[counter * 3] = vb->point().x(); + positions[counter * 3 + 1] = vb->point().y(); + positions[counter * 3 + 2] = vb->point().z(); + + const Polyhedron::Traits::Vector_3& n = + CGAL::Polygon_mesh_processing::compute_vertex_normal(vb, deform_mesh.halfedge_graph()); + normals[counter * 3] = n.x(); + normals[counter * 3 + 1] = n.y(); + normals[counter * 3 + 2] = n.z(); + + ++counter; + } + + tris.clear(); + tris.resize(polyhedron()->size_of_facets() * 3); + counter = 0; + BOOST_FOREACH(face_descriptor fb, faces(*polyhedron())) + { + tris[counter * 3] = static_cast(fb->halfedge()->vertex()->id()); + tris[counter * 3 + 1] = static_cast(fb->halfedge()->next()->vertex()->id()); + tris[counter * 3 + 2] = static_cast(fb->halfedge()->prev()->vertex()->id()); + ++counter; + } + + edges.clear(); + edges.resize(polyhedron()->size_of_halfedges()); + counter = 0; + for (Polyhedron::Edge_iterator eb = polyhedron()->edges_begin(); + eb != polyhedron()->edges_end(); ++eb, ++counter) + { + edges[counter * 2] = static_cast(eb->vertex()->id()); + edges[counter * 2 + 1] = static_cast(eb->opposite()->vertex()->id()); + } +} + void Scene_edit_polyhedron_item::compute_normals_and_vertices(void) { ROI_points.resize(0); @@ -467,6 +487,46 @@ void Scene_edit_polyhedron_item::deform() Q_EMIT itemChanged(); } +void Scene_edit_polyhedron_item::remesh() +{ + const Polyhedron& g = deform_mesh.halfedge_graph(); + Array_based_vertex_point_map vpmap(&positions); + + unsigned int nb_iter = 1; + double min_sqlen = bbox().diagonal_length(); + + std::set roi_facets; + std::set roi_halfedges; + BOOST_FOREACH(vertex_descriptor v, deform_mesh.roi_vertices()) + { + BOOST_FOREACH(face_descriptor fv, CGAL::faces_around_target(halfedge(v, g), g)) + { + roi_facets.insert(fv); + BOOST_FOREACH(halfedge_descriptor h, CGAL::halfedges_around_face(halfedge(fv, g), g)) + { + if (roi_halfedges.find(opposite(h, g)) != roi_halfedges.end()) //already computed + continue; + min_sqlen = (std::min)(min_sqlen, + CGAL::squared_distance(get(vpmap, source(h, g)), get(vpmap, target(h, g)))); + roi_halfedges.insert(h); + } + } + } + + double target_length = CGAL::sqrt(min_sqlen); + + CGAL::Polygon_mesh_processing::incremental_triangle_based_remeshing( + *polyhedron() + , roi_facets + , target_length + , CGAL::Polygon_mesh_processing::parameters::number_of_iterations(nb_iter) + .protect_constraints(false) //no edge_is_constrained_map + .vertex_point_map(vpmap) + ); + + reset_drawing_data(); +} + void Scene_edit_polyhedron_item::timerEvent(QTimerEvent* /*event*/) { // just handle deformation - paint like selection is handled in eventFilter() if(state.ctrl_pressing && (state.left_button_pressing || state.right_button_pressing)) { @@ -511,12 +571,16 @@ bool Scene_edit_polyhedron_item::eventFilter(QObject* /*target*/, QEvent *event) // check state changes between old and current state bool ctrl_pressed_now = state.ctrl_pressing && !old_state.ctrl_pressing; bool ctrl_released_now = !state.ctrl_pressing && old_state.ctrl_pressing; - if(ctrl_pressed_now || ctrl_released_now || event->type() == QEvent::HoverMove) + if(ctrl_pressed_now || ctrl_released_now || event->type() == QEvent::HoverMove) {// activate a handle manipulated frame QGLViewer* viewer = *QGLViewer::QGLViewerPool().begin(); const QPoint& p = viewer->mapFromGlobal(QCursor::pos()); bool need_repaint = activate_closest_manipulated_frame(p.x(), p.y()); + if (ctrl_released_now && ui_widget->RemeshingCheckBox->isChecked()){ + remesh(); + } + if(need_repaint) { Q_EMIT itemChanged(); } } diff --git a/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.h b/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.h index 72a4d4af6d2..e6fbc3ef19a 100644 --- a/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.h +++ b/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.h @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include @@ -19,7 +19,11 @@ #include #include "ui_Deform_mesh.h" + +#include #include +#include + #include #include #include @@ -29,15 +33,15 @@ typedef Polyhedron::Vertex_handle Vertex_handle; typedef boost::graph_traits::vertex_descriptor vertex_descriptor; typedef boost::graph_traits::vertex_iterator vertex_iterator; -typedef boost::graph_traits::in_edge_iterator in_edge_iterator; -typedef boost::graph_traits::out_edge_iterator out_edge_iterator; +typedef boost::graph_traits::face_descriptor face_descriptor; +typedef boost::graph_traits::halfedge_descriptor halfedge_descriptor; struct Array_based_vertex_point_map { public: typedef vertex_descriptor key_type; typedef Polyhedron::Traits::Point_3 value_type; - typedef value_type& reference; + typedef value_type& reference; typedef boost::read_write_property_map_tag category; Array_based_vertex_point_map(std::vector* positions) : positions(positions) {} std::vector* positions; @@ -55,14 +59,25 @@ inline void put(Array_based_vertex_point_map pmap, Array_based_vertex_point_map::key_type key, - Array_based_vertex_point_map::value_type val) { + Array_based_vertex_point_map::value_type val) +{ key->point() = val; // to make things easy (ray selection after deformation, save to polyhedron after close etc), // I also change point() of vertex together with positions list // So that we do not need to pmap everywhere other than draw + if (key->id() == -1) + { + key->id() = pmap.positions->size() / 3; + pmap.positions->push_back(val.x()); + pmap.positions->push_back(val.y()); + pmap.positions->push_back(val.z()); + } + else + { std::size_t pos = key->id() * 3; (*pmap.positions)[pos] = val.x(); (*pmap.positions)[pos+1] = val.y(); (*pmap.positions)[pos+2] = val.z(); + } } typedef CGAL::Surface_mesh_deformation Ctrl_vertices_group_data_list; From 75863ea8bb116eca57a57d88874d74a1601ce84c Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Mon, 27 Jul 2015 12:27:27 +0200 Subject: [PATCH 124/217] add (undocumented) function to reset the halfedge graph to be deformed --- .../include/CGAL/Surface_mesh_deformation.h | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Surface_modeling/include/CGAL/Surface_mesh_deformation.h b/Surface_modeling/include/CGAL/Surface_mesh_deformation.h index 997fb597370..19881110da4 100644 --- a/Surface_modeling/include/CGAL/Surface_mesh_deformation.h +++ b/Surface_modeling/include/CGAL/Surface_mesh_deformation.h @@ -380,6 +380,28 @@ private: #endif } + +public: +#ifndef DOXYGEN_RUNNING + void reinit(Halfedge_graph& g) + { + m_halfedge_graph = g; + + ros_id_map.resize(num_vertices(g), (std::numeric_limits::max)()); + is_roi_map.resize(num_vertices(g), false); + is_ctrl_map.resize(num_vertices(g), false); + m_iterations = 5; + m_tolerance = 1e-4; + need_preprocess_factorization = true; + need_preprocess_region_of_solution = true; + last_preprocess_successful = false; + //unchanged: + //vertex_index_map, hedge_index_map, vertex_point_map, weight_calculator + + init(); + } +#endif + public: /// \name Preprocessing From 7c8f0f93f2c4047d920c652bb9a25091ab5cc9e8 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Mon, 27 Jul 2015 12:28:43 +0200 Subject: [PATCH 125/217] fix display of polyhedron after being remeshed --- .../Polyhedron/Scene_edit_polyhedron_item.cpp | 45 ++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.cpp b/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.cpp index a7c7f13520f..eca8c626079 100644 --- a/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.cpp @@ -1,4 +1,4 @@ -#define CGAL_PMP_REMESHING_VERBOSE +//#define CGAL_PMP_REMESHING_VERBOSE #include "opengl_tools.h" #include "Scene_edit_polyhedron_item.h" @@ -513,8 +513,16 @@ void Scene_edit_polyhedron_item::remesh() } } + std::vector roi_border; + BOOST_FOREACH(halfedge_descriptor h, roi_halfedges) + { + if (roi_halfedges.find(opposite(h, g)) == roi_halfedges.end()) + roi_border.push_back(opposite(h, g)); + } + double target_length = CGAL::sqrt(min_sqlen); + std::cout << "Remeshing..."; CGAL::Polygon_mesh_processing::incremental_triangle_based_remeshing( *polyhedron() , roi_facets @@ -523,8 +531,43 @@ void Scene_edit_polyhedron_item::remesh() .protect_constraints(false) //no edge_is_constrained_map .vertex_point_map(vpmap) ); + std::cout << "done." << std::endl; + + //reset ROI from its outside border roi_border + clear_roi(); + delete_ctrl_vertices_group(); + + //std::list visitor; + //visitor.push_back(opposite(roi_border[0], g), g); + //do + //{ + // halfedge_descriptor h = visitor.front(); + // visitor.pop_front(); + + // BOOST_FOREACH(halfedge_descriptor hf, halfedges_around_face(h, g)) + // { + // halfedge_descriptor hfopp = opposite(hf, g); + // face_descriptor fopp = face(hfopp, g); + + // if (roi_border.find(hfopp) == roi_border.end() + // && roi_facets.find(fopp) == roi_facets.end()) + // { + // deform_mesh.insert_roi_vertex();// + // visitor.insert(hfopp); + // } + // } + //} + //while (!visitor.empty()); + + poly_item->update_vertex_indices(); + poly_item->update_halfedge_indices(); + deform_mesh.reinit(*(poly_item->polyhedron())), reset_drawing_data(); + compute_normals_and_vertices(); + + poly_item->changed(); // now we need to call poly_item changed to delete AABB tree + Q_EMIT itemChanged(); } void Scene_edit_polyhedron_item::timerEvent(QTimerEvent* /*event*/) From 97117a323f3a132fb5f20c861a665ebbd8399d89 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Mon, 27 Jul 2015 15:06:50 +0200 Subject: [PATCH 126/217] add options to set target edge length and nb iterations for remeshing --- Polyhedron/demo/Polyhedron/Deform_mesh.ui | 46 +++++++++++++++++-- .../Polyhedron/Scene_edit_polyhedron_item.cpp | 34 ++++++++++---- 2 files changed, 68 insertions(+), 12 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Deform_mesh.ui b/Polyhedron/demo/Polyhedron/Deform_mesh.ui index 9eea6307818..020429be10d 100644 --- a/Polyhedron/demo/Polyhedron/Deform_mesh.ui +++ b/Polyhedron/demo/Polyhedron/Deform_mesh.ui @@ -6,8 +6,8 @@ 0 0 - 438 - 732 + 442 + 762 @@ -191,7 +191,7 @@ - + @@ -202,6 +202,46 @@ + + + + + + If unchecked, automatic value is used (the average edge length at ROI boundary) + + + Qt::RightToLeft + + + Target edge length + + + + + + + Qt::RightToLeft + + + Nb. iterations + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + + + diff --git a/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.cpp b/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.cpp index eca8c626079..2d8636043e2 100644 --- a/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.cpp @@ -94,6 +94,14 @@ Scene_edit_polyhedron_item::Scene_edit_polyhedron_item bbox_program.addShaderFromSourceCode(QOpenGLShader::Fragment,fragment_shader_source); bbox_program.link(); + ui_widget->remeshing_iterations_spinbox->setValue(1); + + ui_widget->remeshing_edge_length_spinbox->setValue(length_of_axis); + ui_widget->remeshing_edge_length_spinbox->setDisabled(true); + ui_widget->remeshingEdgeLengthInput_checkBox->setChecked(false); + connect(ui_widget->remeshingEdgeLengthInput_checkBox, SIGNAL(toggled(bool)), + ui_widget->remeshing_edge_length_spinbox, SLOT(setEnabled(bool))); + //the spheres : create_Sphere(length_of_axis/15.0); changed(); @@ -492,9 +500,6 @@ void Scene_edit_polyhedron_item::remesh() const Polyhedron& g = deform_mesh.halfedge_graph(); Array_based_vertex_point_map vpmap(&positions); - unsigned int nb_iter = 1; - double min_sqlen = bbox().diagonal_length(); - std::set roi_facets; std::set roi_halfedges; BOOST_FOREACH(vertex_descriptor v, deform_mesh.roi_vertices()) @@ -504,23 +509,34 @@ void Scene_edit_polyhedron_item::remesh() roi_facets.insert(fv); BOOST_FOREACH(halfedge_descriptor h, CGAL::halfedges_around_face(halfedge(fv, g), g)) { - if (roi_halfedges.find(opposite(h, g)) != roi_halfedges.end()) //already computed - continue; - min_sqlen = (std::min)(min_sqlen, - CGAL::squared_distance(get(vpmap, source(h, g)), get(vpmap, target(h, g)))); - roi_halfedges.insert(h); + if (roi_halfedges.find(opposite(h, g)) == roi_halfedges.end()) //not already computed + roi_halfedges.insert(h); } } } + bool automatic_target_length = !ui_widget->remeshingEdgeLengthInput_checkBox->isChecked(); + double sum_len = 0.; std::vector roi_border; BOOST_FOREACH(halfedge_descriptor h, roi_halfedges) { if (roi_halfedges.find(opposite(h, g)) == roi_halfedges.end()) + { roi_border.push_back(opposite(h, g)); + if (automatic_target_length) + sum_len += CGAL::sqrt(CGAL::squared_distance( + get(vpmap, source(h, g)), get(vpmap, target(h, g)))); + } } - double target_length = CGAL::sqrt(min_sqlen); + if (roi_border.empty()) + automatic_target_length = false; + + double target_length = automatic_target_length + ? sum_len / (0. + roi_border.size()) + : ui_widget->remeshing_edge_length_spinbox->value(); + + unsigned int nb_iter = ui_widget->remeshing_iterations_spinbox->value(); std::cout << "Remeshing..."; CGAL::Polygon_mesh_processing::incremental_triangle_based_remeshing( From b19c69700d22ce469edcd3a622e52dfde6d53c80 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Mon, 27 Jul 2015 15:32:09 +0200 Subject: [PATCH 127/217] Revert "add (undocumented) function to reset the halfedge graph to be deformed" This reverts commit 75863ea8bb116eca57a57d88874d74a1601ce84c. --- .../include/CGAL/Surface_mesh_deformation.h | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/Surface_modeling/include/CGAL/Surface_mesh_deformation.h b/Surface_modeling/include/CGAL/Surface_mesh_deformation.h index 19881110da4..997fb597370 100644 --- a/Surface_modeling/include/CGAL/Surface_mesh_deformation.h +++ b/Surface_modeling/include/CGAL/Surface_mesh_deformation.h @@ -380,28 +380,6 @@ private: #endif } - -public: -#ifndef DOXYGEN_RUNNING - void reinit(Halfedge_graph& g) - { - m_halfedge_graph = g; - - ros_id_map.resize(num_vertices(g), (std::numeric_limits::max)()); - is_roi_map.resize(num_vertices(g), false); - is_ctrl_map.resize(num_vertices(g), false); - m_iterations = 5; - m_tolerance = 1e-4; - need_preprocess_factorization = true; - need_preprocess_region_of_solution = true; - last_preprocess_successful = false; - //unchanged: - //vertex_index_map, hedge_index_map, vertex_point_map, weight_calculator - - init(); - } -#endif - public: /// \name Preprocessing From d9d5a9edc3350fd71e492c56a377c29627ea38ec Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Mon, 27 Jul 2015 15:39:21 +0200 Subject: [PATCH 128/217] make deform_mesh a pointer we do this to make possible to update the polyhedron between a remeshing and a deformation step --- .../Polyhedron/Scene_edit_polyhedron_item.cpp | 31 +++++++++------ .../Polyhedron/Scene_edit_polyhedron_item.h | 38 +++++++++---------- 2 files changed, 39 insertions(+), 30 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.cpp b/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.cpp index 2d8636043e2..4bc0825a326 100644 --- a/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.cpp @@ -26,9 +26,8 @@ Scene_edit_polyhedron_item::Scene_edit_polyhedron_item Ui::DeformMesh* ui_widget, QMainWindow* mw) :Scene_item(20,8), - ui_widget(ui_widget), + ui_widget(ui_widget), poly_item(poly_item), - deform_mesh(*(poly_item->polyhedron()), Deform_mesh::Vertex_index_map(), Deform_mesh::Hedge_index_map(), Array_based_vertex_point_map(&positions)), is_rot_free(true), own_poly_item(true), k_ring_selector(poly_item, mw, Scene_polyhedron_item_k_ring_selection::Active_handle::VERTEX, true), @@ -43,6 +42,11 @@ Scene_edit_polyhedron_item::Scene_edit_polyhedron_item poly_item->set_color_vector_read_only(true); // to prevent recomputation of color vector in changed() poly_item->update_vertex_indices(); + deform_mesh = new Deform_mesh(*(poly_item->polyhedron()), + Deform_mesh::Vertex_index_map(), + Deform_mesh::Hedge_index_map(), + Array_based_vertex_point_map(&positions)); + length_of_axis = bbox().diagonal_length() / 15.0; // interleave events of viewer (there is only one viewer) @@ -114,8 +118,9 @@ Scene_edit_polyhedron_item::~Scene_edit_polyhedron_item() delete_ctrl_vertices_group(false); } gluDeleteQuadric(quadric); - if (own_poly_item) delete poly_item; + delete deform_mesh; + if (own_poly_item) delete poly_item; } ///////////////////////////// /// For the Shader gestion/// @@ -341,7 +346,7 @@ void Scene_edit_polyhedron_item::reset_drawing_data() positions[counter * 3 + 2] = vb->point().z(); const Polyhedron::Traits::Vector_3& n = - CGAL::Polygon_mesh_processing::compute_vertex_normal(vb, deform_mesh.halfedge_graph()); + CGAL::Polygon_mesh_processing::compute_vertex_normal(vb, deform_mesh->halfedge_graph()); normals[counter * 3] = n.x(); normals[counter * 3 + 1] = n.y(); normals[counter * 3 + 2] = n.z(); @@ -375,9 +380,9 @@ void Scene_edit_polyhedron_item::compute_normals_and_vertices(void) { ROI_points.resize(0); control_points.resize(0); - BOOST_FOREACH(vertex_descriptor vd, deform_mesh.roi_vertices()) + BOOST_FOREACH(vertex_descriptor vd, deform_mesh->roi_vertices()) { - if(!deform_mesh.is_control_vertex(vd)) + if(!deform_mesh->is_control_vertex(vd)) {//gl_draw_point( vd->point() ); ROI_points.push_back(vd->point().x()); ROI_points.push_back(vd->point().y()); @@ -489,7 +494,7 @@ void Scene_edit_polyhedron_item::deform() for(Ctrl_vertices_group_data_list::iterator it = ctrl_vertex_frame_map.begin(); it != ctrl_vertex_frame_map.end(); ++it) { it->set_target_positions(); } - deform_mesh.deform(); + deform_mesh->deform(); poly_item->changed(); // now we need to call poly_item changed to delete AABB tree Q_EMIT itemChanged(); @@ -497,12 +502,12 @@ void Scene_edit_polyhedron_item::deform() void Scene_edit_polyhedron_item::remesh() { - const Polyhedron& g = deform_mesh.halfedge_graph(); + const Polyhedron& g = deform_mesh->halfedge_graph(); Array_based_vertex_point_map vpmap(&positions); std::set roi_facets; std::set roi_halfedges; - BOOST_FOREACH(vertex_descriptor v, deform_mesh.roi_vertices()) + BOOST_FOREACH(vertex_descriptor v, deform_mesh->roi_vertices()) { BOOST_FOREACH(face_descriptor fv, CGAL::faces_around_target(halfedge(v, g), g)) { @@ -568,7 +573,7 @@ void Scene_edit_polyhedron_item::remesh() // if (roi_border.find(hfopp) == roi_border.end() // && roi_facets.find(fopp) == roi_facets.end()) // { - // deform_mesh.insert_roi_vertex();// + // deform_mesh->insert_roi_vertex();// // visitor.insert(hfopp); // } // } @@ -577,7 +582,11 @@ void Scene_edit_polyhedron_item::remesh() poly_item->update_vertex_indices(); poly_item->update_halfedge_indices(); - deform_mesh.reinit(*(poly_item->polyhedron())), + delete deform_mesh; + deform_mesh = new Deform_mesh(*(poly_item->polyhedron()), + Deform_mesh::Vertex_index_map(), + Deform_mesh::Hedge_index_map(), + vpmap); reset_drawing_data(); compute_normals_and_vertices(); diff --git a/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.h b/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.h index e6fbc3ef19a..5cb7799515a 100644 --- a/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.h +++ b/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.h @@ -313,7 +313,7 @@ private: void create_Sphere(double); void reset_drawing_data(); - Deform_mesh deform_mesh; + Deform_mesh* deform_mesh; typedef std::list Ctrl_vertices_group_data_list; Ctrl_vertices_group_data_list::iterator active_group; Ctrl_vertices_group_data_list ctrl_vertex_frame_map; // keep list of group of control vertices with assoc data @@ -339,7 +339,7 @@ public: return false; } // no group of control vertices to insert - bool inserted = deform_mesh.insert_control_vertex(v); + bool inserted = deform_mesh->insert_control_vertex(v); if(inserted) { active_group->ctrl_vertices_group.push_back(v); active_group->refresh(); @@ -349,12 +349,12 @@ public: bool insert_roi_vertex(vertex_descriptor v) { - return deform_mesh.insert_roi_vertex(v); + return deform_mesh->insert_roi_vertex(v); } bool erase_control_vertex(vertex_descriptor v) { - if(deform_mesh.erase_control_vertex(v)) // API should be safe enough to do that (without checking empty group of control vertices etc.) + if(deform_mesh->erase_control_vertex(v)) // API should be safe enough to do that (without checking empty group of control vertices etc.) { refresh_all_group_centers(); // since we don't know which group of control vertices v is erased from, refresh all return true; @@ -367,7 +367,7 @@ public: bool erase_roi_vertex(vertex_descriptor v) { erase_control_vertex(v); // erase control vertex - return deform_mesh.erase_roi_vertex(v); + return deform_mesh->erase_roi_vertex(v); } void set_all_vertices_as_roi() @@ -386,7 +386,7 @@ public: delete it->frame; } ctrl_vertex_frame_map.clear(); - deform_mesh.clear_roi_vertices(); + deform_mesh->clear_roi_vertices(); create_ctrl_vertices_group(); // create one new group of control vertices } @@ -404,7 +404,7 @@ public: qglviewer::ManipulatedFrame* new_frame = new qglviewer::ManipulatedFrame(); new_frame->setRotationSensitivity(2.0f); - Control_vertices_data hgd(&deform_mesh, new_frame); + Control_vertices_data hgd(deform_mesh, new_frame); ctrl_vertex_frame_map.push_back(hgd); hgd.refresh(); @@ -431,7 +431,7 @@ public: { delete it->frame; for(std::vector::iterator v_it = it->ctrl_vertices_group.begin(); v_it != it->ctrl_vertices_group.end(); ++v_it) { - deform_mesh.erase_control_vertex(*v_it); + deform_mesh->erase_control_vertex(*v_it); } ctrl_vertex_frame_map.erase(it); break; @@ -508,8 +508,8 @@ public: { std::ofstream out(file_name); // save roi - out << deform_mesh.roi_vertices().size() << std::endl; - BOOST_FOREACH(vertex_descriptor vd, deform_mesh.roi_vertices()) + out << deform_mesh->roi_vertices().size() << std::endl; + BOOST_FOREACH(vertex_descriptor vd, deform_mesh->roi_vertices()) { out << vd->id() << " "; } @@ -535,9 +535,9 @@ public: // put vertices to vector std::vector all_vertices; - all_vertices.reserve(num_vertices(deform_mesh.halfedge_graph())); + all_vertices.reserve(num_vertices(deform_mesh->halfedge_graph())); vertex_iterator vb, ve; - for(boost::tie(vb, ve) = vertices(deform_mesh.halfedge_graph()); vb != ve; ++vb) { + for(boost::tie(vb, ve) = vertices(deform_mesh->halfedge_graph()); vb != ve; ++vb) { all_vertices.push_back(*vb); } // read roi @@ -569,16 +569,16 @@ public: void overwrite_deform_object() { - deform_mesh.overwrite_initial_geometry(); + deform_mesh->overwrite_initial_geometry(); refresh_all_group_centers(); } struct Is_selected { - Deform_mesh& dm; - Is_selected(Deform_mesh& dm) : dm(dm) {} + Deform_mesh* dm; + Is_selected(Deform_mesh* dm) : dm(dm) {} bool count(Vertex_handle vh) const { - return dm.is_roi_vertex(vh); + return dm->is_roi_vertex(vh); } }; @@ -600,7 +600,7 @@ public: boost::optional select_isolated_components(std::size_t threshold) { typedef boost::function_output_iterator Output_iterator; - Output_iterator out(&deform_mesh); + Output_iterator out(deform_mesh); Travel_isolated_components::Selection_visitor visitor(threshold, out); Travel_isolated_components().travel @@ -700,11 +700,11 @@ protected: bool keyPressEvent(QKeyEvent* e); void update_normals() { - BOOST_FOREACH(vertex_descriptor vd, deform_mesh.roi_vertices()) + BOOST_FOREACH(vertex_descriptor vd, deform_mesh->roi_vertices()) { std::size_t id = vd->id(); const Polyhedron::Traits::Vector_3& n = - CGAL::Polygon_mesh_processing::compute_vertex_normal(vd, deform_mesh.halfedge_graph()); + CGAL::Polygon_mesh_processing::compute_vertex_normal(vd, deform_mesh->halfedge_graph()); normals[id*3] = n.x(); normals[id*3+1] = n.y(); normals[id*3+2] = n.z(); From 380f77002eacf2b3dfa264e1559c5d7038b09900 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Mon, 27 Jul 2015 15:57:22 +0200 Subject: [PATCH 129/217] add tooltip --- Polyhedron/demo/Polyhedron/Deform_mesh.ui | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Polyhedron/demo/Polyhedron/Deform_mesh.ui b/Polyhedron/demo/Polyhedron/Deform_mesh.ui index 020429be10d..4d20d7ebf91 100644 --- a/Polyhedron/demo/Polyhedron/Deform_mesh.ui +++ b/Polyhedron/demo/Polyhedron/Deform_mesh.ui @@ -194,6 +194,9 @@ + + Warning : after remeshing all ROI and control vertices will be unselected + Qt::LeftToRight From 21cf70af60233f5a1b2f13a84a4b5e9bea72ad0b Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Mon, 27 Jul 2015 16:05:08 +0200 Subject: [PATCH 130/217] remove commented draft --- .../Polyhedron/Scene_edit_polyhedron_item.cpp | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.cpp b/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.cpp index 4bc0825a326..fdc8c2be16b 100644 --- a/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.cpp @@ -558,28 +558,6 @@ void Scene_edit_polyhedron_item::remesh() clear_roi(); delete_ctrl_vertices_group(); - //std::list visitor; - //visitor.push_back(opposite(roi_border[0], g), g); - //do - //{ - // halfedge_descriptor h = visitor.front(); - // visitor.pop_front(); - - // BOOST_FOREACH(halfedge_descriptor hf, halfedges_around_face(h, g)) - // { - // halfedge_descriptor hfopp = opposite(hf, g); - // face_descriptor fopp = face(hfopp, g); - - // if (roi_border.find(hfopp) == roi_border.end() - // && roi_facets.find(fopp) == roi_facets.end()) - // { - // deform_mesh->insert_roi_vertex();// - // visitor.insert(hfopp); - // } - // } - //} - //while (!visitor.empty()); - poly_item->update_vertex_indices(); poly_item->update_halfedge_indices(); delete deform_mesh; From 14035ecac25a420660fc8e8c0d14ceb58c1dccd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 27 Jul 2015 18:40:39 +0200 Subject: [PATCH 131/217] add the possibility to constraint the movement of control vertices in a plane if you want to modify the plane constraint you need to use the "Activate pivoting" switch --- Polyhedron/demo/Polyhedron/Deform_mesh.ui | 23 +++++++++---- .../Polyhedron/Scene_edit_polyhedron_item.cpp | 32 +++++++++++++++++++ .../Polyhedron/Scene_edit_polyhedron_item.h | 26 +++++++++++++-- 3 files changed, 73 insertions(+), 8 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Deform_mesh.ui b/Polyhedron/demo/Polyhedron/Deform_mesh.ui index 4d20d7ebf91..7cc4f5bf615 100644 --- a/Polyhedron/demo/Polyhedron/Deform_mesh.ui +++ b/Polyhedron/demo/Polyhedron/Deform_mesh.ui @@ -6,7 +6,7 @@ 0 0 - 442 + 582 762 @@ -299,11 +299,22 @@ - - - Activate Pivoting - - + + + + + Activate Pivoting + + + + + + + Activate Fixed Plane Deformation + + + + diff --git a/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.cpp b/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.cpp index fdc8c2be16b..66e1c9bd259 100644 --- a/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.cpp @@ -663,8 +663,40 @@ void Scene_edit_polyhedron_item::draw(Viewer_interface* viewer) const { vaos[0]->release(); draw_edges(viewer); draw_ROI_and_control_vertices(viewer); + if(ui_widget->ActivateFixedPlaneCheckBox->isChecked()) + draw_frame_plane(viewer); +} +void Scene_edit_polyhedron_item::draw_frame_plane(Viewer_interface* viewer) const +{ + for(Ctrl_vertices_group_data_list::const_iterator hgb_data = ctrl_vertex_frame_map.begin(); hgb_data != ctrl_vertex_frame_map.end(); ++hgb_data) + { + if(hgb_data->frame == viewer->manipulatedFrame()) + { + const double diag = scene_diag(); + glColor3f(0,0,0); + qglviewer::Vec base1(1,0,0); + qglviewer::Vec base2(0,1,0); + qglviewer::Quaternion orientation=hgb_data->frame->orientation(); + base1=orientation.rotate(base1); + base2=orientation.rotate(base2); + + qglviewer::Vec center = hgb_data->frame_initial_center; + + qglviewer::Vec p1 = center - diag*base1 - diag*base2; + qglviewer::Vec p2 = center + diag*base1 - diag*base2; + qglviewer::Vec p3 = center + diag*base1 + diag*base2; + qglviewer::Vec p4 = center - diag*base1 + diag*base2; + + glBegin(GL_LINE_LOOP); + glVertex3f(p1.x, p1.y, p1.z); + glVertex3f(p2.x, p2.y, p2.z); + glVertex3f(p3.x, p3.y, p3.z); + glVertex3f(p4.x, p4.y, p4.z); + glEnd(); + } + } } void Scene_edit_polyhedron_item::draw_ROI_and_control_vertices(Viewer_interface* viewer) const { diff --git a/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.h b/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.h index 5cb7799515a..5f8907293ac 100644 --- a/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.h +++ b/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.h @@ -119,7 +119,7 @@ public: bool oldState = frame->blockSignals(true); // do not let it Q_EMIT modified, which will cause a deformation // but we are just adjusting the center so it does not require a deformation - frame->setOrientation(qglviewer::Quaternion()); + // frame->setOrientation(qglviewer::Quaternion()); frame->setPosition(frame_initial_center); frame->blockSignals(oldState); } @@ -220,6 +220,7 @@ public: void draw_edges(Viewer_interface*) const; void draw_bbox(const Scene_interface::Bbox&) const; void draw_ROI_and_control_vertices(Viewer_interface *viewer) const; + void draw_frame_plane(Viewer_interface* viewer) const; // Get wrapped polyhedron Polyhedron* polyhedron(); @@ -496,6 +497,7 @@ public: { is_rot_free=true; rot_constraint.setRotationConstraintType(qglviewer::AxisPlaneConstraint::FREE); + rot_constraint.setTranslationConstraintType(qglviewer::AxisPlaneConstraint::FREE); // just block signals to prevent deformation for(Ctrl_vertices_group_data_list::iterator it = ctrl_vertex_frame_map.begin(); it != ctrl_vertex_frame_map.end(); ++it) @@ -688,7 +690,16 @@ protected: min_it->frame->setConstraint(&rot_constraint); } else - rot_constraint.setRotationConstraintType(qglviewer::AxisPlaneConstraint::FREE); + { + if(!ui_widget->ActivatePivotingCheckBox->isChecked() && + ui_widget->ActivateFixedPlaneCheckBox->isChecked()) + { + // the constraint is local to the frame + rot_constraint.setTranslationConstraint(qglviewer::AxisPlaneConstraint::PLANE,qglviewer::Vec(0,0,1)); + rot_constraint.setRotationConstraintType(qglviewer::AxisPlaneConstraint::FORBIDDEN); + min_it->frame->setConstraint(&rot_constraint); + } + } if(viewer->manipulatedFrame() == min_it->frame) { return false; } @@ -711,6 +722,17 @@ protected: } } + + double scene_diag() const { + const double& xdelta = bbox().xmax-bbox().xmin; + const double& ydelta = bbox().ymax-bbox().ymin; + const double& zdelta = bbox().zmax-bbox().zmin; + const double diag = std::sqrt(xdelta*xdelta + + ydelta*ydelta + + zdelta*zdelta); + return diag * 0.5; + } + protected: GLUquadric* quadric; // for drawing spheres }; // end class Scene_edit_polyhedron_item From b0c34ee58fc57ab1799182f9c775304e0f2f8ea3 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 28 Jul 2015 11:09:27 +0200 Subject: [PATCH 132/217] fix restriction plane center --- .../Polyhedron/Scene_edit_polyhedron_item.cpp | 2 +- .../Polyhedron/Scene_edit_polyhedron_item.h | 23 ++++++++++--------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.cpp b/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.cpp index 66e1c9bd259..dd8efca0258 100644 --- a/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.cpp @@ -682,7 +682,7 @@ void Scene_edit_polyhedron_item::draw_frame_plane(Viewer_interface* viewer) cons base1=orientation.rotate(base1); base2=orientation.rotate(base2); - qglviewer::Vec center = hgb_data->frame_initial_center; + qglviewer::Vec center = hgb_data->calculate_initial_center(); qglviewer::Vec p1 = center - diag*base1 - diag*base2; qglviewer::Vec p2 = center + diag*base1 - diag*base2; diff --git a/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.h b/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.h index 5f8907293ac..e05a4d7beb6 100644 --- a/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.h +++ b/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.h @@ -135,6 +135,18 @@ public: deform_mesh->set_target_position(*hb, Point(rotated_and_translated.x, rotated_and_translated.y, rotated_and_translated.z) ); } } + qglviewer::Vec calculate_initial_center() const + { + qglviewer::Vec center_acc(0, 0, 0); + if (initial_positions.empty()) { return center_acc; } + + for (std::vector::const_iterator it = initial_positions.begin(); + it != initial_positions.end(); ++it) + { + center_acc += (*it); + } + return center_acc / initial_positions.size(); + } private: void reset_initial_positions() @@ -147,17 +159,6 @@ private: initial_positions.push_back(point); } } - qglviewer::Vec calculate_initial_center() - { - qglviewer::Vec center_acc(0, 0, 0); - if(initial_positions.empty()) {return center_acc; } - - for(std::vector::iterator it = initial_positions.begin(); it != initial_positions.end(); ++it) - { - center_acc += (*it); - } - return center_acc / initial_positions.size(); - } Scene_interface::Bbox calculate_initial_bbox() { if(initial_positions.empty()) {return Scene_interface::Bbox(0,0,0,0,0,0); } From fad75752e72f1fa3756c6a679a83cc0339dd5c76 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 28 Jul 2015 12:25:57 +0200 Subject: [PATCH 133/217] add "discard changes" button that cancels the last deformation this button resets the mesh to its geometry before last call to overwrite_initial_geometry also reorganize buttons in the widget --- Polyhedron/demo/Polyhedron/Deform_mesh.ui | 191 ++++++++---------- ...Polyhedron_demo_edit_polyhedron_plugin.cpp | 11 + .../Polyhedron/Scene_edit_polyhedron_item.h | 6 + 3 files changed, 106 insertions(+), 102 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Deform_mesh.ui b/Polyhedron/demo/Polyhedron/Deform_mesh.ui index 7cc4f5bf615..f7a85a7b196 100644 --- a/Polyhedron/demo/Polyhedron/Deform_mesh.ui +++ b/Polyhedron/demo/Polyhedron/Deform_mesh.ui @@ -6,8 +6,8 @@ 0 0 - 582 - 762 + 568 + 588 @@ -21,7 +21,7 @@ Selection - + @@ -57,7 +57,7 @@ - + @@ -104,7 +104,7 @@ - + @@ -127,6 +127,47 @@ + + + + QLayout::SetDefaultConstraint + + + + + Load ROI / Control Vertices + + + + + + + Show As Sphere + + + false + + + + + + + Show ROI + + + true + + + + + + + Save ROI / Control Vertices + + + + + @@ -195,7 +236,7 @@ - Warning : after remeshing all ROI and control vertices will be unselected + Warning : after remeshing all ROI and control vertices will be unselected. "Discard changes" will be unavailable. Qt::LeftToRight @@ -319,36 +360,6 @@ - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 0 - 0 - - - - Update Original Positions - - - - - @@ -356,75 +367,51 @@ - - - - - - Show ROI - - - true - - - - - - - Show As Sphere - - - false - - - - - - - - - - - Save ROI / Control Vertices - - - - - - - Load ROI / Control Vertices - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 0 - 0 - - - - Apply and Close - - + + + + + + + Reset mesh to last version saved by "Overwrite Initial Geometry" + + + Discard changes + + + + + + + + 0 + 0 + + + + Overwrite Initial Geometry + + + + + + + + 0 + 0 + + + + Apply and Close + + + + + + diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_edit_polyhedron_plugin.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_edit_polyhedron_plugin.cpp index fbf0f337fcf..36ab7c9728e 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_demo_edit_polyhedron_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_edit_polyhedron_plugin.cpp @@ -39,6 +39,7 @@ public Q_SLOTS: void on_SelectAllVerticesPushButton_clicked(); void on_DeleteCtrlVertPushButton_clicked(); void on_ApplyAndClosePushButton_clicked(); + void on_DiscardChangesPushButton_clicked(); void on_ClearROIPushButton_clicked(); void on_ShowROICheckBox_stateChanged(int state); void on_ShowAsSphereCheckBox_stateChanged(int state); @@ -114,6 +115,7 @@ void Polyhedron_demo_edit_polyhedron_plugin::init(QMainWindow* mainWindow, Scene connect(ui_widget.SelectAllVerticesPushButton, SIGNAL(clicked()), this, SLOT(on_SelectAllVerticesPushButton_clicked())); connect(ui_widget.DeleteCtrlVertPushButton, SIGNAL(clicked()), this, SLOT(on_DeleteCtrlVertPushButton_clicked())); connect(ui_widget.ApplyAndClosePushButton, SIGNAL(clicked()), this, SLOT(on_ApplyAndClosePushButton_clicked())); + connect(ui_widget.DiscardChangesPushButton, SIGNAL(clicked()), this, SLOT(on_DiscardChangesPushButton_clicked())); connect(ui_widget.ClearROIPushButton, SIGNAL(clicked()), this, SLOT(on_ClearROIPushButton_clicked())); connect(ui_widget.ShowROICheckBox, SIGNAL(stateChanged(int)), this, SLOT(on_ShowROICheckBox_stateChanged(int))); connect(ui_widget.ShowAsSphereCheckBox, SIGNAL(stateChanged(int)), this, SLOT(on_ShowAsSphereCheckBox_stateChanged(int))); @@ -198,6 +200,15 @@ void Polyhedron_demo_edit_polyhedron_plugin::on_ApplyAndClosePushButton_clicked( { dock_widget->setVisible(false); } +void Polyhedron_demo_edit_polyhedron_plugin::on_DiscardChangesPushButton_clicked() +{ + int item_id = scene->mainSelectionIndex(); + Scene_edit_polyhedron_item* edit_item = qobject_cast(scene->item(item_id)); + if (!edit_item) return; // the selected item is not of the right type + + edit_item->reset_deform_object(); + scene->itemChanged(edit_item); //for redraw +} void Polyhedron_demo_edit_polyhedron_plugin::on_ShowROICheckBox_stateChanged(int /*state*/) { for(Scene_interface::Item_id i = 0, end = scene->numberOfEntries(); i < end; ++i) diff --git a/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.h b/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.h index e05a4d7beb6..733b58a8775 100644 --- a/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.h +++ b/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.h @@ -577,6 +577,12 @@ public: refresh_all_group_centers(); } + void reset_deform_object() + { + deform_mesh->reset(); + refresh_all_group_centers(); + } + struct Is_selected { Deform_mesh* dm; Is_selected(Deform_mesh* dm) : dm(dm) {} From 4741e4c3d5746b5572176a59576777bb4a574157 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 28 Jul 2015 12:29:10 +0200 Subject: [PATCH 134/217] add warning --- Polyhedron/demo/Polyhedron/Deform_mesh.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polyhedron/demo/Polyhedron/Deform_mesh.ui b/Polyhedron/demo/Polyhedron/Deform_mesh.ui index f7a85a7b196..cb959cdad52 100644 --- a/Polyhedron/demo/Polyhedron/Deform_mesh.ui +++ b/Polyhedron/demo/Polyhedron/Deform_mesh.ui @@ -376,7 +376,7 @@ - Reset mesh to last version saved by "Overwrite Initial Geometry" + Reset mesh to last version saved by "Overwrite Initial Geometry". Not available when Remeshing is ON. Discard changes From d7fa45184ecacef3afba3d0bab1e59f35b3b3348 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Fri, 7 Aug 2015 17:33:03 +0200 Subject: [PATCH 135/217] recreate the first group of vertices after the deform object is reinit --- .../demo/Polyhedron/Scene_edit_polyhedron_item.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.cpp b/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.cpp index 261a97e6be6..9ec65d7a393 100644 --- a/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.cpp @@ -491,7 +491,10 @@ void Scene_edit_polyhedron_item::remesh() //reset ROI from its outside border roi_border clear_roi(); - delete_ctrl_vertices_group(); + do{ + delete_ctrl_vertices_group(false); + } + while(!ctrl_vertex_frame_map.empty()); poly_item->update_vertex_indices(); poly_item->update_halfedge_indices(); @@ -504,7 +507,9 @@ void Scene_edit_polyhedron_item::remesh() reset_drawing_data(); compute_normals_and_vertices(); - poly_item->changed(); // now we need to call poly_item changed to delete AABB tree + poly_item->invalidate_aabb_tree(); // invalidate the AABB tree + create_ctrl_vertices_group(); + Q_EMIT itemChanged(); } From a45368680fb50996618cceddc6a26391d37a58ef Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Mon, 10 Aug 2015 19:03:54 +0200 Subject: [PATCH 136/217] add function to remove isolated vertices --- .../CGAL/Polygon_mesh_processing/repair.h | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) 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 4c173e6ca82..b2b3a5849a0 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair.h @@ -882,6 +882,27 @@ std::size_t remove_degenerate_faces(TriangleMesh& tmesh) } /// \endcond + +template +std::size_t remove_isolated_vertices(PolygonMesh& pmesh) +{ + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + std::vector to_be_removed; + + BOOST_FOREACH(vertex_descriptor v, vertices(pmesh)) + { + if (CGAL::halfedges_around_target(v, pmesh).first + == CGAL::halfedges_around_target(v, pmesh).second) + to_be_removed.push_back(v); + } + std::size_t nb_removed = to_be_removed.size(); + BOOST_FOREACH(vertex_descriptor v, to_be_removed) + { + remove_vertex(v, pmesh); + } + return nb_removed; +} + } } // end of CGAL::Polygon_mesh_processing #endif // CGAL_POLYGON_MESH_PROCESSING_REPAIR_H From 3f7021f20bb55141457d469877e3428e5a66d0c4 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 11 Aug 2015 12:52:08 +0200 Subject: [PATCH 137/217] add plugin that implements the function in PMP/repair.h Remove degenerate faces Remove isolated vertices //does not work yet because Polyhedron item discards them --- Polyhedron/demo/Polyhedron/CMakeLists.txt | 5 +- ...lyhedron_demo_repair_polyhedron_plugin.cpp | 113 ++++++++++++++++++ 2 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 Polyhedron/demo/Polyhedron/Polyhedron_demo_repair_polyhedron_plugin.cpp diff --git a/Polyhedron/demo/Polyhedron/CMakeLists.txt b/Polyhedron/demo/Polyhedron/CMakeLists.txt index 69b43cfa186..8ae9a7a63b2 100644 --- a/Polyhedron/demo/Polyhedron/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/CMakeLists.txt @@ -400,8 +400,11 @@ if(CGAL_Qt5_FOUND AND Qt5_FOUND AND OPENGL_FOUND AND QGLVIEWER_FOUND) polyhedron_demo_plugin(corefinement_plugin Polyhedron_demo_corefinement_plugin) target_link_libraries(corefinement_plugin scene_polyhedron_item scene_combinatorial_map_item scene_polylines_item) - polyhedron_demo_plugin(trivial_plugin Polyhedron_demo_trivial_plugin) + polyhedron_demo_plugin(repair_polyhedron_plugin Polyhedron_demo_repair_polyhedron_plugin) + target_link_libraries(repair_polyhedron_plugin scene_polyhedron_item) + polyhedron_demo_plugin(trivial_plugin Polyhedron_demo_trivial_plugin) + # Edit polyhedron scene item and plugin if ( EIGEN3_FOUND AND "${EIGEN3_VERSION}" VERSION_GREATER "3.1.90" ) qt5_wrap_ui( editionUI_FILES Deform_mesh.ui ) diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_repair_polyhedron_plugin.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_repair_polyhedron_plugin.cpp new file mode 100644 index 00000000000..d0762c70e76 --- /dev/null +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_repair_polyhedron_plugin.cpp @@ -0,0 +1,113 @@ +#include + +#include "Scene_polyhedron_item.h" +#include "Scene_interface.h" +#include "Polyhedron_type.h" +#include "Polyhedron_demo_plugin_interface.h" +#include "Polyhedron_demo_plugin_helper.h" +#include "Messages_interface.h" +#include + +#include +#include +#include + +#include +#include + +class Polyhedron_demo_repair_polyhedron_plugin : + public QObject, + public Polyhedron_demo_plugin_helper +{ + Q_OBJECT + Q_INTERFACES(Polyhedron_demo_plugin_interface) + Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.PluginInterface/1.0") + +public: + // To silent a warning -Woverloaded-virtual + // See http://stackoverflow.com/questions/9995421/gcc-woverloaded-virtual-warnings + using Polyhedron_demo_plugin_helper::init; + + void init(QMainWindow* mainWindow, + Scene_interface* scene_interface, + Messages_interface* m) + { + this->scene = scene_interface; + this->mw = mainWindow; + this->messages = m; + + actionRemoveIsolatedVertices = new QAction(tr("Remove isolated vertices"), mw); + if (actionRemoveIsolatedVertices){ + connect(actionRemoveIsolatedVertices, SIGNAL(triggered()), + this, SLOT(on_actionRemoveIsolatedVertices_triggered())); + } + + actionRemoveDegenerateFaces = new QAction(tr("Remove degenerate faces"), mw); + if (actionRemoveDegenerateFaces){ + connect(actionRemoveDegenerateFaces, SIGNAL(triggered()), + this, SLOT(on_actionRemoveDegenerateFaces_triggered())); + } + } + + QList actions() const + { + return QList() << actionRemoveIsolatedVertices + << actionRemoveDegenerateFaces; + } + + bool applicable(QAction*) const + { + int item_id = scene->mainSelectionIndex(); + return qobject_cast( + scene->item(item_id)); + } + +public Q_SLOTS: + void on_actionRemoveIsolatedVertices_triggered(); + void on_actionRemoveDegenerateFaces_triggered(); + +private: + QAction* actionRemoveIsolatedVertices; + QAction* actionRemoveDegenerateFaces; + + Messages_interface* messages; +}; // end Polyhedron_demo_repair_polyhedron_plugin + + +void Polyhedron_demo_repair_polyhedron_plugin::on_actionRemoveIsolatedVertices_triggered() +{ + const Scene_interface::Item_id index = scene->mainSelectionIndex(); + + Scene_polyhedron_item* poly_item = + qobject_cast(scene->item(index)); + if (poly_item) + { + std::size_t nbv = + CGAL::Polygon_mesh_processing::remove_isolated_vertices( + *poly_item->polyhedron()); + messages->information(tr(" %1 isolated vertices have been removed.") + .arg(nbv)); + poly_item->changed(); + } +} + +void Polyhedron_demo_repair_polyhedron_plugin::on_actionRemoveDegenerateFaces_triggered() +{ + const Scene_interface::Item_id index = scene->mainSelectionIndex(); + + Scene_polyhedron_item* poly_item = + qobject_cast(scene->item(index)); + if (poly_item) + { + std::size_t nbv = + CGAL::Polygon_mesh_processing::remove_degenerate_faces( + *poly_item->polyhedron()); + messages->information(tr(" %1 degenerate faces have been removed.") + .arg(nbv)); + poly_item->changed(); + } + +} + + +#include "Polyhedron_demo_repair_polyhedron_plugin.moc" From 768dfbc0b05e3f89521dd9b840b28cb66960c1ec Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 11 Aug 2015 12:56:37 +0200 Subject: [PATCH 138/217] write documentation --- .../include/CGAL/Polygon_mesh_processing/repair.h | 11 +++++++++++ 1 file changed, 11 insertions(+) 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 b2b3a5849a0..46ce8a1064a 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair.h @@ -883,6 +883,17 @@ std::size_t remove_degenerate_faces(TriangleMesh& tmesh) /// \endcond +/// \ingroup PkgPolygonMeshProcessing +/// removes the isolated vertices from any polygon mesh. +/// A vertex is considered isolated if it is not incident to any simplex +/// of higher dimension. +/// +/// @tparam PolygonMesh a model of `FaceListGraph` and `MutableFaceGraph` +/// +/// @param pmesh the polygon mesh to be repaired +/// +/// @return number of removed isolated vertices +/// template std::size_t remove_isolated_vertices(PolygonMesh& pmesh) { From d8d63fce5a8c6dba95a14a151e28ee809c8b959e Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 11 Aug 2015 13:07:46 +0200 Subject: [PATCH 139/217] complete documentation --- .../doc/Polygon_mesh_processing/PackageDescription.txt | 1 + .../doc/Polygon_mesh_processing/Polygon_mesh_processing.txt | 3 +++ 2 files changed, 4 insertions(+) diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt index c97801ffe83..d3d80f85c14 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt @@ -70,6 +70,7 @@ and provides a list of the parameters that are used in this package. - `CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh()` - `CGAL::Polygon_mesh_processing::orient_polygon_soup()` - \link reverse_face_orientations_grp `CGAL::Polygon_mesh_processing::remove_degenerate_faces()` \endlink +- `CGAL::Polygon_mesh_processing::remove_isolated_vertices()` ## Normal Computation Functions ## - `CGAL::Polygon_mesh_processing::compute_face_normal()` 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 a2fe31a6b76..0662915cdce 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 @@ -275,6 +275,8 @@ or in general if its three vertices are collinear. The function `CGAL::Polygon_mesh_processing::remove_degenerate_faces()` removes those faces and fixes the connectivity of the newly cleaned up mesh. +It is also possible to remove isolated vertices from any polygon mesh, using the function +`CGAL::Polygon_mesh_processing::remove_isolated_vertices()`. \subsubsection RemoveDegenerateExample Example @@ -452,6 +454,7 @@ Function or Class | Pure Triangle | Self-Intersection Free `polygon_soup_to_polygon_mesh()` | no | no | no `orient_polygon_soup()` | no | no | no `remove_degenerate_faces()` | yes | no | no +`remove_isolated_vertices()` | no | no | no `compute_face_normal()` | no | no | no `compute_face_normals()` | no | no | no `compute_vertex_normal()` | no | no | no From 6fd4a474dbf8cf6d7386b7808da6b9ce1db9c009 Mon Sep 17 00:00:00 2001 From: Maxime Gimeno Date: Tue, 11 Aug 2015 15:43:16 +0200 Subject: [PATCH 140/217] OpenGL upgrade - replaced the glVertex() calls by use of shaders. --- .../Polyhedron/Scene_edit_polyhedron_item.cpp | 55 +++++++++++++++---- .../Polyhedron/Scene_edit_polyhedron_item.h | 3 +- 2 files changed, 46 insertions(+), 12 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.cpp b/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.cpp index 9ec65d7a393..a4887468c45 100644 --- a/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.cpp @@ -11,7 +11,7 @@ Scene_edit_polyhedron_item::Scene_edit_polyhedron_item (Scene_polyhedron_item* poly_item, Ui::DeformMesh* ui_widget, QMainWindow* mw) - : Scene_item(19,8), + : Scene_item(20,9), ui_widget(ui_widget), poly_item(poly_item), is_rot_free(true), @@ -91,6 +91,7 @@ Scene_edit_polyhedron_item::Scene_edit_polyhedron_item //the spheres : create_Sphere(length_of_axis/15.0); + pos_frame_plane.resize(0); changed(); } @@ -304,6 +305,23 @@ void Scene_edit_polyhedron_item::initialize_buffers(Viewer_interface *viewer =0) vaos[7]->release(); program->release(); } + //vao for the frame plane + { + program = getShaderProgram(PROGRAM_WITHOUT_LIGHT, viewer); + program->bind(); + bbox_program.bind(); + vaos[8]->bind(); + buffers[19].bind(); + buffers[19].allocate(pos_frame_plane.data(), + static_cast(pos_frame_plane.size()*sizeof(double))); + bbox_program.enableAttributeArray("vertex"); + bbox_program.setAttributeBuffer("vertex",GL_DOUBLE,0,3); + buffers[19].release(); + + vaos[8]->release(); + bbox_program.release(); + program->release(); + } are_buffers_filled = true; } @@ -358,6 +376,7 @@ void Scene_edit_polyhedron_item::compute_normals_and_vertices(void) ROI_points.resize(0); control_points.resize(0); control_color.resize(0); + pos_frame_plane.resize(0); BOOST_FOREACH(vertex_descriptor vd, deform_mesh->roi_vertices()) { if(!deform_mesh->is_control_vertex(vd)) @@ -419,6 +438,9 @@ void Scene_edit_polyhedron_item::compute_normals_and_vertices(void) color_lines[6] = 1.0; color_lines[9] = 1.0; color_lines[13] = 1.0; color_lines[16] = 1.0; + if(ui_widget->ActivateFixedPlaneCheckBox->isChecked()) + draw_frame_plane(viewer); + } ///////////////////////////////////////////////////////// @@ -586,6 +608,17 @@ void Scene_edit_polyhedron_item::draw_edges(Viewer_interface* viewer) const { program->release(); vaos[2]->release(); + + vaos[8]->bind(); + program = getShaderProgram(PROGRAM_WITHOUT_LIGHT); + attrib_buffers(viewer,PROGRAM_WITHOUT_LIGHT); + program->bind(); + program->setAttributeValue("colors", QColor(0,0,0)); + viewer->glDrawArrays(GL_LINE_LOOP, 0, (GLsizei)pos_frame_plane.size()/3); + program->release(); + vaos[8]->release(); + + if(rendering_mode == Wireframe) { draw_ROI_and_control_vertices(viewer); } @@ -604,18 +637,18 @@ void Scene_edit_polyhedron_item::draw(Viewer_interface* viewer) const { vaos[0]->release(); draw_edges(viewer); draw_ROI_and_control_vertices(viewer); - if(ui_widget->ActivateFixedPlaneCheckBox->isChecked()) - draw_frame_plane(viewer); + } -void Scene_edit_polyhedron_item::draw_frame_plane(Viewer_interface* viewer) const +void Scene_edit_polyhedron_item::draw_frame_plane(QGLViewer* viewer) const { + pos_frame_plane.resize(15); for(Ctrl_vertices_group_data_list::const_iterator hgb_data = ctrl_vertex_frame_map.begin(); hgb_data != ctrl_vertex_frame_map.end(); ++hgb_data) { if(hgb_data->frame == viewer->manipulatedFrame()) { + const double diag = scene_diag(); - glColor3f(0,0,0); qglviewer::Vec base1(1,0,0); qglviewer::Vec base2(0,1,0); @@ -630,12 +663,12 @@ void Scene_edit_polyhedron_item::draw_frame_plane(Viewer_interface* viewer) cons qglviewer::Vec p3 = center + diag*base1 + diag*base2; qglviewer::Vec p4 = center - diag*base1 + diag*base2; - glBegin(GL_LINE_LOOP); - glVertex3f(p1.x, p1.y, p1.z); - glVertex3f(p2.x, p2.y, p2.z); - glVertex3f(p3.x, p3.y, p3.z); - glVertex3f(p4.x, p4.y, p4.z); - glEnd(); + pos_frame_plane[0] = p1.x ; pos_frame_plane[1] = p1.y; pos_frame_plane[2] =p1.z ; + pos_frame_plane[3] = p2.x ; pos_frame_plane[4] = p2.y; pos_frame_plane[5] =p2.z ; + pos_frame_plane[6] = p3.x ; pos_frame_plane[7] = p3.y; pos_frame_plane[8] =p3.z ; + pos_frame_plane[9] = p4.x ; pos_frame_plane[10]= p4.y; pos_frame_plane[11] =p4.z ; + pos_frame_plane[12] = p1.x ; pos_frame_plane[13]= p1.y; pos_frame_plane[14] =p1.z ; + are_buffers_filled = false; } } } diff --git a/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.h b/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.h index 43daaf592da..1980f1e4ce2 100644 --- a/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.h +++ b/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.h @@ -220,7 +220,7 @@ public: void draw_edges(Viewer_interface*) const; void draw_bbox(const Scene_interface::Bbox&) const; void draw_ROI_and_control_vertices(Viewer_interface *viewer) const; - void draw_frame_plane(Viewer_interface* viewer) const; + void draw_frame_plane(QGLViewer *viewer) const; // Get wrapped polyhedron Polyhedron* polyhedron(); @@ -298,6 +298,7 @@ private: std::vector pos_axis; std::vector pos_sphere; std::vector normals_sphere; + mutable std::vector pos_frame_plane; mutable QOpenGLShaderProgram *program; mutable QOpenGLShaderProgram bbox_program; From 73450942f81fda6a4b585fc96c2e39fdf0d25d64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 11 Aug 2015 16:33:29 +0200 Subject: [PATCH 141/217] reset constraint types --- Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.h b/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.h index 1980f1e4ce2..f6ea3361257 100644 --- a/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.h +++ b/Polyhedron/demo/Polyhedron/Scene_edit_polyhedron_item.h @@ -657,6 +657,9 @@ protected: } if(ctrl_vertex_frame_map.empty()) { return false; } + rot_constraint.setRotationConstraintType(qglviewer::AxisPlaneConstraint::FREE); + rot_constraint.setTranslationConstraintType(qglviewer::AxisPlaneConstraint::FREE); + QGLViewer* viewer = *QGLViewer::QGLViewerPool().begin(); qglviewer::Camera* camera = viewer->camera(); From a5c14aad2151f186f7d6942e5697a53e52563597 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Fri, 14 Aug 2015 18:52:28 +0200 Subject: [PATCH 142/217] fix a bug in collapse_short_edges an edge that is about to be collapsed can be not on border, but with both of its vertices on the mesh Border this causes the appearance of a null_face that causes a seg fault --- .../internal/remesh_impl.h | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index f6c1ed16c73..0779854d78f 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -512,18 +512,18 @@ namespace internal { halfedge_and_opp_removed(he); halfedge_and_opp_removed(prev(he, mesh_)); - //perform collapse - Point target_point = get(vpmap_, vb); - - vertex_descriptor vkept = CGAL::Euler::collapse_edge(edge(he, mesh_), mesh_); - put(vpmap_, vkept, target_point); - ++nb_collapses; - // merge halfedge_status to keep the more important on both sides + //do it before collapse is performed to be sure everything is valid merge_status(en, s_epo, s_ep); if (!mesh_border_case) merge_status(en_p, s_epo_p, s_ep_p); + //perform collapse + Point target_point = get(vpmap_, vb); + vertex_descriptor vkept = CGAL::Euler::collapse_edge(edge(he, mesh_), mesh_); + put(vpmap_, vkept, target_point); + ++nb_collapses; + fix_degenerate_faces(vkept, short_edges, sq_low); #ifdef CGAL_PMP_REMESHING_DEBUG @@ -995,6 +995,9 @@ namespace internal { Halfedge_status s_en = status(en); Halfedge_status s_eno = status(eno); + if (s_epo == MESH_BORDER && s_eno == MESH_BORDER) + return; + if(s_epo == MESH_BORDER || s_ep == MESH_BORDER || s_epo == PATCH_BORDER @@ -1025,6 +1028,8 @@ namespace internal { degenerate_faces.pop_back(); CGAL_assertion(PMP::is_degenerated(h, mesh_, vpmap_, GeomTraits())); + if (face(h, mesh_) == boost::graph_traits::null_face()) + continue; BOOST_FOREACH(halfedge_descriptor hf, halfedges_around_face(h, mesh_)) From 6062c9405f4f3a4536aab70986fb16eb82e25954 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 18 Aug 2015 17:21:40 +0200 Subject: [PATCH 143/217] add reference manual for remeshing --- .../NamedParameters.txt | 34 ++++++++++++++----- .../PackageDescription.txt | 5 ++- .../Polygon_mesh_processing.txt | 4 +++ 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/NamedParameters.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/NamedParameters.txt index 49efa117af3..0f51b96857e 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/NamedParameters.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/NamedParameters.txt @@ -112,15 +112,6 @@ typename CGAL::Kernel_traits< \endcode \cgalNPEnd -\cgalNPBegin{edge_is_constrained_map} \anchor PMP_edge_is_constrained_map - the property map containing information about edges of the input polygon mesh being constrained or not.\n -\b Type: a class model of `ReadablePropertyMap` with -`boost::graph_traits::%edge_descriptor` as key type and -`bool` as value type. It should be default - constructible.\n -\b Default: if this parameter is omitted, -a default property map where no edge is constrained is provided. -\cgalNPEnd - \cgalNPBegin{face_index_map} \anchor PMP_face_index_map the property map containing the index of each face of the input polygon mesh.\n \b Type: a class model of `ReadablePropertyMap` with @@ -137,6 +128,31 @@ a default property map where no edge is constrained is provided. \b Default value is \code boost::get(CGAL::vertex_index, pmesh)\endcode \cgalNPEnd +\cgalNPBegin{ number_of_iterations } \anchor PMP_number_of_iterations +the number of iterations of the sequence of iterations performed by the isotropic remeshing +algorithm.\n +\b Type : \c unsigned \c int \n +\b Default value is `1` +\cgalNPEnd + +\cgalNPBegin{ edge_is_constrained_map } \anchor PMP_edge_is_constrained_map +the property map containing information about edges of the input polygon mesh being constrained or not.\n +\b Type : a class model of `ReadablePropertyMap` with +`boost::graph_traits::%edge_descriptor` as key type and +`bool` as value type.It should be default - constructible.\n +\b Default : if this parameter is omitted, +a default property map where no edge is constrained is provided. +\cgalNPEnd + +\cgalNPBegin{protect_constraints} \anchor PMP_protect_constraints +enables the protection of constraints listed by \ref PMP_edge_is_constrained_map "edge_is_constrained_map" +during isotropic remeshing. If `true`, constraint edges cannot be modified at all +during the remeshing process.\n +\b Type : boolean \n +\b Default value is `false` +\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 d3d80f85c14..79a83c474f8 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt @@ -3,6 +3,8 @@ /// \ingroup PkgPolygonMeshProcessing /// \defgroup stitching_grp CGAL::Polygon_mesh_processing::stitch_borders() /// \ingroup PkgPolygonMeshProcessing +/// \defgroup remeshing_grp Isotropic remeshing +/// \ingroup PkgPolygonMeshProcessing /// \defgroup reverse_face_orientations_grp CGAL::reverse_face_orientations() /// \ingroup PkgPolygonMeshProcessing /// \defgroup keep_connected_components_grp CGAL::keep_connected_components() @@ -48,7 +50,8 @@ and provides a list of the parameters that are used in this package. - `CGAL::Polygon_mesh_processing::fair()` - `CGAL::Polygon_mesh_processing::refine()` - `CGAL::Polygon_mesh_processing::triangulate_faces()` -- `CGAL::Polygon_mesh_processing::incremental_triangle_based_remeshing()` +- \link remeshing_grp `CGAL::Polygon_mesh_processing::incremental_triangle_based_remeshing()` \endlink +- \link remeshing_grp `CGAL::Polygon_mesh_processing::split_long_edges()` \endlink ## Hole Filling Functions ## - `CGAL::Polygon_mesh_processing::triangulate_hole()` 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 0662915cdce..2a5caf60ad2 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 @@ -96,6 +96,10 @@ maximizes the minimum angle of all the angles of the triangles in the triangulat \subsubsection Remeshing - `CGAL::Polygon_mesh_processing::incremental_triangle_based_remeshing()` \todo user manual remeshing +* implements section 6.5.3 "Incremental remeshing" from the PMP book \cgalCite{botsch2010PMP}. + +- `CGAL::Polygon_mesh_processing::split_long_edges()` + \subsection MeshingExamples Meshing Examples From 5cd95d9289bdb16286066684dc8e2ce782aa4337 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 18 Aug 2015 17:48:57 +0200 Subject: [PATCH 144/217] add remeshing example --- .../Polygon_mesh_processing/CMakeLists.txt | 1 + .../isotropic_remeshing_example.cpp | 64 +++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 Polygon_mesh_processing/examples/Polygon_mesh_processing/isotropic_remeshing_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 7bf348f24fc..68838e2dd9f 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt @@ -85,6 +85,7 @@ create_single_source_cgal_program( "triangulate_polyline_example.cpp") create_single_source_cgal_program( "refine_fair_example.cpp") create_single_source_cgal_program( "mesh_slicer_example.cpp") create_single_source_cgal_program( "remove_degeneracies_example.cpp") +create_single_source_cgal_program( "isotropic_remeshing_example.cpp") if(OpenMesh_FOUND) create_single_source_cgal_program( "compute_normals_example_OM.cpp" ) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/isotropic_remeshing_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/isotropic_remeshing_example.cpp new file mode 100644 index 00000000000..7a91ac640e8 --- /dev/null +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/isotropic_remeshing_example.cpp @@ -0,0 +1,64 @@ +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +typedef CGAL::Exact_predicates_inexact_constructions_kernel K; +typedef CGAL::Surface_mesh Mesh; + +typedef boost::graph_traits::halfedge_descriptor halfedge_descriptor; +typedef boost::graph_traits::edge_descriptor edge_descriptor; +typedef boost::graph_traits::vertex_descriptor vertex_descriptor; +typedef boost::graph_traits::face_descriptor face_descriptor; + +int main(int argc, char* argv[]) +{ + const char* filename = (argc > 1) ? argv[1] : "data/pig.off"; + std::ifstream input(filename); + + Mesh mesh; + if (!input || !(input >> mesh)) { + std::cerr << "Not a valid off file." << std::endl; + return 1; + } + + double target_edge_length = 0.04; + unsigned int nb_iter = 3; + + std::cout << "Split border..."; + + std::vector border; + PMP::get_border(mesh, faces(mesh), std::back_inserter(border)); + PMP::split_long_edges(mesh, border, target_edge_length); + + std::cout << "done." << std::endl; + + std::cout << "Start remeshing of " << filename + << " (" << num_faces(mesh) << " faces)..." << std::endl; + + CGAL::Timer t; + t.start(); + + PMP::incremental_triangle_based_remeshing(mesh, + faces(mesh), + target_edge_length, + PMP::parameters::number_of_iterations(nb_iter) + .protect_constraints(true)//i.e. protect border, here + ); + + t.stop(); + std::cout << "Remeshing took " << t.time() << std::endl; + + std::ofstream out("remeshed.off"); + out << mesh; + out.close(); + + return 0; +} \ No newline at end of file From 9edeaa38f21ceebf55a2d707cb581cfd6c130910 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 18 Aug 2015 17:52:33 +0200 Subject: [PATCH 145/217] cleanup example --- .../Polygon_mesh_processing/isotropic_remeshing_example.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/isotropic_remeshing_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/isotropic_remeshing_example.cpp index 7a91ac640e8..a5dfe95f7ab 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/isotropic_remeshing_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/isotropic_remeshing_example.cpp @@ -7,16 +7,12 @@ #include #include -#include #include typedef CGAL::Exact_predicates_inexact_constructions_kernel K; typedef CGAL::Surface_mesh Mesh; typedef boost::graph_traits::halfedge_descriptor halfedge_descriptor; -typedef boost::graph_traits::edge_descriptor edge_descriptor; -typedef boost::graph_traits::vertex_descriptor vertex_descriptor; -typedef boost::graph_traits::face_descriptor face_descriptor; int main(int argc, char* argv[]) { From 713f7424abad52b295b9d66e8214ae18e1786afc Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 18 Aug 2015 18:24:27 +0200 Subject: [PATCH 146/217] documentation for remeshing --- .../CGAL/Polygon_mesh_processing/remesh.h | 140 +++++++++++------- 1 file changed, 87 insertions(+), 53 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h index b1408b00f34..62981c53282 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h @@ -33,79 +33,88 @@ namespace CGAL { namespace Polygon_mesh_processing { /*! -* \ingroup PkgPolygonMeshProcessing -* @brief remeshes a triangulated region of a polygon mesh. -* implements section 6.5.3 "Incremental remeshing" from the PMP book +* \ingroup remeshing_grp +* @brief remeshes a triangulated region of a triangulated surface mesh. +* This operation sequentially performs edge splits, edge collapses, +* edge flips, Laplacian smoothing and projection to the initial surface +* to generate a smooth mesh with a prescribed edge length. +* The output is a new triangle mesh of the range of faces given to be remeshed. * -* @tparam PolygonMesh model of `MutableFaceGraph` that -* has an internal property map for `CGAL::vertex_point_t` -* @tparam FaceRange range of `boost::graph_traits::%face_descriptor`, +* @tparam TriangleMesh model of `MutableFaceGraph` that +* has an internal property map for `CGAL::vertex_point_t`. +* @tparam FaceRange range of `boost::graph_traits::%face_descriptor`, model of `Range`. Its iterator type is `InputIterator`. * @tparam NamedParameters a sequence of \ref namedparameters * -* @param pmesh polygon mesh with patches to be remeshed -* @param faces the range of faces defining one patch to remesh +* @param tmesh triangulated surface mesh with patches to be remeshed +* @param faces the range of faces defining one patch to be remeshed * @param target_edge_length the edge length that is targetted in the remeshed patch * @param np optional sequence of \ref namedparameters among the ones listed below * \cgalNamedParamsBegin * \cgalParamBegin{vertex_point_map} the property map with the points associated -* to the vertices of `pmesh`. Instance of a class model of `ReadWritePropertyMap`. +* to the vertices of `tmesh`. Instance of a class model of `ReadWritePropertyMap`. * \cgalParamEnd -* \cgalParamBegin{number_of_iterations} TODO... +* \cgalParamBegin{number_of_iterations} the number of iterations for the +* sequence of atomic operations performed (listed in the above description) * \cgalParamEnd * \cgalParamBegin{geom_traits} a geometric traits class instance * \cgalParamEnd -* \cgalParamBegin{edge_is_constrained_map} +* \cgalParamBegin{edge_is_constrained_map} a property map containing the +* constrained-or-not status of each edge of pmesh. A constrained edge can be splitted +* or collapsed, but not flipped, nor its endpoints moved by smoothing. +* However this parameter is provided or not, the boundary of `faces` +* (edges not sharing two faces +* in the range) is considered constrained * \cgalParamEnd * \cgalParamBegin{protect_constraints} If `true`, the edges set as constrained * in `edge_is_constrained_map` (or by default the boundary edges) * are not splitted nor collapsed during remeshing. -* Note that around edges that have their length higher than +* Note that around constrained edges that have their length higher than * twice `target_edge_length`, remeshing will fail to provide -* good quality results. +* good quality results. It can even fail to terminate because of cascading vertex +* insertions. * \cgalParamEnd * \cgalNamedParamsEnd * -* @sa `split_long_edges` +* @sa `split_long_edges()` * *@todo we suppose `faces` describe only one patch. Handle several patches. -*@todo document `number_of_iterations` *@todo add possibility to provide a functor that projects to a prescribed surface */ -template -void incremental_triangle_based_remeshing(PolygonMesh& pmesh +void incremental_triangle_based_remeshing(TriangleMesh& tmesh , const FaceRange& faces , const double& target_edge_length , const NamedParameters& np) { - typedef PolygonMesh PM; + typedef TriangleMesh TM; using boost::choose_pmap; using boost::get_param; using boost::choose_param; - typedef typename GetGeomTraits::type GT; + typedef typename GetGeomTraits::type GT; - typedef typename GetVertexPointMap::type VPMap; + typedef typename GetVertexPointMap::type VPMap; VPMap vpmap = choose_pmap(get_param(np, boost::vertex_point), - pmesh, + tmesh, boost::vertex_point); typedef typename boost::lookup_named_param_def < CGAL::edge_is_constrained_t, NamedParameters, - internal::Border_constraint_pmap//default + internal::Border_constraint_pmap//default > ::type ECMap; ECMap ecmap = choose_param(get_param(np, edge_is_constrained), - internal::Border_constraint_pmap(pmesh, faces)); + internal::Border_constraint_pmap(tmesh, faces)); bool protect = choose_param(get_param(np, protect_constraints), false); - typename internal::Incremental_remesher - remesher(pmesh, vpmap, protect); + typename internal::Incremental_remesher + remesher(tmesh, vpmap, protect); remesher.init_faces_remeshing(faces, ecmap); unsigned int nb_iterations = choose_param(get_param(np, number_of_iterations), 1); @@ -142,83 +151,108 @@ void incremental_triangle_based_remeshing(PolygonMesh& pmesh #endif } -template -void incremental_triangle_based_remeshing(PolygonMesh& pmesh +void incremental_triangle_based_remeshing(TriangleMesh& tmesh , const FaceRange& faces , const double& target_edge_length) { - incremental_triangle_based_remeshing(pmesh, + incremental_triangle_based_remeshing(tmesh, faces, target_edge_length, parameters::all_default()); } /*! -* \ingroup PkgPolygonMeshProcessing -* @brief splits the edges listed in `edges` +* \ingroup remeshing_grp +* @brief splits the edges listed in `edges` into sub-edges +* that are not longer than the given threshold `max_length`. +* +* Note this function is particularly useful before calling +* `incremental_triangle_based_remeshing()` with the protection of constraints activated. +* It prevents the remeshing algorithm to fall in the case where it does +* not terminate because of one or more constrained edges that are more than +* twice longer than the target edge length. +* +* @tparam TriangleMesh model of `MutableFaceGraph` that +* has an internal property map for `CGAL::vertex_point_t`. +* @tparam EdgeRange range of `boost::graph_traits::%edge_descriptor`, +* model of `Range`. Its iterator type is `InputIterator`. +* @tparam NamedParameters a sequence of \ref namedparameters +* +* @param tmesh triangulated surface mesh with patches to be remeshed +* @param edges the range of edges to be split if they are longer than given threshold +* @param max_length the edge length above which an edge from `edges` is split +* into to sub-edges +* @param np optional \ref namedparameters described below + +* \cgalNamedParamsBegin +* \cgalParamBegin{vertex_point_map} the property map with the points associated +* to the vertices of `tmesh`. Instance of a class model of `ReadWritePropertyMap`. +* \cgalParamEnd +* \cgalNamedParamsEnd +* +* @sa `incremental_triangle_based_remeshing()` * -* @tparam PolygonMesh model of `MutableFaceGraph` that -* has an internal property map for `CGAL::vertex_point_t` */ -template -void split_long_edges(PolygonMesh& pmesh - , EdgeRange& edge_range +void split_long_edges(TriangleMesh& tmesh + , EdgeRange& edges , const double& max_length , const NamedParameters& np) { - typedef PolygonMesh PM; + typedef TriangleMesh TM; using boost::choose_pmap; using boost::get_param; - typedef typename GetGeomTraits::type GT; - typedef typename GetVertexPointMap::type VPMap; + typedef typename GetGeomTraits::type GT; + typedef typename GetVertexPointMap::type VPMap; VPMap vpmap = choose_pmap(get_param(np, boost::vertex_point), - pmesh, + tmesh, boost::vertex_point); - typename internal::Incremental_remesher - remesher(pmesh, vpmap, false/*protect constraints*/); + typename internal::Incremental_remesher + remesher(tmesh, vpmap, false/*protect constraints*/); - remesher.split_long_edges(edge_range, max_length, Emptyset_iterator()); + remesher.split_long_edges(edges, max_length, Emptyset_iterator()); } -template -void split_long_edges(PolygonMesh& pmesh +template +void split_long_edges(TriangleMesh& tmesh , EdgeRange& edges , const double& max_length) { - split_long_edges(pmesh, + split_long_edges(tmesh, edges, max_length, parameters::all_default()); } //used in the Polyhedron demo -template -void split_long_edges(PolygonMesh& pmesh +void split_long_edges(TriangleMesh& tmesh , EdgeRange& edge_range , const double& max_length , OutputIterator out//edges after splitting, all shorter than target_length , const NamedParameters& np) { - typedef PolygonMesh PM; + typedef TriangleMesh TM; using boost::choose_pmap; using boost::get_param; - typedef typename GetGeomTraits::type GT; - typedef typename GetVertexPointMap::type VPMap; + typedef typename GetGeomTraits::type GT; + typedef typename GetVertexPointMap::type VPMap; VPMap vpmap = choose_pmap(get_param(np, boost::vertex_point), - pmesh, + tmesh, boost::vertex_point); - typename internal::Incremental_remesher - remesher(pmesh, vpmap, false/*protect constraints*/); + typename internal::Incremental_remesher + remesher(tmesh, vpmap, false/*protect constraints*/); remesher.split_long_edges(edge_range, max_length, out); } From 2d3cf9210b21d8dc1a9b9de8d4e9ba89f98dcae6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 1 Sep 2015 12:36:07 +0200 Subject: [PATCH 147/217] remove group_box and use layout instead to avoid display issues --- .../demo/Polyhedron/Selection_widget.ui | 380 ++++++++---------- 1 file changed, 170 insertions(+), 210 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Selection_widget.ui b/Polyhedron/demo/Polyhedron/Selection_widget.ui index cbdc0f6be44..499a78cea2a 100644 --- a/Polyhedron/demo/Polyhedron/Selection_widget.ui +++ b/Polyhedron/demo/Polyhedron/Selection_widget.ui @@ -6,15 +6,15 @@ 0 0 - 399 - 556 + 455 + 684 Selection - + @@ -71,81 +71,72 @@ - - - - - - - - - - - - - - - Insertion - - - true - - - - - - - Removal - - - - - - - - - - - - - Brush &size: - - - Brush_size_spin_box - - - - - - - - - - - - - - - - - - Select &All - - - - - - - &Clear - - - - - - - - - + + + + + + + + + Insertion + + + true + + + + + + + Removal + + + + + + + + + + + + + Brush &size: + + + Brush_size_spin_box + + + + + + + + + + + + + + + + + + Select &All + + + + + + + &Clear + + + + + + @@ -161,55 +152,46 @@ - - - - - - - - - - - - - Isolated &Component Size: - - - Threshold_size_spin_box - - - - - - - 999999999 - - - 8 - - - - - - - &Get Minimum - - - - - - - - - Select &Isolated Components Below Threshold - - - - - - - + + + + + + + Isolated &Component Size: + + + Threshold_size_spin_box + + + + + + + 999999999 + + + 8 + + + + + + + &Get Minimum + + + + + + + + + Select &Isolated Components Below Threshold + + + + @@ -225,52 +207,41 @@ - - - - 316 - 50 - - - - - - - - - - Sharp edges angle: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - 180 - - - 60 - - - - - - - Select - - - - - + + + + + Sharp edges angle: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + 180 + + + 60 + + + + + + + Select + + + + @@ -286,43 +257,32 @@ - - - - 316 - 50 - - - - - - - - - - Dilate or erode selection: - - - - - - - -50 - - - 50 - - - - - - - Apply - - - - - + + + + + Dilate or erode selection: + + + + + + + -50 + + + 50 + + + + + + + Apply + + + + From 3a2850eecd5db1a25a293e9100df0212a7c3e622 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Wed, 2 Sep 2015 14:47:37 +0200 Subject: [PATCH 148/217] Use accelerate_distance_queries() --- .../include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 0779854d78f..06c81822de3 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -135,6 +135,7 @@ namespace internal { Triangle_3(get(vpmap, v1), get(vpmap, v2), get(vpmap, v3))); } tree_ptr_ = new AABB_tree(input_triangles_.begin(), input_triangles_.end()); + tree_ptr_->accelerate_distance_queries(); } ~Incremental_remesher() From 06bac198dca288869f1c6e6ca1a8c0510574f19f Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Wed, 2 Sep 2015 15:33:03 +0200 Subject: [PATCH 149/217] endl -> '\n' --- Surface_mesh/include/CGAL/Surface_mesh/Surface_mesh.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Surface_mesh/include/CGAL/Surface_mesh/Surface_mesh.h b/Surface_mesh/include/CGAL/Surface_mesh/Surface_mesh.h index e60a3f53ba5..75de8988ad4 100644 --- a/Surface_mesh/include/CGAL/Surface_mesh/Surface_mesh.h +++ b/Surface_mesh/include/CGAL/Surface_mesh/Surface_mesh.h @@ -2474,7 +2474,7 @@ private: //------------------------------------------------------- private data reindex.resize(sm.num_vertices()); int n = 0; BOOST_FOREACH(Vertex_index v, sm.vertices()){ - os << sm.point(v) << std::endl; + os << sm.point(v) << '\n'; reindex[v]=n++; } @@ -2483,7 +2483,7 @@ private: //------------------------------------------------------- private data BOOST_FOREACH(Vertex_index v, CGAL::vertices_around_face(sm.halfedge(f),sm)){ os << " " << reindex[v]; } - os << "\n"; + os << '\n'; } return os; } From e790bda3803987260adbee69817873dafa5b3c0f Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Wed, 2 Sep 2015 16:05:05 +0200 Subject: [PATCH 150/217] move macro inside debug code --- .../include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h | 1 + .../include/CGAL/Polygon_mesh_processing/remesh.h | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 06c81822de3..f8e18239f95 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -29,6 +29,7 @@ #ifdef CGAL_PMP_REMESHING_DEBUG #include +#define CGAL_DUMP_REMESHING_STEPS #endif #ifdef CGAL_PMP_REMESHING_VERY_VERBOSE diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h index 62981c53282..c8874b9122e 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h @@ -21,8 +21,6 @@ #ifndef CGAL_POLYGON_MESH_PROCESSING_REMESH_H #define CGAL_POLYGON_MESH_PROCESSING_REMESH_H -#define CGAL_DUMP_REMESHING_STEPS - #include #include From 33710fe170c6b41458e6360b74108ff69805bd7b Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Wed, 2 Sep 2015 16:29:29 +0200 Subject: [PATCH 151/217] replace std::map with boost::unordered_map this speeds up the calls to "find" in status() --- .../Polygon_mesh_processing/internal/remesh_impl.h | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index f8e18239f95..c1f3c5c7076 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -980,8 +981,9 @@ namespace internal { Halfedge_status status(const halfedge_descriptor& h) const { - typename std::map < halfedge_descriptor, Halfedge_status >::const_iterator - it = halfedge_status_map_.find(h); + typename boost::unordered_map < + halfedge_descriptor, Halfedge_status >::const_iterator + it = halfedge_status_map_.find(h); CGAL_assertion(it != halfedge_status_map_.end()); return it->second; } @@ -1218,8 +1220,9 @@ namespace internal { unsigned int nb_patch = 0; unsigned int nb_patch_border = 0; - typedef typename std::map::value_type - HD_pair; + typedef typename boost::unordered_map < + halfedge_descriptor, Halfedge_status>::value_type + HD_pair; BOOST_FOREACH(const HD_pair& hs, halfedge_status_map_) { if(is_on_patch(hs.first)) nb_patch++; @@ -1299,7 +1302,7 @@ namespace internal { const AABB_tree* tree_ptr_; bool own_tree_; Triangle_list input_triangles_; - std::map halfedge_status_map_; + boost::unordered_map halfedge_status_map_; bool protect_constraints_; };//end class Incremental_remesher From 549266bb8a5a1bff74774eb80683cf3b3b09912a Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 15 Sep 2015 14:40:55 +0200 Subject: [PATCH 152/217] fix degeneracy test on border --- .../include/CGAL/Polygon_mesh_processing/repair.h | 2 ++ 1 file changed, 2 insertions(+) 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 46ce8a1064a..dc649051160 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair.h @@ -69,6 +69,8 @@ bool is_degenerated( const VertexPointMap& vpmap, const Traits& traits) { + if (is_border(hd, tmesh) && !is_triangle(hd, tmesh)) + return false; const typename Traits::Point_3& p1 = get(vpmap, target( hd, tmesh) ); const typename Traits::Point_3& p2 = get(vpmap, target(next(hd, tmesh), tmesh) ); const typename Traits::Point_3& p3 = get(vpmap, source( hd, tmesh) ); From a0ba10438e2255fa3a4e6081eaf98c13ac64a0d7 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 15 Sep 2015 14:57:35 +0200 Subject: [PATCH 153/217] fix collapsibility test, and reorder things dealing with the tags collapse on face range border was broken --- .../internal/remesh_impl.h | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index c1f3c5c7076..bb216fbec61 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -500,6 +500,7 @@ namespace internal { } //before collapse + bool mesh_border_case = is_on_border(opposite(he, mesh_)); halfedge_descriptor ep_p = prev(opposite(he, mesh_), mesh_); halfedge_descriptor epo_p = opposite(ep_p, mesh_); halfedge_descriptor en = next(he, mesh_); @@ -509,18 +510,17 @@ namespace internal { Halfedge_status s_ep = status(prev(he, mesh_)); Halfedge_status s_epo = status(opposite(prev(he, mesh_), mesh_)); - bool mesh_border_case = is_on_border(opposite(he, mesh_)); - if (!mesh_border_case) - halfedge_and_opp_removed(prev(opposite(he, mesh_), mesh_)); - halfedge_and_opp_removed(he); - halfedge_and_opp_removed(prev(he, mesh_)); - // merge halfedge_status to keep the more important on both sides //do it before collapse is performed to be sure everything is valid merge_status(en, s_epo, s_ep); if (!mesh_border_case) merge_status(en_p, s_epo_p, s_ep_p); + if (!mesh_border_case) + halfedge_and_opp_removed(prev(opposite(he, mesh_), mesh_)); + halfedge_and_opp_removed(he); + halfedge_and_opp_removed(prev(he, mesh_)); + //perform collapse Point target_point = get(vpmap_, vb); vertex_descriptor vkept = CGAL::Euler::collapse_edge(edge(he, mesh_), mesh_); @@ -866,12 +866,16 @@ namespace internal { halfedge_descriptor he = halfedge(e, mesh_); halfedge_descriptor hopp = opposite(he, mesh_); - if (is_on_patch(he)) //hopp is also on patch - return true; + if (!is_on_patch(he)) //hopp is also on patch + return false; + else if (is_on_patch_border(next(he, mesh_)) && is_on_patch_border(prev(he, mesh_))) + return false;//too many cases to be handled + else if (is_on_patch_border(next(hopp, mesh_)) && is_on_patch_border(prev(hopp, mesh_))) + return false;//too many cases to be handled else if (is_on_patch_border(he) || is_on_patch_border(hopp)) return !protect_constraints_;//allowed only when no protection else - return false; + return true; } bool collapse_does_not_invert_face(const halfedge_descriptor& h) const From 5e2c263cf5bce091ff754b5d1ef9b5e02f7bf76e Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 15 Sep 2015 15:04:59 +0200 Subject: [PATCH 154/217] remove debug_normals test in presence of sharp edges which are not constrained, the "false" result does not highlight a bug and is misleading --- .../internal/remesh_impl.h | 23 +++---------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index bb216fbec61..71a12104152 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -152,12 +152,6 @@ namespace internal { , const EdgeIsConstrainedMap& ecmap) { tag_halfedges_status(face_range, ecmap); - -#ifdef CGAL_PMP_REMESHING_EXPENSIVE_DEBUG - BOOST_FOREACH(vertex_descriptor v, vertices(mesh_)) - debug_normals(v); -#endif - } // split edges of edge_range that have their length > high @@ -369,10 +363,6 @@ namespace internal { debug_status_map(); debug_self_intersections(); #endif -#ifdef CGAL_PMP_REMESHING_EXPENSIVE_DEBUG - BOOST_FOREACH(vertex_descriptor v, vertices(mesh_)) - debug_normals(v); -#endif #ifdef CGAL_DUMP_REMESHING_STEPS dump("1-edge_split.off"); @@ -534,7 +524,6 @@ namespace internal { CGAL_assertion(nbb == halfedge_status_map_.size()); debug_status_map(); CGAL_assertion(!incident_to_degenerate(halfedge(vkept, mesh_))); - debug_normals(vkept); #endif //insert new/remaining short edges @@ -549,10 +538,6 @@ namespace internal { }//end if(collapse_ok) } -#ifdef CGAL_PMP_REMESHING_EXPENSIVE_DEBUG - BOOST_FOREACH(vertex_descriptor v, vertices(mesh_)) - debug_normals(v); -#endif #ifdef CGAL_PMP_REMESHING_VERBOSE std::cout << " done (" << nb_collapses << " collapses)." << std::endl; #endif @@ -1263,11 +1248,9 @@ namespace internal { } #endif - void debug_normals(const vertex_descriptor& v) const - { - CGAL_assertion(check_normals(v)); - } - + //warning : when v is on a sharp edge (angle <= 90 deg) + // which is not constrained (it's not mandatory) + //this test will return false, though normals are correct bool check_normals(const vertex_descriptor& v) const { if (!is_on_patch(v)) From a7c3670f8e1460c2ed979f737acc7d1c55532892 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 15 Sep 2015 17:07:17 +0200 Subject: [PATCH 155/217] do not test is_degenerated on a border halfedge is_border test should only be an assertion inside the function also make sure is_degenerated is called only on non-border edges --- .../Polygon_mesh_processing/internal/remesh_impl.h | 12 +++++++++--- .../include/CGAL/Polygon_mesh_processing/repair.h | 4 ++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h index 71a12104152..fb6dceb1bab 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/remesh_impl.h @@ -516,7 +516,7 @@ namespace internal { vertex_descriptor vkept = CGAL::Euler::collapse_edge(edge(he, mesh_), mesh_); put(vpmap_, vkept, target_point); ++nb_collapses; - + fix_degenerate_faces(vkept, short_edges, sq_low); #ifdef CGAL_PMP_REMESHING_DEBUG @@ -1012,6 +1012,8 @@ namespace internal { BOOST_FOREACH(halfedge_descriptor h, halfedges_around_target(halfedge(v, mesh_), mesh_)) { + if (is_border(h, mesh_)) + continue; if (PMP::is_degenerated(h, mesh_, vpmap_, GeomTraits())) degenerate_faces.push_back(h); } @@ -1064,9 +1066,11 @@ namespace internal { short_edges.insert(typename Bimap::value_type(hf, sqlen)); } - if (PMP::is_degenerated(hf, mesh_, vpmap_, GeomTraits())) + if (!is_border(hf, mesh_) + && PMP::is_degenerated(hf, mesh_, vpmap_, GeomTraits())) degenerate_faces.push_back(hf); - if (PMP::is_degenerated(hfo, mesh_, vpmap_, GeomTraits())) + if (!is_border(hfo, mesh_) + && PMP::is_degenerated(hfo, mesh_, vpmap_, GeomTraits())) degenerate_faces.push_back(hfo); break; @@ -1083,6 +1087,8 @@ namespace internal { BOOST_FOREACH(halfedge_descriptor h, halfedges_around_target(he, mesh_)) { + if (is_border(h, mesh_)) + continue; if (PMP::is_degenerated(h, mesh_, vpmap_, GeomTraits())) return true; } 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 dc649051160..63d82d2c9e4 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair.h @@ -69,8 +69,8 @@ bool is_degenerated( const VertexPointMap& vpmap, const Traits& traits) { - if (is_border(hd, tmesh) && !is_triangle(hd, tmesh)) - return false; + CGAL_assertion(!is_border(hd, tmesh)); + const typename Traits::Point_3& p1 = get(vpmap, target( hd, tmesh) ); const typename Traits::Point_3& p2 = get(vpmap, target(next(hd, tmesh), tmesh) ); const typename Traits::Point_3& p3 = get(vpmap, source( hd, tmesh) ); From e7f384d11cb88931f757a89e16ee67e272d79ef0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Fri, 18 Sep 2015 16:48:20 +0200 Subject: [PATCH 156/217] add a todo --- .../doc/Surface_mesh_skeletonization/PackageDescription.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Surface_mesh_skeletonization/doc/Surface_mesh_skeletonization/PackageDescription.txt b/Surface_mesh_skeletonization/doc/Surface_mesh_skeletonization/PackageDescription.txt index 64bbb2f6df0..50c7f846bf8 100644 --- a/Surface_mesh_skeletonization/doc/Surface_mesh_skeletonization/PackageDescription.txt +++ b/Surface_mesh_skeletonization/doc/Surface_mesh_skeletonization/PackageDescription.txt @@ -37,6 +37,9 @@ - `CGAL::Mean_curvature_flow_skeletonization` + \todo doc+code: mention that to get a better skeleton that is closer to the medial axis, + the surface must be sufficiently well sampled so that the Voronoi poles lie on the media axis (see Amenta's paper). + Propose the usage of the isotropic remeshing and see if we add a boolean to do it automatically in the api (correspondance would be broken) \todo code: implement the random sampling of surface using the work started by Alexandru during its gsoc to get a better approximation of poles \todo code: expose in polygon mesh processing the function to compute the voronoi pole of a close triangle mesh \todo code: expose in polygon mesh processing the function to remesh locally a triangle mesh with the angle and edge length parameters From 72c7781b56d49b716e79ad8f575ad1b9459bd3e4 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Mon, 21 Sep 2015 11:59:07 +0200 Subject: [PATCH 157/217] Comment add_edge(V,V, OM) as it conflicts with Euler::add_edge(V,V,MFG) --- .../CGAL/boost/graph/graph_traits_PolyMesh_ArrayKernelT.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/BGL/include/CGAL/boost/graph/graph_traits_PolyMesh_ArrayKernelT.h b/BGL/include/CGAL/boost/graph/graph_traits_PolyMesh_ArrayKernelT.h index 393a79de179..6899216356c 100644 --- a/BGL/include/CGAL/boost/graph/graph_traits_PolyMesh_ArrayKernelT.h +++ b/BGL/include/CGAL/boost/graph/graph_traits_PolyMesh_ArrayKernelT.h @@ -612,7 +612,7 @@ remove_face(typename boost::graph_traits >::f sm.status(f).set_deleted(true); } - +#if 0 // conflits with function in Euler_operations.h template std::pair >::edge_descriptor, bool> @@ -622,6 +622,7 @@ add_edge(typename boost::graph_traits >::vert return sm.new_edge(v1, v2); } +#endif template typename boost::graph_traits >::face_descriptor From 66b3d24af3022632930bf816e53e25f0b8beb820 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Mon, 21 Sep 2015 12:00:11 +0200 Subject: [PATCH 158/217] Add converter between models of FaceGraph --- BGL/examples/BGL_polyhedron_3/CMakeLists.txt | 73 +++++++++++++++++++ .../polyhedron_2_OpenMesh.cpp | 48 ++++++++++++ .../CGAL/boost/graph/convert_surface_mesh.h | 64 ++++++++++++++++ 3 files changed, 185 insertions(+) create mode 100644 BGL/examples/BGL_polyhedron_3/CMakeLists.txt create mode 100644 BGL/examples/BGL_polyhedron_3/polyhedron_2_OpenMesh.cpp create mode 100644 BGL/include/CGAL/boost/graph/convert_surface_mesh.h diff --git a/BGL/examples/BGL_polyhedron_3/CMakeLists.txt b/BGL/examples/BGL_polyhedron_3/CMakeLists.txt new file mode 100644 index 00000000000..a84cf7493c0 --- /dev/null +++ b/BGL/examples/BGL_polyhedron_3/CMakeLists.txt @@ -0,0 +1,73 @@ +# Created by the script cgal_create_CMakeLists +# This is the CMake script for compiling a set of CGAL applications. + +project( BGL_polyhedron_3 ) + + +cmake_minimum_required(VERSION 2.8.11) + +# CGAL and its components +find_package( CGAL QUIET COMPONENTS ) + +if ( NOT CGAL_FOUND ) + + message(STATUS "This project requires the CGAL library, and will not be compiled.") + return() + +endif() + +# include helper file +include( ${CGAL_USE_FILE} ) + + +# Boost and its components +find_package( Boost REQUIRED ) + +if ( NOT Boost_FOUND ) + + message(STATUS "This project requires the Boost library, and will not be compiled.") + + return() + +endif() + +find_package( OpenMesh QUIET ) + +if ( OpenMesh_FOUND ) +include( UseOpenMesh ) +else() + message(STATUS "Examples that use OpenMesh will not be compiled.") +endif() + +# include for local directory + +# include for local package +include_directories( BEFORE ../../include ) + + +# Creating entries for all C++ files with "main" routine +# ########################################################## + +include( CGAL_CreateSingleSourceCGALProgram ) + +create_single_source_cgal_program( "distance.cpp" ) + +create_single_source_cgal_program( "incident_vertices.cpp" ) + +create_single_source_cgal_program( "kruskal.cpp" ) + +create_single_source_cgal_program( "kruskal_with_stored_id.cpp" ) + +create_single_source_cgal_program( "normals.cpp" ) + +create_single_source_cgal_program( "range.cpp" ) + +create_single_source_cgal_program( "transform_iterator.cpp" ) + + + +if(OpenMesh_FOUND) + create_single_source_cgal_program( "polyhedron_2_OpenMesh.cpp" ) + target_link_libraries( polyhedron_2_OpenMesh ${OPENMESH_LIBRARIES} ) +endif() + diff --git a/BGL/examples/BGL_polyhedron_3/polyhedron_2_OpenMesh.cpp b/BGL/examples/BGL_polyhedron_3/polyhedron_2_OpenMesh.cpp new file mode 100644 index 00000000000..06c26ff04de --- /dev/null +++ b/BGL/examples/BGL_polyhedron_3/polyhedron_2_OpenMesh.cpp @@ -0,0 +1,48 @@ + +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include + +#include +#include + + +typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; +typedef Kernel::Vector_3 Vector; +typedef Kernel::Point_3 Point; +typedef CGAL::Polyhedron_3 Source; + +typedef OpenMesh::PolyMesh_ArrayKernelT Target; + +typedef boost::graph_traits::vertex_descriptor sm_vertex_descriptor; +typedef boost::graph_traits::vertex_descriptor tm_vertex_descriptor; + +typedef boost::graph_traits::halfedge_descriptor sm_halfedge_descriptor; +typedef boost::graph_traits::halfedge_descriptor tm_halfedge_descriptor; + +boost::unordered_map v2v; +boost::unordered_map h2h; + +int main(int, char* argv[]) +{ + Source S; + Target T; + std::ifstream in(argv[1]); + in >> S; + + convert_surface_mesh(S,T,v2v,h2h); + + OpenMesh::IO::write_mesh(T, "om.off"); + + return 0; +} diff --git a/BGL/include/CGAL/boost/graph/convert_surface_mesh.h b/BGL/include/CGAL/boost/graph/convert_surface_mesh.h new file mode 100644 index 00000000000..55cf23dd01c --- /dev/null +++ b/BGL/include/CGAL/boost/graph/convert_surface_mesh.h @@ -0,0 +1,64 @@ + + +#ifndef CGAL_BOOST_GRAPH_CONVERT_SURFACE_MESH_H +#define CGAL_BOOST_GRAPH_CONVERT_SURFACE_MESH_H + +#include +#include + + +namespace CGAL { + + template + void convert_surface_mesh(const SourceMesh& sm, TargetMesh& tm, V2V& v2v, H2H& h2h) +{ + typedef boost::graph_traits::vertex_descriptor sm_vertex_descriptor; + typedef boost::graph_traits::vertex_descriptor tm_vertex_descriptor; + + typedef boost::graph_traits::face_descriptor sm_face_descriptor; + typedef boost::graph_traits::face_descriptor tm_face_descriptor; + + typedef boost::graph_traits::halfedge_descriptor sm_halfedge_descriptor; + typedef boost::graph_traits::halfedge_descriptor tm_halfedge_descriptor; + + typedef typename boost::property_map::const_type sm_PMap; + typedef typename boost::property_map::const_type tm_PMap; + + sm_PMap sm_pmap = get(vertex_point, sm); + tm_PMap tm_pmap = get(vertex_point, tm); + + + BOOST_FOREACH(sm_vertex_descriptor svd, vertices(sm)){ + tm_vertex_descriptor tvd = add_vertex(tm); + v2v[svd] = tvd; + put(tm_pmap, tvd, get(sm_pmap, svd)); + } + + boost::unordered_map f2f; + BOOST_FOREACH(sm_face_descriptor sfd, faces(sm)){ + std::vector tv; + BOOST_FOREACH(sm_vertex_descriptor svd, vertices_around_face(halfedge(sfd,sm),sm)){ + tv.push_back(v2v[svd]); + } + f2f[sfd] = Euler::add_face(tv,tm); + } + + BOOST_FOREACH(sm_face_descriptor sfd, faces(sm)){ + sm_halfedge_descriptor shd = halfedge(sfd,sm), done(shd); + tm_halfedge_descriptor thd = halfedge(f2f[sfd],tm); + tm_vertex_descriptor tvd = v2v[target(shd,sm)]; + while(target(thd,tm) != tvd){ + thd = next(thd,tm); + } + do { + h2h[shd] = thd; + shd = next(shd,sm); + thd = next(thd,tm); + }while(shd != done); + } + +} + +} // namespace CGAL + +#endif // CGAL_BOOST_GRAPH_CONVERT_SURFACE_MESH_H From cff5745e3d62b443f3bb35e7572a5377f44c9d2c Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Mon, 21 Sep 2015 14:53:42 +0200 Subject: [PATCH 159/217] Duplicate the graph traits from PolyMesh to TriMesh --- BGL/examples/BGL_OpenMesh/CMakeLists.txt | 57 ++ BGL/examples/BGL_OpenMesh/TriMesh.cpp | 51 ++ .../graph/graph_traits_TriMesh_ArrayKernelT.h | 680 ++++++++++++++++++ .../graph/properties_TriMesh_ArrayKernelT.h | 356 +++++++++ 4 files changed, 1144 insertions(+) create mode 100644 BGL/examples/BGL_OpenMesh/CMakeLists.txt create mode 100644 BGL/examples/BGL_OpenMesh/TriMesh.cpp create mode 100644 BGL/include/CGAL/boost/graph/graph_traits_TriMesh_ArrayKernelT.h create mode 100644 BGL/include/CGAL/boost/graph/properties_TriMesh_ArrayKernelT.h diff --git a/BGL/examples/BGL_OpenMesh/CMakeLists.txt b/BGL/examples/BGL_OpenMesh/CMakeLists.txt new file mode 100644 index 00000000000..02119ee3340 --- /dev/null +++ b/BGL/examples/BGL_OpenMesh/CMakeLists.txt @@ -0,0 +1,57 @@ +# Created by the script cgal_create_CMakeLists +# This is the CMake script for compiling a set of CGAL applications. + +project( BGL_OpenMesh ) + + +cmake_minimum_required(VERSION 2.8.11) + +# CGAL and its components +find_package( CGAL QUIET COMPONENTS ) + +if ( NOT CGAL_FOUND ) + + message(STATUS "This project requires the CGAL library, and will not be compiled.") + return() + +endif() + +# include helper file +include( ${CGAL_USE_FILE} ) + + +# Boost and its components +find_package( Boost REQUIRED ) + +if ( NOT Boost_FOUND ) + + message(STATUS "This project requires the Boost library, and will not be compiled.") + + return() + +endif() + +find_package( OpenMesh QUIET ) + +if ( OpenMesh_FOUND ) +include( UseOpenMesh ) +else() + message(STATUS "Examples that use OpenMesh will not be compiled.") +endif() + +# include for local directory + +# include for local package +include_directories( BEFORE ../../include ) + + +# Creating entries for all C++ files with "main" routine +# ########################################################## + +include( CGAL_CreateSingleSourceCGALProgram ) + +if(OpenMesh_FOUND) +create_single_source_cgal_program( "TriMesh.cpp" ) + target_link_libraries( TriMesh ${OPENMESH_LIBRARIES} ) +endif() + diff --git a/BGL/examples/BGL_OpenMesh/TriMesh.cpp b/BGL/examples/BGL_OpenMesh/TriMesh.cpp new file mode 100644 index 00000000000..c28e11f7886 --- /dev/null +++ b/BGL/examples/BGL_OpenMesh/TriMesh.cpp @@ -0,0 +1,51 @@ + +#include + +#include +#include + +#include +#include +#include + +#include + +#include + +#include +#include + +#include + +typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; + +typedef OpenMesh::TriMesh_ArrayKernelT Mesh; + +typedef boost::graph_traits::vertex_descriptor vertex_descriptor; +typedef boost::graph_traits::face_descriptor face_descriptor; +typedef boost::graph_traits::halfedge_descriptor halfedge_descriptor; + + +int main(int argc, char** argv ) +{ + Mesh mesh; + + std::vector V; + V.push_back(add_vertex(mesh)); + V.push_back(add_vertex(mesh)); + V.push_back(add_vertex(mesh)); + add_face(V.begin(), V.end(), mesh); + + // OpenMesh::IO::read_mesh(mesh, (argc>1)?argv[1]:"in.off"); + + BOOST_FOREACH(vertex_descriptor vd, vertices(mesh)){ + BOOST_FOREACH(halfedge_descriptor hd, CGAL::halfedges_around_target(vd,mesh)){ + if(! CGAL::is_border(edge(hd,mesh),mesh)){ + CGAL::Euler::flip_edge(hd,mesh); + OpenMesh::IO::write_mesh(mesh, (argc>2)?argv[2]:"out.off"); + return 0; + } + } + } + return 0; +} diff --git a/BGL/include/CGAL/boost/graph/graph_traits_TriMesh_ArrayKernelT.h b/BGL/include/CGAL/boost/graph/graph_traits_TriMesh_ArrayKernelT.h new file mode 100644 index 00000000000..075cfa52265 --- /dev/null +++ b/BGL/include/CGAL/boost/graph/graph_traits_TriMesh_ArrayKernelT.h @@ -0,0 +1,680 @@ +// Copyright (c) 2007 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 Lesser 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) : Andreas Fabri, Philipp Moeller + +#ifndef CGAL_BOOST_GRAPH_GRAPH_TRAITS_TRIMESH_ARRAYKERNELT_H +#define CGAL_BOOST_GRAPH_GRAPH_TRAITS_TRIMESH_ARRAYKERNELT_H + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include + +// http://openmesh.org/Documentation/OpenMesh-Doc-Latest/classOpenMesh_1_1Concepts_1_1KernelT.html + +#if defined(BOOST_MSVC) +# pragma warning(push) +# pragma warning(disable:4267) +#endif +namespace CGAL { namespace internal { + + +template +class OMesh_edge { +public: + OMesh_edge() : halfedge_() {} + explicit OMesh_edge(const Halfedge_handle& h) : halfedge_(h) {} + Halfedge_handle halfedge() const { return halfedge_; } + bool is_valid() const { return halfedge_.is_valid(); } + + bool + operator==(const OMesh_edge& other) { + if(halfedge_ == other.halfedge_) { + return true; + } else if(halfedge_ != Halfedge_handle()) { + return opposite() == other.halfedge_; + } else { + return false; + } + } + + bool operator<(const OMesh_edge& other) const + { + return this->idx() < other.idx(); + } + + bool + operator!=(const OMesh_edge& other) { return !(*this == other); } + + Halfedge_handle + opposite() const { return Halfedge_handle((halfedge_.idx() & 1) ? halfedge_.idx()-1 : halfedge_.idx()+1); } + + OMesh_edge + opposite_edge() const { return OMesh_edge(Halfedge_handle((halfedge_.idx() & 1) ? halfedge_.idx()-1 : halfedge_.idx()+1)); } + + unsigned int idx() const { return halfedge_.idx() / 2; } +private: + Halfedge_handle halfedge_; +}; + +template +struct Convert_omesh_edge +{ + typedef OMesh_edge result_type; + result_type operator()(const OMeshEdge& h) const { + return result_type(Halfedge_handle(h.idx() * 2)); + } +}; + +template +struct Construct_omesh_edge +{ + typedef OMesh_edge result_type; + template + result_type operator()(const T& h) const { return result_type(h); } +}; + +template +struct Construct_omesh_edge_opposite +{ + typedef OMesh_edge result_type; + template + result_type operator()(const T& h) const { return result_type(h).opposite_edge(); } +}; + + +} // internal +} // CGAL + + +namespace boost { + +template +struct graph_traits< OpenMesh::TriMesh_ArrayKernelT > +{ +private: + typedef OpenMesh::TriMesh_ArrayKernelT SM; + + struct SM_graph_traversal_category : public virtual boost::bidirectional_graph_tag, + public virtual boost::vertex_list_graph_tag, + public virtual boost::edge_list_graph_tag + {}; + +public: + // Graph + typedef typename SM::VertexHandle vertex_descriptor; + typedef typename SM::Point vertex_property_type; + typedef typename CGAL::internal::OMesh_edge edge_descriptor; + typedef boost::undirected_tag directed_category; + typedef boost::disallow_parallel_edge_tag edge_parallel_category; + typedef SM_graph_traversal_category traversal_category; + + // HalfedgeGraph + typedef typename SM::HalfedgeHandle halfedge_descriptor; + + // FaceGraph + typedef typename SM::FaceHandle face_descriptor; + + // VertexListGraph + typedef typename SM::VertexIter vertex_iterator; + typedef unsigned int vertices_size_type; + // EdgeListGraph + typedef boost::transform_iterator< + CGAL::internal::Convert_omesh_edge, + typename SM::EdgeIter, + edge_descriptor> edge_iterator; + + typedef unsigned int edges_size_type; + // HalfEdgeListGraph + typedef typename SM::HalfedgeIter halfedge_iterator; + typedef unsigned int halfedges_size_type; + // FaceListGraph + typedef typename SM::FaceIter face_iterator; + typedef unsigned int faces_size_type; + + // IncidenceGraph + typedef unsigned int degree_size_type; + + + typedef CGAL::In_edge_iterator in_edge_iterator; + + typedef CGAL::Out_edge_iterator out_edge_iterator; + + // nulls + static vertex_descriptor null_vertex() { return vertex_descriptor(); } + static face_descriptor null_face() { return face_descriptor(); } + static halfedge_descriptor null_halfedge() { return halfedge_descriptor(); } +}; + +template +struct graph_traits< const OpenMesh::TriMesh_ArrayKernelT > + : public graph_traits< OpenMesh::TriMesh_ArrayKernelT > +{ }; + +} // namespace boost + +namespace OpenMesh { + +template +typename boost::graph_traits >::vertices_size_type +num_vertices(const OpenMesh::TriMesh_ArrayKernelT& sm) +{ + return sm.n_vertices(); +} + + +template +typename boost::graph_traits >::edges_size_type +num_edges(const OpenMesh::TriMesh_ArrayKernelT& sm) +{ + return sm.n_edges(); +} + + +template +typename boost::graph_traits >::degree_size_type +degree(typename boost::graph_traits >::vertex_descriptor v, + const OpenMesh::TriMesh_ArrayKernelT& sm) +{ + return sm.valence(v); +} + + +template +typename boost::graph_traits >::degree_size_type +out_degree(typename boost::graph_traits >::vertex_descriptor v, + const OpenMesh::TriMesh_ArrayKernelT& sm) +{ + return sm.valence(v); +} + + +template +typename boost::graph_traits >::degree_size_type +in_degree(typename boost::graph_traits >::vertex_descriptor v, + const OpenMesh::TriMesh_ArrayKernelT& sm) +{ + return sm.valence(v); +} + + +template +typename boost::graph_traits >::vertex_descriptor +source(typename boost::graph_traits >::edge_descriptor e, + const OpenMesh::TriMesh_ArrayKernelT& sm) +{ + return sm.from_vertex_handle(e.halfedge()); +} + +template +typename boost::graph_traits >::vertex_descriptor +source(typename boost::graph_traits >::halfedge_descriptor h, + const OpenMesh::TriMesh_ArrayKernelT& sm) +{ + return sm.from_vertex_handle(h); +} + + +template +typename boost::graph_traits >::vertex_descriptor +target(typename boost::graph_traits >::edge_descriptor e, + const OpenMesh::TriMesh_ArrayKernelT& sm) +{ + return sm.to_vertex_handle(e.halfedge()); +} + +template +typename boost::graph_traits >::vertex_descriptor +target(typename boost::graph_traits >::halfedge_descriptor h, + const OpenMesh::TriMesh_ArrayKernelT& sm) +{ + return sm.to_vertex_handle(h); +} + +template +CGAL::Iterator_range >::vertex_iterator> +vertices(const OpenMesh::TriMesh_ArrayKernelT& sm) +{ + return CGAL::make_range(sm.vertices_sbegin(), sm.vertices_end()); +} + + +template +CGAL::Iterator_range >::edge_iterator> +edges(const OpenMesh::TriMesh_ArrayKernelT& sm) +{ + typedef typename boost::graph_traits >::edge_iterator iterator; + iterator beg(sm.edges_sbegin()); + iterator end(sm.edges_end()); + return CGAL::make_range(beg,end); +} + + +template +CGAL::Iterator_range >::in_edge_iterator> +in_edges(typename boost::graph_traits >::vertex_descriptor v, + const OpenMesh::TriMesh_ArrayKernelT& sm) +{ + typedef typename boost::graph_traits >::in_edge_iterator Iter; + + return CGAL::make_range(Iter(halfedge(v,sm),sm), Iter(halfedge(v,sm),sm,1)); +} + + +template +CGAL::Iterator_range >::out_edge_iterator> +out_edges(typename boost::graph_traits >::vertex_descriptor v, + const OpenMesh::TriMesh_ArrayKernelT& sm) +{ + typedef typename boost::graph_traits >::out_edge_iterator Iter; + return CGAL::make_range(Iter(halfedge(v,sm),sm), Iter(halfedge(v,sm),sm,1)); +} + + +template +std::pair >::edge_descriptor, + bool> +edge(typename boost::graph_traits >::vertex_descriptor u, + typename boost::graph_traits >::vertex_descriptor v, + const OpenMesh::TriMesh_ArrayKernelT& sm) { + typename boost::graph_traits >::edge_descriptor + he(sm.find_halfedge(u, v)); + return std::make_pair(he, he.is_valid()); +} + + +// +// HalfedgeGraph +// +template +typename boost::graph_traits >::halfedge_descriptor +next(typename boost::graph_traits >::halfedge_descriptor h, + const OpenMesh::TriMesh_ArrayKernelT& sm) +{ + return sm.next_halfedge_handle(h); +} + +template +typename boost::graph_traits >::halfedge_descriptor +prev(typename boost::graph_traits >::halfedge_descriptor h, + const OpenMesh::TriMesh_ArrayKernelT& sm) +{ + return sm.prev_halfedge_handle(h); +} + +template +typename boost::graph_traits >::halfedge_descriptor +opposite(typename boost::graph_traits >::halfedge_descriptor h, + const OpenMesh::TriMesh_ArrayKernelT& sm) +{ + return sm.opposite_halfedge_handle(h); +} + +template +typename boost::graph_traits >::edge_descriptor +edge(typename boost::graph_traits >::halfedge_descriptor h, + const OpenMesh::TriMesh_ArrayKernelT& /*sm*/) +{ + return typename boost::graph_traits >::edge_descriptor(h); +} + +template +typename boost::graph_traits >::halfedge_descriptor +halfedge(typename boost::graph_traits >::edge_descriptor e, + const OpenMesh::TriMesh_ArrayKernelT&) +{ + return e.halfedge(); +} + +template +typename boost::graph_traits >::halfedge_descriptor +halfedge(typename boost::graph_traits >::vertex_descriptor v, + const OpenMesh::TriMesh_ArrayKernelT& sm) +{ + // prev because OpenMesh stores out-going halfedges + // return sm.prev_halfedge_handle(sm.halfedge_handle(v)); + return sm.opposite_halfedge_handle(sm.halfedge_handle(v)); +} + + +template +std::pair< + typename boost::graph_traits >::halfedge_descriptor, + bool +> +halfedge(typename boost::graph_traits >::vertex_descriptor u, + typename boost::graph_traits >::vertex_descriptor v, + const OpenMesh::TriMesh_ArrayKernelT& sm) +{ + typename boost::graph_traits >::halfedge_descriptor h = sm.find_halfedge(u, v); + return std::make_pair(h, h.is_valid()); +} + + + +// +// HalfedgeListGraph +// +template +CGAL::Iterator_range >::halfedge_iterator> +halfedges(const OpenMesh::TriMesh_ArrayKernelT& sm) +{ + return CGAL::make_range(sm.halfedges_sbegin(), sm.halfedges_end()); +} + +template +typename boost::graph_traits >::halfedges_size_type +num_halfedges(const OpenMesh::TriMesh_ArrayKernelT& sm) +{ + return sm.n_halfedges(); +} + + + +// +// MutableHalfedgeGraph +// +template +void +set_next(typename boost::graph_traits >::halfedge_descriptor h1, + typename boost::graph_traits >::halfedge_descriptor h2, + OpenMesh::TriMesh_ArrayKernelT& sm) +{ + sm.set_next_halfedge_handle(h1, h2); +} + + + +template +void +set_target(typename boost::graph_traits >::halfedge_descriptor h, + typename boost::graph_traits >::vertex_descriptor v, + OpenMesh::TriMesh_ArrayKernelT& sm) +{ + sm.set_vertex_handle(h, v); +} + + +template +void +set_halfedge(typename boost::graph_traits >::vertex_descriptor v, + typename boost::graph_traits >::halfedge_descriptor h, + OpenMesh::TriMesh_ArrayKernelT& sm) +{ + sm.set_halfedge_handle(v, sm.opposite_halfedge_handle(h)); +} + + +template +void +adjust_border_halfedge(typename boost::graph_traits >::vertex_descriptor v, + OpenMesh::TriMesh_ArrayKernelT& sm) +{ + sm.adjust_outgoing_halfedge(v); +} + +template +void +garbage_collection(OpenMesh::TriMesh_ArrayKernelT& sm) +{ + sm.garbage_collection(); +} + +template +typename boost::graph_traits >::edge_descriptor +add_edge(OpenMesh::TriMesh_ArrayKernelT& sm) +{ + return edge(sm.new_edge(boost::graph_traits >::null_vertex(), + boost::graph_traits >::null_vertex() ), sm); +} + + +// +// FaceGraph +// +template +typename boost::graph_traits >::halfedge_descriptor +halfedge(typename boost::graph_traits >::face_descriptor f, + const OpenMesh::TriMesh_ArrayKernelT& sm) +{ + return sm.halfedge_handle(f); +} + +template +typename boost::graph_traits >::face_descriptor +face(typename boost::graph_traits >::halfedge_descriptor h, + const OpenMesh::TriMesh_ArrayKernelT& sm) +{ + return sm.face_handle(h); +} + + + +// +// MutableFaceGraph +// +template +void +set_face(typename boost::graph_traits >::halfedge_descriptor h, + typename boost::graph_traits >::face_descriptor f, + OpenMesh::TriMesh_ArrayKernelT& sm) +{ + sm.set_face_handle(h, f); +} + + +template +void +set_halfedge(typename boost::graph_traits >::face_descriptor f, + typename boost::graph_traits >::halfedge_descriptor h, + OpenMesh::TriMesh_ArrayKernelT& sm) +{ + sm.set_halfedge_handle(f, h); +} + + +// +// FaceListGraph +// +template +typename boost::graph_traits >::faces_size_type +num_faces(const OpenMesh::TriMesh_ArrayKernelT& sm) +{ + return sm.n_faces(); +} + +template +CGAL::Iterator_range >::face_iterator> +faces(const OpenMesh::TriMesh_ArrayKernelT& sm) +{ + return CGAL::make_range(sm.faces_sbegin(), sm.faces_end()); +} + + +template +typename boost::graph_traits >::vertex_descriptor +add_vertex(OpenMesh::TriMesh_ArrayKernelT& sm) { + return sm.new_vertex(); +} + + /* + +// MutableGraph +// add a vertex with a default constructed property +template +typename boost::graph_traits >::vertex_descriptor +add_vertex(OpenMesh::TriMesh_ArrayKernelT& sm) { + return sm.add_vertex(typename boost::graph_traits >::vertex_property_type()); +} + +template +typename boost::graph_traits >::vertex_descriptor +add_vertex(const typename boost::graph_traits >::vertex_property_type& p, OpenMesh::TriMesh_ArrayKernelT& sm) { + return sm.add_vertex(p); +} + +template +void +clear_vertex(typename boost::graph_traits >::vertex_descriptor, + OpenMesh::TriMesh_ArrayKernelT&) { + CGAL_assert(false); +} + + */ + +template +void +remove_vertex(typename boost::graph_traits >::vertex_descriptor v, + OpenMesh::TriMesh_ArrayKernelT& sm) { + + sm.request_face_status(); + sm.request_vertex_status(); + sm.request_halfedge_status(); + sm.set_halfedge_handle(v, typename boost::graph_traits >::halfedge_descriptor()); + sm.status(v).set_deleted(true); +} + + +template +void +remove_edge(typename boost::graph_traits >::vertex_descriptor u, + typename boost::graph_traits >::vertex_descriptor v, + OpenMesh::TriMesh_ArrayKernelT& sm) +{ + typename boost::graph_traits >::edge_descriptor e = edge(u, v, sm); + remove_edge(e,sm); +} + +template +void +remove_edge(typename boost::graph_traits >::edge_descriptor e, + OpenMesh::TriMesh_ArrayKernelT& sm) +{ + sm.request_face_status(); + sm.request_vertex_status(); + sm.request_halfedge_status(); + sm.request_edge_status(); + + typedef typename boost::graph_traits >::halfedge_descriptor halfedge_descriptor; + + halfedge_descriptor h1 = halfedge(e,sm); + halfedge_descriptor h2 = opposite(halfedge(e,sm),sm); + sm.status(sm.edge_handle(h1)).set_deleted(true); + sm.status(h1).set_deleted(true); + sm.status(h2).set_deleted(true); + +} + + +template +void +remove_edge(typename boost::graph_traits >::edge_iterator eiter, + OpenMesh::TriMesh_ArrayKernelT& sm) +{ + remove_edge(*eiter, sm); +} + +template +void +remove_face(typename boost::graph_traits >::face_descriptor f, + OpenMesh::TriMesh_ArrayKernelT& sm) +{ + + sm.request_face_status(); + sm.request_vertex_status(); + sm.request_halfedge_status(); + + set_halfedge(f, typename boost::graph_traits >::halfedge_descriptor(), sm); + sm.status(f).set_deleted(true); +} + +#if 0 // conflits with function in Euler_operations.h +template +std::pair >::edge_descriptor, + bool> +add_edge(typename boost::graph_traits >::vertex_descriptor v1, + typename boost::graph_traits >::vertex_descriptor v2, + OpenMesh::TriMesh_ArrayKernelT& sm) { + + return sm.new_edge(v1, v2); +} +#endif + +template +typename boost::graph_traits >::face_descriptor +add_face(OpenMesh::TriMesh_ArrayKernelT& sm) +{ + return sm.new_face(); +} + +template +typename boost::graph_traits >::face_descriptor +add_face(InputIterator begin, InputIterator end, OpenMesh::TriMesh_ArrayKernelT& sm) +{ + typedef typename boost::graph_traits >::vertex_descriptor vertex_descriptor; + assert(begin!= end); + vertex_descriptor u = *begin; + ++begin; + assert(begin!= end); + vertex_descriptor v = *begin; + ++begin; + assert(begin!= end); + vertex_descriptor w = *begin; + + return sm.add_face(u,v,w); +} + +template +bool is_valid(OpenMesh::TriMesh_ArrayKernelT& sm, bool /* verbose */ = false) +{ + return CGAL::is_valid_polygon_mesh(sm); +} + +} // namespace OpenMesh + + +#ifndef CGAL_NO_DEPRECATED_CODE +#include + +namespace boost { + // The following functions were defined in the namespace boost + using OpenMesh::vertices; + using OpenMesh::edges; + using OpenMesh::num_vertices; + using OpenMesh::num_edges; + using OpenMesh::out_edges; + using OpenMesh::in_edges; + using OpenMesh::target; + using OpenMesh::source; +} // namespace boost +#endif //CGAL_NO_DEPRECATED_CODE + +#if defined(BOOST_MSVC) +# pragma warning(pop) +#endif + +#endif // CGAL_BOOST_GRAPH_TRAITS_TRIMESH_ARRAYKERNELT_H diff --git a/BGL/include/CGAL/boost/graph/properties_TriMesh_ArrayKernelT.h b/BGL/include/CGAL/boost/graph/properties_TriMesh_ArrayKernelT.h new file mode 100644 index 00000000000..e26b707c544 --- /dev/null +++ b/BGL/include/CGAL/boost/graph/properties_TriMesh_ArrayKernelT.h @@ -0,0 +1,356 @@ +// Copyright (c) 2014 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 Lesser 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) : Philipp Möller + + +#ifndef CGAL_PROPERTIES_TRIMESH_ARRAYKERNELT_H +#define CGAL_PROPERTIES_TRIMESH_ARRAYKERNELT_H + +#include +#include +#include +#include +#include + +namespace CGAL { + +template +class OM_pmap { +public: + typedef typename boost::mpl::if_::vertex_descriptor>, + OpenMesh::VPropHandleT, + typename boost::mpl::if_::face_descriptor>, + OpenMesh::FPropHandleT, + typename boost::mpl::if_::halfedge_descriptor>, + OpenMesh::HPropHandleT, + OpenMesh::EPropHandleT >::type>::type>::type H; + + typedef boost::read_write_property_map_tag category; + + typedef Descriptor key_type; + typedef Value value_type; + + typedef value_type& reference; + + OM_pmap(Mesh& m) + : mesh(m) + {} + + OM_pmap(Mesh& m, H h) + : mesh(m), h(h) + {} + + inline friend reference get(const OM_pmap& pm, key_type k) + { + return pm.mesh.property(pm.h,k); + } + + inline friend void put(const OM_pmap& pm, key_type k, const value_type& v) + { + pm.mesh.property(pm.h,k) = v; + } + + reference operator[](key_type k) + { + return mesh.property(h,k); + } + + H handle() const + { + return h; + } + + H& handle() + { + return h; + } + + Mesh& mesh; + H h; +}; + + +template +class OM_edge_weight_pmap + : public boost::put_get_helper::Scalar , OM_edge_weight_pmap > +{ +public: + typedef boost::readable_property_map_tag category; + typedef typename OpenMesh::TriMesh_ArrayKernelT::Scalar value_type; + typedef value_type reference; + typedef typename boost::graph_traits >::edge_descriptor key_type; + + OM_edge_weight_pmap(const OpenMesh::TriMesh_ArrayKernelT& sm) + : sm_(sm) + {} + + value_type operator[](const key_type& e) const + { + return sm_.calc_edge_length(e.halfedge()); + } + +private: + const OpenMesh::TriMesh_ArrayKernelT& sm_; +}; + +template +class OM_index_pmap : public boost::put_get_helper > +{ +public: + typedef boost::readable_property_map_tag category; + typedef unsigned int value_type; + typedef unsigned int reference; + typedef VEF key_type; + + value_type operator[](const key_type& vd) const + { + return vd.idx(); + } +}; + + + template +class OM_point_pmap //: public boost::put_get_helper > +{ +public: + typedef boost::read_write_property_map_tag category; +#if defined(CGAL_USE_OM_POINTS) + typedef typename OpenMesh::TriMesh_ArrayKernelT::Point value_type; + typedef const typename OpenMesh::TriMesh_ArrayKernelT::Point& reference; +#else + typedef P value_type; + typedef P reference; +#endif + typedef typename boost::graph_traits< OpenMesh::TriMesh_ArrayKernelT >::vertex_descriptor key_type; + + OM_point_pmap() + : sm_(NULL) + {} + + OM_point_pmap(const OpenMesh::TriMesh_ArrayKernelT& sm) + : sm_(&sm) + {} + + OM_point_pmap(const OM_point_pmap& pm) + : sm_(pm.sm_) + {} + + value_type operator[](key_type v) + { +#if defined(CGAL_USE_OM_POINTS) + return sm_->point(v); +#else + CGAL_assertion(sm_!=NULL); + typename OpenMesh::TriMesh_ArrayKernelT::Point const& omp = sm_->point(v); + return value_type(omp[0], omp[1], omp[2]); +#endif + } + + inline friend reference get(const OM_point_pmap& pm, key_type v) + { + CGAL_precondition(pm.sm_!=NULL); +#if defined(CGAL_USE_OM_POINTS) + return pm.sm_->point(v); +#else + CGAL_assertion(pm.sm_!=NULL); + typename OpenMesh::TriMesh_ArrayKernelT::Point const& omp = pm.sm_->point(v); + return value_type(omp[0], omp[1], omp[2]); +#endif + } + + inline friend void put(const OM_point_pmap& pm, key_type v, const value_type& p) + { + CGAL_precondition(pm.sm_!=NULL); +#if defined(CGAL_USE_OM_POINTS) + const_cast&>(*pm.sm_).set_point(v,p); +#else + const_cast&>(*pm.sm_).set_point + (v, typename OpenMesh::TriMesh_ArrayKernelT::Point((float)p[0], (float)p[1], (float)p[2])); +#endif + } + + private: + const OpenMesh::TriMesh_ArrayKernelT* sm_; +}; + + +} // CGAL + +// overloads and specializations in the boost namespace +namespace boost { + +// +// edge_weight +// + + +template +struct property_map, boost::edge_weight_t > +{ + typedef CGAL::OM_edge_weight_pmap type; + typedef CGAL::OM_edge_weight_pmap const_type; +}; + + + +// +// vertex_index +// + +template +struct property_map, boost::vertex_index_t > +{ + typedef CGAL::OM_index_pmap >::vertex_descriptor> type; + typedef CGAL::OM_index_pmap >::vertex_descriptor> const_type; +}; + + +// +// face_index +// + +template +struct property_map, boost::face_index_t > +{ + typedef CGAL::OM_index_pmap >::face_descriptor> type; + typedef CGAL::OM_index_pmap >::face_descriptor> const_type; +}; + +// +// edge_index +// + +template +struct property_map, boost::edge_index_t > +{ + typedef CGAL::OM_index_pmap >::edge_descriptor> type; + typedef CGAL::OM_index_pmap >::edge_descriptor> const_type; +}; + +// +// halfedge_index +// + +template +struct property_map, boost::halfedge_index_t > +{ + typedef CGAL::OM_index_pmap >::halfedge_descriptor> type; + typedef CGAL::OM_index_pmap >::halfedge_descriptor> const_type; +}; + + +template +struct property_map, boost::vertex_point_t > +{ + typedef CGAL::Exact_predicates_inexact_constructions_kernel::Point_3 P; + typedef CGAL::OM_point_pmap type; + typedef type const_type; +}; + +} // namespace boost + +namespace boost { + + +template +typename boost::property_map, boost::edge_weight_t>::const_type +get(boost::edge_weight_t, const OpenMesh::TriMesh_ArrayKernelT& sm) +{ + return CGAL::OM_edge_weight_pmap(sm); +} + +template +typename OpenMesh::TriMesh_ArrayKernelT::Scalar +get(boost::edge_weight_t, const OpenMesh::TriMesh_ArrayKernelT& sm, + const typename boost::graph_traits >::edge_descriptor& e) +{ + return CGAL::OM_edge_weight_pmap(sm)[e]; +} + + +template +CGAL::OM_index_pmap >::vertex_descriptor> +get(const boost::vertex_index_t&, const OpenMesh::TriMesh_ArrayKernelT&) +{ + return CGAL::OM_index_pmap >::vertex_descriptor>(); +} + +template +typename boost::property_map, boost::face_index_t>::const_type +get(const boost::face_index_t&, const OpenMesh::TriMesh_ArrayKernelT&) +{ + return CGAL::OM_index_pmap >::face_descriptor>(); +} + +template +CGAL::OM_index_pmap >::edge_descriptor> +get(const boost::edge_index_t&, const OpenMesh::TriMesh_ArrayKernelT&) +{ + return CGAL::OM_index_pmap >::edge_descriptor>(); +} + +template +CGAL::OM_index_pmap >::halfedge_descriptor> +get(const boost::halfedge_index_t&, const OpenMesh::TriMesh_ArrayKernelT&) +{ + return CGAL::OM_index_pmap >::halfedge_descriptor>(); +} + +template +CGAL::OM_point_pmap +get(boost::vertex_point_t, const OpenMesh::TriMesh_ArrayKernelT& g) +{ + typedef typename CGAL::Exact_predicates_inexact_constructions_kernel::Point_3 P; + return CGAL::OM_point_pmap(g); +} + +// get for intrinsic properties +#define CGAL_OM_INTRINSIC_PROPERTY(RET, PROP, TYPE) \ + template \ + RET \ + get(PROP p, const OpenMesh::TriMesh_ArrayKernelT& sm, \ + typename boost::graph_traits< OpenMesh::TriMesh_ArrayKernelT >::TYPE x) \ + { return get(get(p, sm), x); } \ + + CGAL_OM_INTRINSIC_PROPERTY(int, boost::vertex_index_t, vertex_descriptor) + CGAL_OM_INTRINSIC_PROPERTY(int, boost::edge_index_t, edge_descriptor) + CGAL_OM_INTRINSIC_PROPERTY(int, boost::halfedge_index_t, halfedge_descriptor) + CGAL_OM_INTRINSIC_PROPERTY(int, boost::face_index_t, face_descriptor) + // CGAL_OM_INTRINSIC_PROPERTY(std::size_t, boost::halfedge_index_t, face_descriptor) + CGAL_OM_INTRINSIC_PROPERTY(typename CGAL::Exact_predicates_inexact_constructions_kernel::Point_3, boost::vertex_point_t, vertex_descriptor) + +#undef CGAL_OM_INTRINSIC_PROPERTY + +// put for intrinsic properties +// only available for vertex_point + +template +void +put(boost::vertex_point_t p, OpenMesh::TriMesh_ArrayKernelT& g, + typename boost::graph_traits< OpenMesh::TriMesh_ArrayKernelT >::vertex_descriptor vd, + const typename K::Point& point) +{ + put(get(p,g), vd, point); +} + + +} // namespace boost + + + +#endif /* CGAL_PROPERTIES_TRIMESH_ARRAYKERNELT_H */ From 881a9aefcc6ddca021f2d30f29ae6cd676175526 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Mon, 21 Sep 2015 15:49:34 +0200 Subject: [PATCH 160/217] Check that the incident halfedge is not the null_halfedge It is astonishing that add_face works for the PolyMesh but not for the TriMesh. The function is_isolated(V) does not the right thing for a TriMesh --- .../CGAL/boost/graph/graph_traits_TriMesh_ArrayKernelT.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/BGL/include/CGAL/boost/graph/graph_traits_TriMesh_ArrayKernelT.h b/BGL/include/CGAL/boost/graph/graph_traits_TriMesh_ArrayKernelT.h index 075cfa52265..786e32754a4 100644 --- a/BGL/include/CGAL/boost/graph/graph_traits_TriMesh_ArrayKernelT.h +++ b/BGL/include/CGAL/boost/graph/graph_traits_TriMesh_ArrayKernelT.h @@ -355,6 +355,9 @@ typename boost::graph_traits >::halfedge_descr halfedge(typename boost::graph_traits >::vertex_descriptor v, const OpenMesh::TriMesh_ArrayKernelT& sm) { + if(sm.halfedge_handle(v) == boost::graph_traits >::null_halfedge()){ + return boost::graph_traits >::null_halfedge(); + } // prev because OpenMesh stores out-going halfedges // return sm.prev_halfedge_handle(sm.halfedge_handle(v)); return sm.opposite_halfedge_handle(sm.halfedge_handle(v)); From 1eb87f5a9ddc13ccba9b468a1332d92e3679951d Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Mon, 21 Sep 2015 16:05:46 +0200 Subject: [PATCH 161/217] #ifdef to switch between TriMesh and PolyMesh --- .../BGL_polyhedron_3/polyhedron_2_OpenMesh.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/BGL/examples/BGL_polyhedron_3/polyhedron_2_OpenMesh.cpp b/BGL/examples/BGL_polyhedron_3/polyhedron_2_OpenMesh.cpp index 06c26ff04de..fceb0523da3 100644 --- a/BGL/examples/BGL_polyhedron_3/polyhedron_2_OpenMesh.cpp +++ b/BGL/examples/BGL_polyhedron_3/polyhedron_2_OpenMesh.cpp @@ -6,8 +6,14 @@ #include #include + +#if 1 #include #include +#else +#include +#include +#endif #include @@ -22,8 +28,11 @@ typedef Kernel::Vector_3 Vector; typedef Kernel::Point_3 Point; typedef CGAL::Polyhedron_3 Source; +#if 1 typedef OpenMesh::PolyMesh_ArrayKernelT Target; - +#else +typedef OpenMesh::TriMesh_ArrayKernelT Target; +#endif typedef boost::graph_traits::vertex_descriptor sm_vertex_descriptor; typedef boost::graph_traits::vertex_descriptor tm_vertex_descriptor; From bb208ab2d662b693d356436b958228fe4ce04f31 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Mon, 21 Sep 2015 16:41:24 +0200 Subject: [PATCH 162/217] Fix halfedge(v, PolyMesh) + fixes for conversion from OpenMesh to Polyhedron --- .../polyhedron_2_OpenMesh.cpp | 38 +++++++++++++++++-- .../CGAL/boost/graph/convert_surface_mesh.h | 2 +- .../graph_traits_PolyMesh_ArrayKernelT.h | 3 ++ 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/BGL/examples/BGL_polyhedron_3/polyhedron_2_OpenMesh.cpp b/BGL/examples/BGL_polyhedron_3/polyhedron_2_OpenMesh.cpp index fceb0523da3..6282060f28c 100644 --- a/BGL/examples/BGL_polyhedron_3/polyhedron_2_OpenMesh.cpp +++ b/BGL/examples/BGL_polyhedron_3/polyhedron_2_OpenMesh.cpp @@ -39,8 +39,24 @@ typedef boost::graph_traits::vertex_descriptor tm_vertex_descriptor; typedef boost::graph_traits::halfedge_descriptor sm_halfedge_descriptor; typedef boost::graph_traits::halfedge_descriptor tm_halfedge_descriptor; -boost::unordered_map v2v; -boost::unordered_map h2h; +namespace OpenMesh { + +inline std::size_t hash_value(const VertexHandle& i) + { + return i.idx(); + } + +inline std::size_t hash_value(const HalfedgeHandle& i) + { + return i.idx(); + } + +inline std::size_t hash_value(const FaceHandle& i) + { + return i.idx(); + } + +} int main(int, char* argv[]) { @@ -49,9 +65,23 @@ int main(int, char* argv[]) std::ifstream in(argv[1]); in >> S; - convert_surface_mesh(S,T,v2v,h2h); + { + boost::unordered_map v2v; + boost::unordered_map h2h; + + convert_surface_mesh(S,T,v2v,h2h); + OpenMesh::IO::write_mesh(T, "om.off"); + } - OpenMesh::IO::write_mesh(T, "om.off"); + { + boost::unordered_map v2v; + boost::unordered_map h2h; + + convert_surface_mesh(T,S,v2v,h2h); + std::ofstream out("reverse.off"); + out << S << std::endl; + } + return 0; } diff --git a/BGL/include/CGAL/boost/graph/convert_surface_mesh.h b/BGL/include/CGAL/boost/graph/convert_surface_mesh.h index 55cf23dd01c..b074cca9821 100644 --- a/BGL/include/CGAL/boost/graph/convert_surface_mesh.h +++ b/BGL/include/CGAL/boost/graph/convert_surface_mesh.h @@ -22,7 +22,7 @@ namespace CGAL { typedef boost::graph_traits::halfedge_descriptor tm_halfedge_descriptor; typedef typename boost::property_map::const_type sm_PMap; - typedef typename boost::property_map::const_type tm_PMap; + typedef typename boost::property_map::type tm_PMap; sm_PMap sm_pmap = get(vertex_point, sm); tm_PMap tm_pmap = get(vertex_point, tm); diff --git a/BGL/include/CGAL/boost/graph/graph_traits_PolyMesh_ArrayKernelT.h b/BGL/include/CGAL/boost/graph/graph_traits_PolyMesh_ArrayKernelT.h index 6899216356c..220001a37b1 100644 --- a/BGL/include/CGAL/boost/graph/graph_traits_PolyMesh_ArrayKernelT.h +++ b/BGL/include/CGAL/boost/graph/graph_traits_PolyMesh_ArrayKernelT.h @@ -355,6 +355,9 @@ typename boost::graph_traits >::halfedge_desc halfedge(typename boost::graph_traits >::vertex_descriptor v, const OpenMesh::PolyMesh_ArrayKernelT& sm) { + if(sm.halfedge_handle(v) == boost::graph_traits >::null_halfedge()){ + return boost::graph_traits >::null_halfedge(); + } // prev because OpenMesh stores out-going halfedges // return sm.prev_halfedge_handle(sm.halfedge_handle(v)); return sm.opposite_halfedge_handle(sm.halfedge_handle(v)); From 4f9dc0b0ce1394241ae98b4cf6fcad4a14a1067e Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 22 Sep 2015 14:48:14 +0200 Subject: [PATCH 163/217] remove redundancy to avoid conflicts when both files are included --- .../graph/graph_traits_TriMesh_ArrayKernelT.h | 71 +------- .../graph/properties_PolyMesh_ArrayKernelT.h | 83 +++++---- .../graph/properties_TriMesh_ArrayKernelT.h | 172 +----------------- 3 files changed, 52 insertions(+), 274 deletions(-) diff --git a/BGL/include/CGAL/boost/graph/graph_traits_TriMesh_ArrayKernelT.h b/BGL/include/CGAL/boost/graph/graph_traits_TriMesh_ArrayKernelT.h index 786e32754a4..53e6a5754f4 100644 --- a/BGL/include/CGAL/boost/graph/graph_traits_TriMesh_ArrayKernelT.h +++ b/BGL/include/CGAL/boost/graph/graph_traits_TriMesh_ArrayKernelT.h @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -40,76 +41,6 @@ # pragma warning(push) # pragma warning(disable:4267) #endif -namespace CGAL { namespace internal { - - -template -class OMesh_edge { -public: - OMesh_edge() : halfedge_() {} - explicit OMesh_edge(const Halfedge_handle& h) : halfedge_(h) {} - Halfedge_handle halfedge() const { return halfedge_; } - bool is_valid() const { return halfedge_.is_valid(); } - - bool - operator==(const OMesh_edge& other) { - if(halfedge_ == other.halfedge_) { - return true; - } else if(halfedge_ != Halfedge_handle()) { - return opposite() == other.halfedge_; - } else { - return false; - } - } - - bool operator<(const OMesh_edge& other) const - { - return this->idx() < other.idx(); - } - - bool - operator!=(const OMesh_edge& other) { return !(*this == other); } - - Halfedge_handle - opposite() const { return Halfedge_handle((halfedge_.idx() & 1) ? halfedge_.idx()-1 : halfedge_.idx()+1); } - - OMesh_edge - opposite_edge() const { return OMesh_edge(Halfedge_handle((halfedge_.idx() & 1) ? halfedge_.idx()-1 : halfedge_.idx()+1)); } - - unsigned int idx() const { return halfedge_.idx() / 2; } -private: - Halfedge_handle halfedge_; -}; - -template -struct Convert_omesh_edge -{ - typedef OMesh_edge result_type; - result_type operator()(const OMeshEdge& h) const { - return result_type(Halfedge_handle(h.idx() * 2)); - } -}; - -template -struct Construct_omesh_edge -{ - typedef OMesh_edge result_type; - template - result_type operator()(const T& h) const { return result_type(h); } -}; - -template -struct Construct_omesh_edge_opposite -{ - typedef OMesh_edge result_type; - template - result_type operator()(const T& h) const { return result_type(h).opposite_edge(); } -}; - - -} // internal -} // CGAL - namespace boost { diff --git a/BGL/include/CGAL/boost/graph/properties_PolyMesh_ArrayKernelT.h b/BGL/include/CGAL/boost/graph/properties_PolyMesh_ArrayKernelT.h index d5c092e638a..9b72934c666 100644 --- a/BGL/include/CGAL/boost/graph/properties_PolyMesh_ArrayKernelT.h +++ b/BGL/include/CGAL/boost/graph/properties_PolyMesh_ArrayKernelT.h @@ -85,17 +85,17 @@ public: }; -template +template class OM_edge_weight_pmap - : public boost::put_get_helper::Scalar , OM_edge_weight_pmap > + : public boost::put_get_helper > { public: typedef boost::readable_property_map_tag category; - typedef typename OpenMesh::PolyMesh_ArrayKernelT::Scalar value_type; + typedef typename OpenMesh::Scalar value_type; typedef value_type reference; - typedef typename boost::graph_traits >::edge_descriptor key_type; + typedef typename boost::graph_traits::edge_descriptor key_type; - OM_edge_weight_pmap(const OpenMesh::PolyMesh_ArrayKernelT& sm) + OM_edge_weight_pmap(const OpenMesh& sm) : sm_(sm) {} @@ -105,7 +105,7 @@ public: } private: - const OpenMesh::PolyMesh_ArrayKernelT& sm_; + const OpenMesh& sm_; }; template @@ -124,25 +124,25 @@ public: }; - template -class OM_point_pmap //: public boost::put_get_helper > +template +class OM_point_pmap //: public boost::put_get_helper > { public: typedef boost::read_write_property_map_tag category; #if defined(CGAL_USE_OM_POINTS) - typedef typename OpenMesh::PolyMesh_ArrayKernelT::Point value_type; - typedef const typename OpenMesh::PolyMesh_ArrayKernelT::Point& reference; + typedef typename OpenMesh::Point value_type; + typedef const typename OpenMesh::Point& reference; #else typedef P value_type; typedef P reference; #endif - typedef typename boost::graph_traits< OpenMesh::PolyMesh_ArrayKernelT >::vertex_descriptor key_type; + typedef typename boost::graph_traits::vertex_descriptor key_type; OM_point_pmap() : sm_(NULL) {} - OM_point_pmap(const OpenMesh::PolyMesh_ArrayKernelT& sm) + OM_point_pmap(const OpenMesh& sm) : sm_(&sm) {} @@ -156,36 +156,36 @@ public: return sm_->point(v); #else CGAL_assertion(sm_!=NULL); - typename OpenMesh::PolyMesh_ArrayKernelT::Point const& omp = sm_->point(v); + typename OpenMesh::Point const& omp = sm_->point(v); return value_type(omp[0], omp[1], omp[2]); #endif } - inline friend reference get(const OM_point_pmap& pm, key_type v) + inline friend reference get(const OM_point_pmap& pm, key_type v) { CGAL_precondition(pm.sm_!=NULL); #if defined(CGAL_USE_OM_POINTS) return pm.sm_->point(v); #else CGAL_assertion(pm.sm_!=NULL); - typename OpenMesh::PolyMesh_ArrayKernelT::Point const& omp = pm.sm_->point(v); + typename OpenMesh::Point const& omp = pm.sm_->point(v); return value_type(omp[0], omp[1], omp[2]); #endif } - inline friend void put(const OM_point_pmap& pm, key_type v, const value_type& p) + inline friend void put(const OM_point_pmap& pm, key_type v, const value_type& p) { CGAL_precondition(pm.sm_!=NULL); #if defined(CGAL_USE_OM_POINTS) - const_cast&>(*pm.sm_).set_point(v,p); + const_cast(*pm.sm_).set_point(v,p); #else - const_cast&>(*pm.sm_).set_point - (v, typename OpenMesh::PolyMesh_ArrayKernelT::Point((float)p[0], (float)p[1], (float)p[2])); + const_cast(*pm.sm_).set_point + (v, typename OpenMesh::Point((float)p[0], (float)p[1], (float)p[2])); #endif } private: - const OpenMesh::PolyMesh_ArrayKernelT* sm_; + const OpenMesh* sm_; }; @@ -202,8 +202,9 @@ namespace boost { template struct property_map, boost::edge_weight_t > { - typedef CGAL::OM_edge_weight_pmap type; - typedef CGAL::OM_edge_weight_pmap const_type; + typedef OpenMesh::PolyMesh_ArrayKernelT Mesh; + typedef CGAL::OM_edge_weight_pmap type; + typedef CGAL::OM_edge_weight_pmap const_type; }; @@ -215,8 +216,9 @@ struct property_map, boost::edge_weight_t > template struct property_map, boost::vertex_index_t > { - typedef CGAL::OM_index_pmap >::vertex_descriptor> type; - typedef CGAL::OM_index_pmap >::vertex_descriptor> const_type; + typedef OpenMesh::PolyMesh_ArrayKernelT Mesh; + typedef CGAL::OM_index_pmap::vertex_descriptor> type; + typedef CGAL::OM_index_pmap::vertex_descriptor> const_type; }; @@ -227,8 +229,9 @@ struct property_map, boost::vertex_index_t > template struct property_map, boost::face_index_t > { - typedef CGAL::OM_index_pmap >::face_descriptor> type; - typedef CGAL::OM_index_pmap >::face_descriptor> const_type; + typedef OpenMesh::PolyMesh_ArrayKernelT Mesh; + typedef CGAL::OM_index_pmap::face_descriptor> type; + typedef CGAL::OM_index_pmap::face_descriptor> const_type; }; // @@ -238,8 +241,9 @@ struct property_map, boost::face_index_t > template struct property_map, boost::edge_index_t > { - typedef CGAL::OM_index_pmap >::edge_descriptor> type; - typedef CGAL::OM_index_pmap >::edge_descriptor> const_type; + typedef OpenMesh::PolyMesh_ArrayKernelT Mesh; + typedef CGAL::OM_index_pmap type; + typedef CGAL::OM_index_pmap const_type; }; // @@ -249,8 +253,9 @@ struct property_map, boost::edge_index_t > template struct property_map, boost::halfedge_index_t > { - typedef CGAL::OM_index_pmap >::halfedge_descriptor> type; - typedef CGAL::OM_index_pmap >::halfedge_descriptor> const_type; + typedef OpenMesh::PolyMesh_ArrayKernelT Mesh; + typedef CGAL::OM_index_pmap type; + typedef CGAL::OM_index_pmap const_type; }; @@ -258,7 +263,8 @@ template struct property_map, boost::vertex_point_t > { typedef CGAL::Exact_predicates_inexact_constructions_kernel::Point_3 P; - typedef CGAL::OM_point_pmap type; + typedef OpenMesh::PolyMesh_ArrayKernelT Mesh; + typedef CGAL::OM_point_pmap type; typedef type const_type; }; @@ -271,7 +277,8 @@ template typename boost::property_map, boost::edge_weight_t>::const_type get(boost::edge_weight_t, const OpenMesh::PolyMesh_ArrayKernelT& sm) { - return CGAL::OM_edge_weight_pmap(sm); + typedef OpenMesh::PolyMesh_ArrayKernelT Mesh; + return CGAL::OM_edge_weight_pmap(sm); } template @@ -279,7 +286,8 @@ typename OpenMesh::PolyMesh_ArrayKernelT::Scalar get(boost::edge_weight_t, const OpenMesh::PolyMesh_ArrayKernelT& sm, const typename boost::graph_traits >::edge_descriptor& e) { - return CGAL::OM_edge_weight_pmap(sm)[e]; + typedef OpenMesh::PolyMesh_ArrayKernelT Mesh; + return CGAL::OM_edge_weight_pmap(sm)[e]; } @@ -287,13 +295,15 @@ template CGAL::OM_index_pmap >::vertex_descriptor> get(const boost::vertex_index_t&, const OpenMesh::PolyMesh_ArrayKernelT&) { - return CGAL::OM_index_pmap >::vertex_descriptor>(); + typedef OpenMesh::PolyMesh_ArrayKernelT Mesh; + return CGAL::OM_index_pmap::vertex_descriptor>(); } template typename boost::property_map, boost::face_index_t>::const_type get(const boost::face_index_t&, const OpenMesh::PolyMesh_ArrayKernelT&) { + typedef OpenMesh::PolyMesh_ArrayKernelT Mesh; return CGAL::OM_index_pmap >::face_descriptor>(); } @@ -312,11 +322,12 @@ get(const boost::halfedge_index_t&, const OpenMesh::PolyMesh_ArrayKernelT&) } template -CGAL::OM_point_pmap +CGAL::OM_point_pmap, + typename CGAL::Exact_predicates_inexact_constructions_kernel::Point_3> get(boost::vertex_point_t, const OpenMesh::PolyMesh_ArrayKernelT& g) { typedef typename CGAL::Exact_predicates_inexact_constructions_kernel::Point_3 P; - return CGAL::OM_point_pmap(g); + return CGAL::OM_point_pmap, P>(g); } // get for intrinsic properties diff --git a/BGL/include/CGAL/boost/graph/properties_TriMesh_ArrayKernelT.h b/BGL/include/CGAL/boost/graph/properties_TriMesh_ArrayKernelT.h index e26b707c544..52b3563d289 100644 --- a/BGL/include/CGAL/boost/graph/properties_TriMesh_ArrayKernelT.h +++ b/BGL/include/CGAL/boost/graph/properties_TriMesh_ArrayKernelT.h @@ -24,172 +24,10 @@ #include #include #include +#include #include #include -namespace CGAL { - -template -class OM_pmap { -public: - typedef typename boost::mpl::if_::vertex_descriptor>, - OpenMesh::VPropHandleT, - typename boost::mpl::if_::face_descriptor>, - OpenMesh::FPropHandleT, - typename boost::mpl::if_::halfedge_descriptor>, - OpenMesh::HPropHandleT, - OpenMesh::EPropHandleT >::type>::type>::type H; - - typedef boost::read_write_property_map_tag category; - - typedef Descriptor key_type; - typedef Value value_type; - - typedef value_type& reference; - - OM_pmap(Mesh& m) - : mesh(m) - {} - - OM_pmap(Mesh& m, H h) - : mesh(m), h(h) - {} - - inline friend reference get(const OM_pmap& pm, key_type k) - { - return pm.mesh.property(pm.h,k); - } - - inline friend void put(const OM_pmap& pm, key_type k, const value_type& v) - { - pm.mesh.property(pm.h,k) = v; - } - - reference operator[](key_type k) - { - return mesh.property(h,k); - } - - H handle() const - { - return h; - } - - H& handle() - { - return h; - } - - Mesh& mesh; - H h; -}; - - -template -class OM_edge_weight_pmap - : public boost::put_get_helper::Scalar , OM_edge_weight_pmap > -{ -public: - typedef boost::readable_property_map_tag category; - typedef typename OpenMesh::TriMesh_ArrayKernelT::Scalar value_type; - typedef value_type reference; - typedef typename boost::graph_traits >::edge_descriptor key_type; - - OM_edge_weight_pmap(const OpenMesh::TriMesh_ArrayKernelT& sm) - : sm_(sm) - {} - - value_type operator[](const key_type& e) const - { - return sm_.calc_edge_length(e.halfedge()); - } - -private: - const OpenMesh::TriMesh_ArrayKernelT& sm_; -}; - -template -class OM_index_pmap : public boost::put_get_helper > -{ -public: - typedef boost::readable_property_map_tag category; - typedef unsigned int value_type; - typedef unsigned int reference; - typedef VEF key_type; - - value_type operator[](const key_type& vd) const - { - return vd.idx(); - } -}; - - - template -class OM_point_pmap //: public boost::put_get_helper > -{ -public: - typedef boost::read_write_property_map_tag category; -#if defined(CGAL_USE_OM_POINTS) - typedef typename OpenMesh::TriMesh_ArrayKernelT::Point value_type; - typedef const typename OpenMesh::TriMesh_ArrayKernelT::Point& reference; -#else - typedef P value_type; - typedef P reference; -#endif - typedef typename boost::graph_traits< OpenMesh::TriMesh_ArrayKernelT >::vertex_descriptor key_type; - - OM_point_pmap() - : sm_(NULL) - {} - - OM_point_pmap(const OpenMesh::TriMesh_ArrayKernelT& sm) - : sm_(&sm) - {} - - OM_point_pmap(const OM_point_pmap& pm) - : sm_(pm.sm_) - {} - - value_type operator[](key_type v) - { -#if defined(CGAL_USE_OM_POINTS) - return sm_->point(v); -#else - CGAL_assertion(sm_!=NULL); - typename OpenMesh::TriMesh_ArrayKernelT::Point const& omp = sm_->point(v); - return value_type(omp[0], omp[1], omp[2]); -#endif - } - - inline friend reference get(const OM_point_pmap& pm, key_type v) - { - CGAL_precondition(pm.sm_!=NULL); -#if defined(CGAL_USE_OM_POINTS) - return pm.sm_->point(v); -#else - CGAL_assertion(pm.sm_!=NULL); - typename OpenMesh::TriMesh_ArrayKernelT::Point const& omp = pm.sm_->point(v); - return value_type(omp[0], omp[1], omp[2]); -#endif - } - - inline friend void put(const OM_point_pmap& pm, key_type v, const value_type& p) - { - CGAL_precondition(pm.sm_!=NULL); -#if defined(CGAL_USE_OM_POINTS) - const_cast&>(*pm.sm_).set_point(v,p); -#else - const_cast&>(*pm.sm_).set_point - (v, typename OpenMesh::TriMesh_ArrayKernelT::Point((float)p[0], (float)p[1], (float)p[2])); -#endif - } - - private: - const OpenMesh::TriMesh_ArrayKernelT* sm_; -}; - - -} // CGAL // overloads and specializations in the boost namespace namespace boost { @@ -197,13 +35,12 @@ namespace boost { // // edge_weight // - - template struct property_map, boost::edge_weight_t > { - typedef CGAL::OM_edge_weight_pmap type; - typedef CGAL::OM_edge_weight_pmap const_type; + typedef OpenMesh::TriMesh_ArrayKernelT Mesh; + typedef CGAL::OM_edge_weight_pmap type; + typedef CGAL::OM_edge_weight_pmap const_type; }; @@ -211,7 +48,6 @@ struct property_map, boost::edge_weight_t > // // vertex_index // - template struct property_map, boost::vertex_index_t > { From 1bbd90f25b2f8075ea30e841a83347c9eb8cb3b3 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 22 Sep 2015 14:48:14 +0200 Subject: [PATCH 164/217] remove redundancy to avoid conflicts when both files are included --- .../graph/graph_traits_TriMesh_ArrayKernelT.h | 71 +------ .../graph/properties_PolyMesh_ArrayKernelT.h | 83 ++++---- .../graph/properties_TriMesh_ArrayKernelT.h | 181 +----------------- 3 files changed, 58 insertions(+), 277 deletions(-) diff --git a/BGL/include/CGAL/boost/graph/graph_traits_TriMesh_ArrayKernelT.h b/BGL/include/CGAL/boost/graph/graph_traits_TriMesh_ArrayKernelT.h index 786e32754a4..53e6a5754f4 100644 --- a/BGL/include/CGAL/boost/graph/graph_traits_TriMesh_ArrayKernelT.h +++ b/BGL/include/CGAL/boost/graph/graph_traits_TriMesh_ArrayKernelT.h @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -40,76 +41,6 @@ # pragma warning(push) # pragma warning(disable:4267) #endif -namespace CGAL { namespace internal { - - -template -class OMesh_edge { -public: - OMesh_edge() : halfedge_() {} - explicit OMesh_edge(const Halfedge_handle& h) : halfedge_(h) {} - Halfedge_handle halfedge() const { return halfedge_; } - bool is_valid() const { return halfedge_.is_valid(); } - - bool - operator==(const OMesh_edge& other) { - if(halfedge_ == other.halfedge_) { - return true; - } else if(halfedge_ != Halfedge_handle()) { - return opposite() == other.halfedge_; - } else { - return false; - } - } - - bool operator<(const OMesh_edge& other) const - { - return this->idx() < other.idx(); - } - - bool - operator!=(const OMesh_edge& other) { return !(*this == other); } - - Halfedge_handle - opposite() const { return Halfedge_handle((halfedge_.idx() & 1) ? halfedge_.idx()-1 : halfedge_.idx()+1); } - - OMesh_edge - opposite_edge() const { return OMesh_edge(Halfedge_handle((halfedge_.idx() & 1) ? halfedge_.idx()-1 : halfedge_.idx()+1)); } - - unsigned int idx() const { return halfedge_.idx() / 2; } -private: - Halfedge_handle halfedge_; -}; - -template -struct Convert_omesh_edge -{ - typedef OMesh_edge result_type; - result_type operator()(const OMeshEdge& h) const { - return result_type(Halfedge_handle(h.idx() * 2)); - } -}; - -template -struct Construct_omesh_edge -{ - typedef OMesh_edge result_type; - template - result_type operator()(const T& h) const { return result_type(h); } -}; - -template -struct Construct_omesh_edge_opposite -{ - typedef OMesh_edge result_type; - template - result_type operator()(const T& h) const { return result_type(h).opposite_edge(); } -}; - - -} // internal -} // CGAL - namespace boost { diff --git a/BGL/include/CGAL/boost/graph/properties_PolyMesh_ArrayKernelT.h b/BGL/include/CGAL/boost/graph/properties_PolyMesh_ArrayKernelT.h index d5c092e638a..9b72934c666 100644 --- a/BGL/include/CGAL/boost/graph/properties_PolyMesh_ArrayKernelT.h +++ b/BGL/include/CGAL/boost/graph/properties_PolyMesh_ArrayKernelT.h @@ -85,17 +85,17 @@ public: }; -template +template class OM_edge_weight_pmap - : public boost::put_get_helper::Scalar , OM_edge_weight_pmap > + : public boost::put_get_helper > { public: typedef boost::readable_property_map_tag category; - typedef typename OpenMesh::PolyMesh_ArrayKernelT::Scalar value_type; + typedef typename OpenMesh::Scalar value_type; typedef value_type reference; - typedef typename boost::graph_traits >::edge_descriptor key_type; + typedef typename boost::graph_traits::edge_descriptor key_type; - OM_edge_weight_pmap(const OpenMesh::PolyMesh_ArrayKernelT& sm) + OM_edge_weight_pmap(const OpenMesh& sm) : sm_(sm) {} @@ -105,7 +105,7 @@ public: } private: - const OpenMesh::PolyMesh_ArrayKernelT& sm_; + const OpenMesh& sm_; }; template @@ -124,25 +124,25 @@ public: }; - template -class OM_point_pmap //: public boost::put_get_helper > +template +class OM_point_pmap //: public boost::put_get_helper > { public: typedef boost::read_write_property_map_tag category; #if defined(CGAL_USE_OM_POINTS) - typedef typename OpenMesh::PolyMesh_ArrayKernelT::Point value_type; - typedef const typename OpenMesh::PolyMesh_ArrayKernelT::Point& reference; + typedef typename OpenMesh::Point value_type; + typedef const typename OpenMesh::Point& reference; #else typedef P value_type; typedef P reference; #endif - typedef typename boost::graph_traits< OpenMesh::PolyMesh_ArrayKernelT >::vertex_descriptor key_type; + typedef typename boost::graph_traits::vertex_descriptor key_type; OM_point_pmap() : sm_(NULL) {} - OM_point_pmap(const OpenMesh::PolyMesh_ArrayKernelT& sm) + OM_point_pmap(const OpenMesh& sm) : sm_(&sm) {} @@ -156,36 +156,36 @@ public: return sm_->point(v); #else CGAL_assertion(sm_!=NULL); - typename OpenMesh::PolyMesh_ArrayKernelT::Point const& omp = sm_->point(v); + typename OpenMesh::Point const& omp = sm_->point(v); return value_type(omp[0], omp[1], omp[2]); #endif } - inline friend reference get(const OM_point_pmap& pm, key_type v) + inline friend reference get(const OM_point_pmap& pm, key_type v) { CGAL_precondition(pm.sm_!=NULL); #if defined(CGAL_USE_OM_POINTS) return pm.sm_->point(v); #else CGAL_assertion(pm.sm_!=NULL); - typename OpenMesh::PolyMesh_ArrayKernelT::Point const& omp = pm.sm_->point(v); + typename OpenMesh::Point const& omp = pm.sm_->point(v); return value_type(omp[0], omp[1], omp[2]); #endif } - inline friend void put(const OM_point_pmap& pm, key_type v, const value_type& p) + inline friend void put(const OM_point_pmap& pm, key_type v, const value_type& p) { CGAL_precondition(pm.sm_!=NULL); #if defined(CGAL_USE_OM_POINTS) - const_cast&>(*pm.sm_).set_point(v,p); + const_cast(*pm.sm_).set_point(v,p); #else - const_cast&>(*pm.sm_).set_point - (v, typename OpenMesh::PolyMesh_ArrayKernelT::Point((float)p[0], (float)p[1], (float)p[2])); + const_cast(*pm.sm_).set_point + (v, typename OpenMesh::Point((float)p[0], (float)p[1], (float)p[2])); #endif } private: - const OpenMesh::PolyMesh_ArrayKernelT* sm_; + const OpenMesh* sm_; }; @@ -202,8 +202,9 @@ namespace boost { template struct property_map, boost::edge_weight_t > { - typedef CGAL::OM_edge_weight_pmap type; - typedef CGAL::OM_edge_weight_pmap const_type; + typedef OpenMesh::PolyMesh_ArrayKernelT Mesh; + typedef CGAL::OM_edge_weight_pmap type; + typedef CGAL::OM_edge_weight_pmap const_type; }; @@ -215,8 +216,9 @@ struct property_map, boost::edge_weight_t > template struct property_map, boost::vertex_index_t > { - typedef CGAL::OM_index_pmap >::vertex_descriptor> type; - typedef CGAL::OM_index_pmap >::vertex_descriptor> const_type; + typedef OpenMesh::PolyMesh_ArrayKernelT Mesh; + typedef CGAL::OM_index_pmap::vertex_descriptor> type; + typedef CGAL::OM_index_pmap::vertex_descriptor> const_type; }; @@ -227,8 +229,9 @@ struct property_map, boost::vertex_index_t > template struct property_map, boost::face_index_t > { - typedef CGAL::OM_index_pmap >::face_descriptor> type; - typedef CGAL::OM_index_pmap >::face_descriptor> const_type; + typedef OpenMesh::PolyMesh_ArrayKernelT Mesh; + typedef CGAL::OM_index_pmap::face_descriptor> type; + typedef CGAL::OM_index_pmap::face_descriptor> const_type; }; // @@ -238,8 +241,9 @@ struct property_map, boost::face_index_t > template struct property_map, boost::edge_index_t > { - typedef CGAL::OM_index_pmap >::edge_descriptor> type; - typedef CGAL::OM_index_pmap >::edge_descriptor> const_type; + typedef OpenMesh::PolyMesh_ArrayKernelT Mesh; + typedef CGAL::OM_index_pmap type; + typedef CGAL::OM_index_pmap const_type; }; // @@ -249,8 +253,9 @@ struct property_map, boost::edge_index_t > template struct property_map, boost::halfedge_index_t > { - typedef CGAL::OM_index_pmap >::halfedge_descriptor> type; - typedef CGAL::OM_index_pmap >::halfedge_descriptor> const_type; + typedef OpenMesh::PolyMesh_ArrayKernelT Mesh; + typedef CGAL::OM_index_pmap type; + typedef CGAL::OM_index_pmap const_type; }; @@ -258,7 +263,8 @@ template struct property_map, boost::vertex_point_t > { typedef CGAL::Exact_predicates_inexact_constructions_kernel::Point_3 P; - typedef CGAL::OM_point_pmap type; + typedef OpenMesh::PolyMesh_ArrayKernelT Mesh; + typedef CGAL::OM_point_pmap type; typedef type const_type; }; @@ -271,7 +277,8 @@ template typename boost::property_map, boost::edge_weight_t>::const_type get(boost::edge_weight_t, const OpenMesh::PolyMesh_ArrayKernelT& sm) { - return CGAL::OM_edge_weight_pmap(sm); + typedef OpenMesh::PolyMesh_ArrayKernelT Mesh; + return CGAL::OM_edge_weight_pmap(sm); } template @@ -279,7 +286,8 @@ typename OpenMesh::PolyMesh_ArrayKernelT::Scalar get(boost::edge_weight_t, const OpenMesh::PolyMesh_ArrayKernelT& sm, const typename boost::graph_traits >::edge_descriptor& e) { - return CGAL::OM_edge_weight_pmap(sm)[e]; + typedef OpenMesh::PolyMesh_ArrayKernelT Mesh; + return CGAL::OM_edge_weight_pmap(sm)[e]; } @@ -287,13 +295,15 @@ template CGAL::OM_index_pmap >::vertex_descriptor> get(const boost::vertex_index_t&, const OpenMesh::PolyMesh_ArrayKernelT&) { - return CGAL::OM_index_pmap >::vertex_descriptor>(); + typedef OpenMesh::PolyMesh_ArrayKernelT Mesh; + return CGAL::OM_index_pmap::vertex_descriptor>(); } template typename boost::property_map, boost::face_index_t>::const_type get(const boost::face_index_t&, const OpenMesh::PolyMesh_ArrayKernelT&) { + typedef OpenMesh::PolyMesh_ArrayKernelT Mesh; return CGAL::OM_index_pmap >::face_descriptor>(); } @@ -312,11 +322,12 @@ get(const boost::halfedge_index_t&, const OpenMesh::PolyMesh_ArrayKernelT&) } template -CGAL::OM_point_pmap +CGAL::OM_point_pmap, + typename CGAL::Exact_predicates_inexact_constructions_kernel::Point_3> get(boost::vertex_point_t, const OpenMesh::PolyMesh_ArrayKernelT& g) { typedef typename CGAL::Exact_predicates_inexact_constructions_kernel::Point_3 P; - return CGAL::OM_point_pmap(g); + return CGAL::OM_point_pmap, P>(g); } // get for intrinsic properties diff --git a/BGL/include/CGAL/boost/graph/properties_TriMesh_ArrayKernelT.h b/BGL/include/CGAL/boost/graph/properties_TriMesh_ArrayKernelT.h index e26b707c544..f19093c3670 100644 --- a/BGL/include/CGAL/boost/graph/properties_TriMesh_ArrayKernelT.h +++ b/BGL/include/CGAL/boost/graph/properties_TriMesh_ArrayKernelT.h @@ -24,172 +24,10 @@ #include #include #include +#include #include #include -namespace CGAL { - -template -class OM_pmap { -public: - typedef typename boost::mpl::if_::vertex_descriptor>, - OpenMesh::VPropHandleT, - typename boost::mpl::if_::face_descriptor>, - OpenMesh::FPropHandleT, - typename boost::mpl::if_::halfedge_descriptor>, - OpenMesh::HPropHandleT, - OpenMesh::EPropHandleT >::type>::type>::type H; - - typedef boost::read_write_property_map_tag category; - - typedef Descriptor key_type; - typedef Value value_type; - - typedef value_type& reference; - - OM_pmap(Mesh& m) - : mesh(m) - {} - - OM_pmap(Mesh& m, H h) - : mesh(m), h(h) - {} - - inline friend reference get(const OM_pmap& pm, key_type k) - { - return pm.mesh.property(pm.h,k); - } - - inline friend void put(const OM_pmap& pm, key_type k, const value_type& v) - { - pm.mesh.property(pm.h,k) = v; - } - - reference operator[](key_type k) - { - return mesh.property(h,k); - } - - H handle() const - { - return h; - } - - H& handle() - { - return h; - } - - Mesh& mesh; - H h; -}; - - -template -class OM_edge_weight_pmap - : public boost::put_get_helper::Scalar , OM_edge_weight_pmap > -{ -public: - typedef boost::readable_property_map_tag category; - typedef typename OpenMesh::TriMesh_ArrayKernelT::Scalar value_type; - typedef value_type reference; - typedef typename boost::graph_traits >::edge_descriptor key_type; - - OM_edge_weight_pmap(const OpenMesh::TriMesh_ArrayKernelT& sm) - : sm_(sm) - {} - - value_type operator[](const key_type& e) const - { - return sm_.calc_edge_length(e.halfedge()); - } - -private: - const OpenMesh::TriMesh_ArrayKernelT& sm_; -}; - -template -class OM_index_pmap : public boost::put_get_helper > -{ -public: - typedef boost::readable_property_map_tag category; - typedef unsigned int value_type; - typedef unsigned int reference; - typedef VEF key_type; - - value_type operator[](const key_type& vd) const - { - return vd.idx(); - } -}; - - - template -class OM_point_pmap //: public boost::put_get_helper > -{ -public: - typedef boost::read_write_property_map_tag category; -#if defined(CGAL_USE_OM_POINTS) - typedef typename OpenMesh::TriMesh_ArrayKernelT::Point value_type; - typedef const typename OpenMesh::TriMesh_ArrayKernelT::Point& reference; -#else - typedef P value_type; - typedef P reference; -#endif - typedef typename boost::graph_traits< OpenMesh::TriMesh_ArrayKernelT >::vertex_descriptor key_type; - - OM_point_pmap() - : sm_(NULL) - {} - - OM_point_pmap(const OpenMesh::TriMesh_ArrayKernelT& sm) - : sm_(&sm) - {} - - OM_point_pmap(const OM_point_pmap& pm) - : sm_(pm.sm_) - {} - - value_type operator[](key_type v) - { -#if defined(CGAL_USE_OM_POINTS) - return sm_->point(v); -#else - CGAL_assertion(sm_!=NULL); - typename OpenMesh::TriMesh_ArrayKernelT::Point const& omp = sm_->point(v); - return value_type(omp[0], omp[1], omp[2]); -#endif - } - - inline friend reference get(const OM_point_pmap& pm, key_type v) - { - CGAL_precondition(pm.sm_!=NULL); -#if defined(CGAL_USE_OM_POINTS) - return pm.sm_->point(v); -#else - CGAL_assertion(pm.sm_!=NULL); - typename OpenMesh::TriMesh_ArrayKernelT::Point const& omp = pm.sm_->point(v); - return value_type(omp[0], omp[1], omp[2]); -#endif - } - - inline friend void put(const OM_point_pmap& pm, key_type v, const value_type& p) - { - CGAL_precondition(pm.sm_!=NULL); -#if defined(CGAL_USE_OM_POINTS) - const_cast&>(*pm.sm_).set_point(v,p); -#else - const_cast&>(*pm.sm_).set_point - (v, typename OpenMesh::TriMesh_ArrayKernelT::Point((float)p[0], (float)p[1], (float)p[2])); -#endif - } - - private: - const OpenMesh::TriMesh_ArrayKernelT* sm_; -}; - - -} // CGAL // overloads and specializations in the boost namespace namespace boost { @@ -197,13 +35,12 @@ namespace boost { // // edge_weight // - - template struct property_map, boost::edge_weight_t > { - typedef CGAL::OM_edge_weight_pmap type; - typedef CGAL::OM_edge_weight_pmap const_type; + typedef OpenMesh::TriMesh_ArrayKernelT Mesh; + typedef CGAL::OM_edge_weight_pmap type; + typedef CGAL::OM_edge_weight_pmap const_type; }; @@ -211,7 +48,6 @@ struct property_map, boost::edge_weight_t > // // vertex_index // - template struct property_map, boost::vertex_index_t > { @@ -258,7 +94,8 @@ template struct property_map, boost::vertex_point_t > { typedef CGAL::Exact_predicates_inexact_constructions_kernel::Point_3 P; - typedef CGAL::OM_point_pmap type; + typedef OpenMesh::TriMesh_ArrayKernelT Mesh; + typedef CGAL::OM_point_pmap type; typedef type const_type; }; @@ -312,11 +149,13 @@ get(const boost::halfedge_index_t&, const OpenMesh::TriMesh_ArrayKernelT&) } template -CGAL::OM_point_pmap +CGAL::OM_point_pmap, + typename CGAL::Exact_predicates_inexact_constructions_kernel::Point_3> get(boost::vertex_point_t, const OpenMesh::TriMesh_ArrayKernelT& g) { typedef typename CGAL::Exact_predicates_inexact_constructions_kernel::Point_3 P; - return CGAL::OM_point_pmap(g); + typedef OpenMesh::TriMesh_ArrayKernelT Mesh; + return CGAL::OM_point_pmap(g); } // get for intrinsic properties From fe09c5483eeef77a75185c12bc2b3334946ee05a Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 22 Sep 2015 15:07:49 +0200 Subject: [PATCH 165/217] do not use the brackets [] API of std::map, but an API compatible with boost::bimap --- BGL/include/CGAL/boost/graph/convert_surface_mesh.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/BGL/include/CGAL/boost/graph/convert_surface_mesh.h b/BGL/include/CGAL/boost/graph/convert_surface_mesh.h index b074cca9821..5751b41cebd 100644 --- a/BGL/include/CGAL/boost/graph/convert_surface_mesh.h +++ b/BGL/include/CGAL/boost/graph/convert_surface_mesh.h @@ -30,7 +30,7 @@ namespace CGAL { BOOST_FOREACH(sm_vertex_descriptor svd, vertices(sm)){ tm_vertex_descriptor tvd = add_vertex(tm); - v2v[svd] = tvd; + v2v.insert(std::make_pair(svd, tvd)); put(tm_pmap, tvd, get(sm_pmap, svd)); } @@ -38,7 +38,7 @@ namespace CGAL { BOOST_FOREACH(sm_face_descriptor sfd, faces(sm)){ std::vector tv; BOOST_FOREACH(sm_vertex_descriptor svd, vertices_around_face(halfedge(sfd,sm),sm)){ - tv.push_back(v2v[svd]); + tv.push_back(v2v.at(svd)); } f2f[sfd] = Euler::add_face(tv,tm); } @@ -46,12 +46,12 @@ namespace CGAL { BOOST_FOREACH(sm_face_descriptor sfd, faces(sm)){ sm_halfedge_descriptor shd = halfedge(sfd,sm), done(shd); tm_halfedge_descriptor thd = halfedge(f2f[sfd],tm); - tm_vertex_descriptor tvd = v2v[target(shd,sm)]; + tm_vertex_descriptor tvd = v2v.at(target(shd,sm)); while(target(thd,tm) != tvd){ thd = next(thd,tm); } do { - h2h[shd] = thd; + h2h.insert(std::make_pair(shd, thd)); shd = next(shd,sm); thd = next(thd,tm); }while(shd != done); From 132e083c7df6d5af94a5e2ccda712531ec612ab8 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Mon, 5 Oct 2015 16:19:02 +0200 Subject: [PATCH 166/217] fix compilation --- .../Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp | 3 ++- Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp b/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp index 1587a8751aa..64f96d92e4f 100644 --- a/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Polyhedron_demo_isotropic_remeshing_plugin.cpp @@ -221,7 +221,8 @@ public Q_SLOTS: , CGAL::Polygon_mesh_processing::parameters::number_of_iterations(nb_iter) .protect_constraints(protect)); } - poly_item->changed(); + poly_item->invalidate_buffers(); + Q_EMIT poly_item->itemChanged(); } else{ std::cout << "Can't remesh that type of thing" << std::endl; diff --git a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h index b5394d9a5cd..8b18c987bb1 100644 --- a/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h +++ b/Polyhedron/demo/Polyhedron/Scene_polyhedron_selection_item.h @@ -780,6 +780,7 @@ protected: any_change |= (tr.container().erase(h)!=0); } if(any_change) { invalidate_buffers(); Q_EMIT itemChanged(); } + return any_change; } Facet_handle face(Facet_handle fh) From 57ef5d03f7ef7e50c337ef8af2d440e69bc8e15e Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 20 Oct 2015 15:04:00 +0200 Subject: [PATCH 167/217] remove todo. Works the same for multiple cc --- .../include/CGAL/Polygon_mesh_processing/get_border.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/get_border.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/get_border.h index f05d5d185ad..57d716923b1 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/get_border.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/get_border.h @@ -49,7 +49,6 @@ namespace Polygon_mesh_processing { * @param out the output iterator that collects halfedges that form the border * of `faces`, seen from inside the surface patch * - * @todo code : what shall we do for more than one connected components * @todo add get_border to the user manual */ template::edge_descriptor edge_descriptor; - typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::face_descriptor face_descriptor; //collect halfedges that appear only once From 893b80c49036e7d8cb4705022d36b7849cc89af2 Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 20 Oct 2015 15:40:41 +0200 Subject: [PATCH 168/217] rename function to isotropic_remeshing() --- .../doc/Polygon_mesh_processing/PackageDescription.txt | 4 ++-- .../Polygon_mesh_processing/Polygon_mesh_processing.txt | 2 +- .../isotropic_remeshing_example.cpp | 2 +- .../include/CGAL/Polygon_mesh_processing/remesh.h | 8 ++++---- .../test/Polygon_mesh_processing/remeshing_test.cpp | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt index a47317251e6..6ec1601e263 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt @@ -50,7 +50,7 @@ and provides a list of the parameters that are used in this package. - `CGAL::Polygon_mesh_processing::fair()` - `CGAL::Polygon_mesh_processing::refine()` - `CGAL::Polygon_mesh_processing::triangulate_faces()` -- \link remeshing_grp `CGAL::Polygon_mesh_processing::incremental_triangle_based_remeshing()` \endlink +- \link remeshing_grp `CGAL::Polygon_mesh_processing::isotropic_remeshing()` \endlink - \link remeshing_grp `CGAL::Polygon_mesh_processing::split_long_edges()` \endlink ## Hole Filling Functions ## @@ -92,7 +92,7 @@ and provides a list of the parameters that are used in this package. ## Miscellaneous ## - `CGAL::Polygon_mesh_slicer` -- `CGAL::Polygon_mesh_processing::get_border()` +#- `CGAL::Polygon_mesh_processing::get_border()` \todo make template parameter names uniform in other packages using BGL. Here we chose PolygonMesh as template parameter. It can be made short to PM. And TriangleMesh (or TM) specifies when the parameter should be a triangle mesh. 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 854e8bbf2f6..c716093e1b7 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 @@ -94,7 +94,7 @@ is the triangulation that, given the edges of the face to be triangulated, maximizes the minimum angle of all the angles of the triangles in the triangulation. \subsubsection Remeshing -- `CGAL::Polygon_mesh_processing::incremental_triangle_based_remeshing()` +- `CGAL::Polygon_mesh_processing::isotropic_remeshing()` \todo user manual remeshing * implements section 6.5.3 "Incremental remeshing" from the PMP book \cgalCite{botsch2010PMP}. diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/isotropic_remeshing_example.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/isotropic_remeshing_example.cpp index a5dfe95f7ab..cba53b32a64 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/isotropic_remeshing_example.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/isotropic_remeshing_example.cpp @@ -42,7 +42,7 @@ int main(int argc, char* argv[]) CGAL::Timer t; t.start(); - PMP::incremental_triangle_based_remeshing(mesh, + PMP::isotropic_remeshing(mesh, faces(mesh), target_edge_length, PMP::parameters::number_of_iterations(nb_iter) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h index c8874b9122e..ef8c99dc0c4 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h @@ -83,10 +83,10 @@ namespace Polygon_mesh_processing { template -void incremental_triangle_based_remeshing(TriangleMesh& tmesh - , const FaceRange& faces - , const double& target_edge_length - , const NamedParameters& np) +void isotropic_remeshing(TriangleMesh& tmesh + , const FaceRange& faces + , const double& target_edge_length + , const NamedParameters& np) { typedef TriangleMesh TM; using boost::choose_pmap; diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp index 80e0b15e9d5..22203eeff22 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/remeshing_test.cpp @@ -119,7 +119,7 @@ int main(int argc, char* argv[]) CGAL::Timer t; t.start(); - PMP::incremental_triangle_based_remeshing(m, + PMP::isotropic_remeshing(m, patch, target_edge_length, PMP::parameters::number_of_iterations(nb_iter) From 945d358db58af49c4f41dd18e7170b7a4a02ff6c Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Tue, 20 Oct 2015 17:05:21 +0200 Subject: [PATCH 169/217] change function name in "see also" --- .../include/CGAL/Polygon_mesh_processing/remesh.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h index ef8c99dc0c4..044d6384730 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/remesh.h @@ -190,7 +190,7 @@ void incremental_triangle_based_remeshing(TriangleMesh& tmesh * \cgalParamEnd * \cgalNamedParamsEnd * -* @sa `incremental_triangle_based_remeshing()` +* @sa `isotropic_remeshing()` * */ template Date: Tue, 20 Oct 2015 17:10:30 +0200 Subject: [PATCH 170/217] update changes.html --- Installation/changes.html | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Installation/changes.html b/Installation/changes.html index 91a27548f8b..c77f90f6784 100644 --- a/Installation/changes.html +++ b/Installation/changes.html @@ -137,6 +137,12 @@ and src/ directories). +

Polygon Mesh Processing

+
    +
  • Add a new triangle-based isotropic remeshing algorithm for + triangulated surface meshes, + CGAL::Polygon_mesh_processing::isotropic_remeshing()
  • +

Surface Mesh Parameterization