From 9c181d7860941da3bb27ec5a27a6ca0e90dca8cc Mon Sep 17 00:00:00 2001 From: Jane Tournois Date: Thu, 29 Sep 2016 10:43:11 +0200 Subject: [PATCH 1/3] Angles < 135 deg (90 in theory) should be counted as terminal vertices, otherwise protection may fail by refining protecting balls endlessly, getting closer and closer to the input sharp angle --- .../CGAL/Mesh_3/polylines_to_protect.h | 40 ++++++++++++++++++- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/Mesh_3/include/CGAL/Mesh_3/polylines_to_protect.h b/Mesh_3/include/CGAL/Mesh_3/polylines_to_protect.h index ca83aafde9e..6acd0a92b36 100644 --- a/Mesh_3/include/CGAL/Mesh_3/polylines_to_protect.h +++ b/Mesh_3/include/CGAL/Mesh_3/polylines_to_protect.h @@ -68,6 +68,40 @@ struct Polyline_visitor polylines.resize(polylines.size() - 1); } }; + +struct Angle_tester +{ + template + bool operator()(vertex_descriptor& v, const Graph& g) const + { + typedef typename boost::graph_traits::out_edge_iterator out_edge_iterator; + if (out_degree(v, g) != 2) + return true; + else + { + out_edge_iterator out_edge_it, out_edges_end; + boost::tie(out_edge_it, out_edges_end) = out_edges(v, g); + + vertex_descriptor v1 = target(*out_edge_it++, g); + vertex_descriptor v2 = target(*out_edge_it++, g); + CGAL_assertion(out_edge_it == out_edges_end); + + const typename Kernel::Point_3& p = g[v]; + const typename Kernel::Point_3& p1 = g[v1]; + const typename Kernel::Point_3& p2 = g[v2]; + + const typename Kernel::Vector_3 e1 = p1 - p; + const typename Kernel::Vector_3 e2 = p2 - p; + const typename Kernel::FT sc_prod = e1 * e2; + if (sc_prod >= 0 || // angle < 135 degrees (3*pi/4) + (sc_prod < 0 && + CGAL::square(sc_prod) < (e1 * e1) * (e2 * e2) / 2)) + return true; + } + return false; + } +}; + }//namespace Mesh_3 // this function is overloaded for when `PolylineInputIterator` is `int`. @@ -490,7 +524,8 @@ case_4: K()); Mesh_3::Polyline_visitor visitor(polylines, graph); - split_graph_into_polylines(graph, visitor); + const Graph& const_graph = graph; + split_graph_into_polylines(const_graph, visitor, Mesh_3::Angle_tester()); } template >& polylines, } Mesh_3::Polyline_visitor visitor(polylines, graph); - split_graph_into_polylines(graph, visitor); + const Graph& const_graph = graph; + split_graph_into_polylines(const_graph, visitor, Mesh_3::Angle_tester()); } template From 5bd65fba58b3ba83073f1abd10a8373e8b0ed458 Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Thu, 29 Sep 2016 17:28:03 +0200 Subject: [PATCH 2/3] Make split_graph_into_polylines deterministic - There is a new argument, `Less`, that allows to sort the `std::set` of vertex descriptors with a deterministic sort functor. - The header `` defines and use such a functor. --- .../boost/graph/split_graph_into_polylines.h | 126 ++++++++++++------ .../CGAL/Mesh_3/polylines_to_protect.h | 22 ++- 2 files changed, 103 insertions(+), 45 deletions(-) diff --git a/BGL/include/CGAL/boost/graph/split_graph_into_polylines.h b/BGL/include/CGAL/boost/graph/split_graph_into_polylines.h index dc833362822..f69dd4c0f41 100644 --- a/BGL/include/CGAL/boost/graph/split_graph_into_polylines.h +++ b/BGL/include/CGAL/boost/graph/split_graph_into_polylines.h @@ -51,13 +51,31 @@ struct Dummy_visitor_for_split_graph_into_polylines namespace internal { -/// Splits a graph at vertices with degree higher than two and at vertices where `is_terminal returns `true` +template +class Less_on_G_copy_vertex_descriptors { + const G_copy& g_copy; + const Less_on_orig_vertex_descriptors& less; +public: + Less_on_G_copy_vertex_descriptors ( const G_copy& g_copy, + const Less_on_orig_vertex_descriptors& less) + : g_copy(g_copy), less(less) {} + + typedef typename boost::graph_traits::vertex_descriptor + g_copy_vertex_descriptor; + + bool operator()(g_copy_vertex_descriptor v1, + g_copy_vertex_descriptor v2) const { + return less(g_copy[v1], g_copy[v2]); + } +}; // end class Less_on_G_copy_vertex_descriptors + +/// Splits a graph at vertices with degree higher than two and at vertices where `is_terminal` returns `true` /// The vertices are duplicated, and new incident edges created. -/// OrigGraph must be undirected +/// `OrigGraph` must be undirected template -void split_graph_into_polylines(Graph& graph, +void duplicate_terminal_vertices(Graph& graph, const OrigGraph& orig, IsTerminal is_terminal) { @@ -102,7 +120,7 @@ void split_graph_into_polylines(Graph& graph, CGAL_assertion(v != w); } ) // end of CGAL_assertion_code - } +} // end of duplicate_terminal_vertices } // namespace internal @@ -125,6 +143,8 @@ The polylines are reported using a visitor. An overload without `is_terminal` is provided if no vertices but those of degree different from 2 are polyline endpoints. + +@todo Document the version with four parameters */ template ::vertex_descriptor Graph_vertex_descriptor; + std::less less; + split_graph_into_polylines(graph, polyline_visitor, is_terminal, less); +} + +template +void +split_graph_into_polylines(const Graph& graph, + Visitor& polyline_visitor, + IsTerminal is_terminal, + LessForVertexDescriptors less) { typedef typename boost::graph_traits::vertex_descriptor Graph_vertex_descriptor; typedef typename boost::graph_traits::edge_descriptor Graph_edge_descriptor; @@ -140,22 +175,22 @@ split_graph_into_polylines(const Graph& graph, typedef boost::adjacency_list G; + Graph_vertex_descriptor > G_copy; - typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; - typedef typename boost::graph_traits::edge_descriptor edge_descriptor; - typedef typename boost::graph_traits::out_edge_iterator out_edge_iterator; + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::edge_descriptor edge_descriptor; + typedef typename boost::graph_traits::out_edge_iterator out_edge_iterator; // we make a copy of the input graph - G g; + G_copy g_copy; { typedef std::map::vertex_descriptor, - typename boost::graph_traits::vertex_descriptor> V2vmap; + typename boost::graph_traits::vertex_descriptor> V2vmap; V2vmap v2vmap; BOOST_FOREACH(Graph_vertex_descriptor v, vertices(graph)){ - vertex_descriptor vc = add_vertex(g); - g[vc] = v; + vertex_descriptor vc = add_vertex(g_copy); + g_copy[vc] = v; v2vmap[v] = vc; } @@ -170,35 +205,40 @@ split_graph_into_polylines(const Graph& graph, typename V2vmap::iterator it; if((it = v2vmap.find(vs)) == v2vmap.end()){ - vsc = add_vertex(g); - g[vsc] = vs; + vsc = add_vertex(g_copy); + g_copy[vsc] = vs; v2vmap[vs] = vsc; }else{ vsc = it->second; } if((it = v2vmap.find(vt)) == v2vmap.end()){ - vtc = add_vertex(g); - g[vtc] = vt; + vtc = add_vertex(g_copy); + g_copy[vtc] = vt; v2vmap[vt] = vtc; }else{ vtc = it->second; } - add_edge(vsc,vtc,g); + add_edge(vsc,vtc,g_copy); } } } // duplicate terminal vertices and vertices of degree more than 2 - internal::split_graph_into_polylines(g, graph, is_terminal); - // put polylines endpoint in a set - std::set terminal; + internal::duplicate_terminal_vertices(g_copy, graph, is_terminal); - BOOST_FOREACH(vertex_descriptor v, vertices(g)){ - typename boost::graph_traits::degree_size_type n = degree(v, g); + // put polylines endpoint in a set + typedef internal::Less_on_G_copy_vertex_descriptors< + G_copy, + LessForVertexDescriptors> G_copy_less; + G_copy_less g_copy_less(g_copy, less); + std::set terminal(g_copy_less); + + BOOST_FOREACH(vertex_descriptor v, vertices(g_copy)){ + typename boost::graph_traits::degree_size_type n = degree(v, g_copy); if ( n == 1 ) terminal.insert(v); if ( n ==0 ){ //isolated vertex polyline_visitor.start_new_polyline(); - polyline_visitor.add_node(g[v]); + polyline_visitor.add_node(g_copy[v]); polyline_visitor.end_polyline(); } } @@ -210,15 +250,15 @@ split_graph_into_polylines(const Graph& graph, vertex_descriptor u = *it; terminal.erase(it); polyline_visitor.start_new_polyline(); - polyline_visitor.add_node(g[u]); - while (degree(u,g) != 0) + polyline_visitor.add_node(g_copy[u]); + while (degree(u,g_copy) != 0) { - CGAL_assertion(degree(u,g) == 1); - out_edge_iterator b = out_edges(u, g).first; - vertex_descriptor v = target(*b, g); + CGAL_assertion(degree(u,g_copy) == 1); + out_edge_iterator b = out_edges(u, g_copy).first; + vertex_descriptor v = target(*b, g_copy); CGAL_assertion(u!=v); - polyline_visitor.add_node(g[v]); - remove_edge(b, g); + polyline_visitor.add_node(g_copy[v]); + remove_edge(b, g_copy); u = v; } terminal.erase(u); @@ -226,26 +266,26 @@ split_graph_into_polylines(const Graph& graph, } // do the same but for cycles - while (num_edges(g) != 0) + while (num_edges(g_copy) != 0) { - edge_descriptor first_edge = *edges(g).first; - vertex_descriptor u = source(first_edge, g); + edge_descriptor first_edge = *edges(g_copy).first; + vertex_descriptor u = source(first_edge, g_copy); polyline_visitor.start_new_polyline(); - polyline_visitor.add_node(g[u]); + polyline_visitor.add_node(g_copy[u]); - u = target(first_edge, g); - remove_edge(first_edge, g); - polyline_visitor.add_node(g[u]); + u = target(first_edge, g_copy); + remove_edge(first_edge, g_copy); + polyline_visitor.add_node(g_copy[u]); - while (degree(u,g) != 0) + while (degree(u,g_copy) != 0) { - CGAL_assertion(degree(u,g) == 1); - out_edge_iterator b = out_edges(u, g).first; - vertex_descriptor v = target(*b, g); + CGAL_assertion(degree(u,g_copy) == 1); + out_edge_iterator b = out_edges(u, g_copy).first; + vertex_descriptor v = target(*b, g_copy); CGAL_assertion(u!=v); - polyline_visitor.add_node(g[v]); - remove_edge(b, g); + polyline_visitor.add_node(g_copy[v]); + remove_edge(b, g_copy); u = v; } polyline_visitor.end_polyline(); diff --git a/Mesh_3/include/CGAL/Mesh_3/polylines_to_protect.h b/Mesh_3/include/CGAL/Mesh_3/polylines_to_protect.h index ca83aafde9e..c29a0c1f225 100644 --- a/Mesh_3/include/CGAL/Mesh_3/polylines_to_protect.h +++ b/Mesh_3/include/CGAL/Mesh_3/polylines_to_protect.h @@ -119,6 +119,18 @@ template +struct Less_for_Graph_vertex_descriptors +{ + const Graph& graph; + Less_for_Graph_vertex_descriptors(const Graph& graph) : graph(graph) {} + + template + bool operator()(vertex_descriptor v1, vertex_descriptor v2) const { + return graph[v1] < graph[v2]; + } +}; // end of Less_for_Graph_vertex_descriptors + template visitor(polylines, graph); - split_graph_into_polylines(graph, visitor); + Less_for_Graph_vertex_descriptors less(graph); + split_graph_into_polylines(graph, visitor, + CGAL::internal::IsTerminalDefault(), + less); } template >& polylines, } Mesh_3::Polyline_visitor visitor(polylines, graph); - split_graph_into_polylines(graph, visitor); + Less_for_Graph_vertex_descriptors less(graph); + split_graph_into_polylines(graph, visitor, + CGAL::internal::IsTerminalDefault(), + less); } template From de3d1f4459fbfdb20dd36186baa800f20107f643 Mon Sep 17 00:00:00 2001 From: Laurent Rineau Date: Fri, 30 Sep 2016 10:05:59 +0200 Subject: [PATCH 3/3] Fix compilation of mesh_3_plugin ... after the last merge commit. --- Mesh_3/include/CGAL/Mesh_3/polylines_to_protect.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Mesh_3/include/CGAL/Mesh_3/polylines_to_protect.h b/Mesh_3/include/CGAL/Mesh_3/polylines_to_protect.h index 0df4d824cf9..eb2bee2e982 100644 --- a/Mesh_3/include/CGAL/Mesh_3/polylines_to_protect.h +++ b/Mesh_3/include/CGAL/Mesh_3/polylines_to_protect.h @@ -578,6 +578,7 @@ polylines_to_protect(std::vector >& polylines, Mesh_3::Polyline_visitor visitor(polylines, graph); Less_for_Graph_vertex_descriptors less(graph); const Graph& const_graph = graph; + typedef typename Kernel_traits

::Kernel K; split_graph_into_polylines(const_graph, visitor, Mesh_3::Angle_tester(), less); }