mirror of https://github.com/CGAL/cgal
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:
commit
7b57c42e51
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Reference in New Issue