Merge pull request #1524 from lrineau/Mesh_3-split_graph_into_polylines_determinism-lrineau

Make split_graph_into_polylines deterministic
This commit is contained in:
Laurent Rineau 2016-10-05 15:13:19 +02:00 committed by GitHub
commit 7b57c42e51
2 changed files with 139 additions and 45 deletions

View File

@ -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 <typename G_copy, typename Less_on_orig_vertex_descriptors>
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<G_copy>::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 <typename Graph,
typename OrigGraph,
typename IsTerminal>
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 <typename Graph,
typename Visitor,
@ -133,6 +153,21 @@ void
split_graph_into_polylines(const Graph& graph,
Visitor& polyline_visitor,
IsTerminal is_terminal)
{
typedef typename boost::graph_traits<Graph>::vertex_descriptor Graph_vertex_descriptor;
std::less<Graph_vertex_descriptor> less;
split_graph_into_polylines(graph, polyline_visitor, is_terminal, less);
}
template <typename Graph,
typename Visitor,
typename IsTerminal,
typename LessForVertexDescriptors>
void
split_graph_into_polylines(const Graph& graph,
Visitor& polyline_visitor,
IsTerminal is_terminal,
LessForVertexDescriptors less)
{
typedef typename boost::graph_traits<Graph>::vertex_descriptor Graph_vertex_descriptor;
typedef typename boost::graph_traits<Graph>::edge_descriptor Graph_edge_descriptor;
@ -140,22 +175,22 @@ split_graph_into_polylines(const Graph& graph,
typedef boost::adjacency_list <boost::setS, // this avoids parallel edges
boost::vecS,
boost::undirectedS,
Graph_vertex_descriptor > G;
Graph_vertex_descriptor > G_copy;
typedef typename boost::graph_traits<G>::vertex_descriptor vertex_descriptor;
typedef typename boost::graph_traits<G>::edge_descriptor edge_descriptor;
typedef typename boost::graph_traits<G>::out_edge_iterator out_edge_iterator;
typedef typename boost::graph_traits<G_copy>::vertex_descriptor vertex_descriptor;
typedef typename boost::graph_traits<G_copy>::edge_descriptor edge_descriptor;
typedef typename boost::graph_traits<G_copy>::out_edge_iterator out_edge_iterator;
// we make a copy of the input graph
G g;
G_copy g_copy;
{
typedef std::map<typename boost::graph_traits<Graph>::vertex_descriptor,
typename boost::graph_traits<G>::vertex_descriptor> V2vmap;
typename boost::graph_traits<G_copy>::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<vertex_descriptor> terminal;
internal::duplicate_terminal_vertices(g_copy, graph, is_terminal);
BOOST_FOREACH(vertex_descriptor v, vertices(g)){
typename boost::graph_traits<Graph>::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<vertex_descriptor, G_copy_less> terminal(g_copy_less);
BOOST_FOREACH(vertex_descriptor v, vertices(g_copy)){
typename boost::graph_traits<Graph>::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();

View File

@ -68,6 +68,41 @@ struct Polyline_visitor
polylines.resize(polylines.size() - 1);
}
};
template <typename Kernel>
struct Angle_tester
{
template <typename vertex_descriptor, typename Graph>
bool operator()(vertex_descriptor& v, const Graph& g) const
{
typedef typename boost::graph_traits<Graph>::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`.
@ -119,6 +154,18 @@ template <typename K,
void snap_graph_vertices(Graph&, double, double, double, int, int, K)
{}
template <typename Graph>
struct Less_for_Graph_vertex_descriptors
{
const Graph& graph;
Less_for_Graph_vertex_descriptors(const Graph& graph) : graph(graph) {}
template <typename vertex_descriptor>
bool operator()(vertex_descriptor v1, vertex_descriptor v2) const {
return graph[v1] < graph[v2];
}
}; // end of Less_for_Graph_vertex_descriptors<Graph>
template <typename P,
typename Image_word_type,
typename Null_subdomain_index,
@ -490,7 +537,10 @@ case_4:
K());
Mesh_3::Polyline_visitor<Point_3, Graph> visitor(polylines, graph);
split_graph_into_polylines(graph, visitor);
Less_for_Graph_vertex_descriptors<Graph> less(graph);
const Graph& const_graph = graph;
split_graph_into_polylines(const_graph, visitor,
Mesh_3::Angle_tester<K>(), less);
}
template <typename P,
@ -526,7 +576,11 @@ polylines_to_protect(std::vector<std::vector<P> >& polylines,
}
Mesh_3::Polyline_visitor<Point_3, Graph> visitor(polylines, graph);
split_graph_into_polylines(graph, visitor);
Less_for_Graph_vertex_descriptors<Graph> less(graph);
const Graph& const_graph = graph;
typedef typename Kernel_traits<P>::Kernel K;
split_graph_into_polylines(const_graph, visitor,
Mesh_3::Angle_tester<K>(), less);
}
template <typename P, typename Image_word_type, typename Null_subdomain_index>