Merge pull request #4530 from sgiraudot/Triangulation_2-Split_subconstraint_graph_into_constraints-GF

[Small Feature] CDT+ Split Subconstraint Graph Into Constraints
This commit is contained in:
Sebastien Loriot 2020-03-27 16:03:04 +01:00 committed by GitHub
commit 1d6fcd84c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 237 additions and 0 deletions

View File

@ -1,5 +1,6 @@
Algebraic_foundations
Arithmetic_kernel
BGL
Cartesian_kernel
Circulator
Distance_2

View File

@ -293,6 +293,30 @@ std::size_t insert_constraints(PointIterator points_first, PointIterator points_
IndicesIterator indices_first, IndicesIterator indices_last);
/*!
splits into constraints the graph of subconstraints.
Consider the graph `g={V,E}` where `V` is the set of vertices of the
triangulation and `E` is the set of all subconstraints of all
constraints of the triangulation.
This function splits into polylines the graph `g` at vertices of
degree greater than 2 and at vertices for which
`is_terminal(v)==true`.
Each computed polyline is stored as a constraint of the triangulation.
\warning all existing constraints will be discarded.
\param is_terminal An optional function returning `true` if the vertex
`v` of degree 2 is a polyline endpoint and `false` otherwise. If
omitted, a function always returning `false` will be used, that is no
degree 2 vertex will be considered as a polyline endpoint.
\sa `split_graph_into_polylines()`
*/
void split_subconstraint_graph_into_constraints(const std::function<bool(Vertex_handle)>& is_terminal);
/*!
removes the constraint `cid`, without removing the points from the triangulation.
*/

View File

@ -1124,6 +1124,22 @@ through the edge.
\cgalExample{Triangulation_2/polylines_triangulation.cpp}
\subsection Triangulation_2ExampleBuildingFromSoup Example: Building a Triangulated Arrangement of Polylines from a Segment Soup
The `Constrained_triangulation_plus_2` structure is initialized by a
set of polylines. As users may only be able to provide a disconnected
segment soup as input, a member function \link
Constrained_triangulation_plus_2::split_subconstraint_graph_into_constraints()
`split_subconstraint_graph_into_constraints()` \endlink is provided:
this function identifies the polylines by connecting segments until a
vertex whose degree is different from 2 is reached.
The following code shows how a "blind" insertion of disconnected
segments can be processed into a set of well-defined polyline
constraints in a `Constrained_triangulation_plus_2`:
\cgalExample{Triangulation_2/segment_soup_to_polylines.cpp}
\section Section_2D_Triangulations_Hierarchy The Triangulation Hierarchy
The class `Triangulation_hierarchy_2<Tr>`

View File

@ -4,6 +4,7 @@ STL_Extension
Algebraic_foundations
Circulator
Stream_support
BGL
TDS_2
Triangulation_3
Spatial_sorting

View File

@ -19,5 +19,6 @@
\example Triangulation_2/voronoi.cpp
\example Triangulation_2/copy_triangulation_2.cpp
\example Triangulation_2/polylines_triangulation.cpp
\example Triangulation_2/segment_soup_to_polylines.cpp
\example Triangulation_2/draw_triangulation_2.cpp
*/

View File

@ -0,0 +1,51 @@
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
#include <CGAL/Constrained_Delaunay_triangulation_2.h>
#include <CGAL/Constrained_triangulation_plus_2.h>
typedef CGAL::Exact_predicates_exact_constructions_kernel K;
typedef CGAL::Constrained_Delaunay_triangulation_2<K> CDT;
typedef CGAL::Constrained_triangulation_plus_2<CDT> CDTP;
typedef CDTP::Point Point;
typedef CDTP::Constraint_id Cid;
typedef CDTP::Vertex_handle Vertex_handle;
int main()
{
CDTP cdtp;
// First polyline
cdtp.insert_constraint(Point(0,0), Point(1,1));
cdtp.insert_constraint(Point(1,1), Point(2,2));
cdtp.insert_constraint(Point(2,2), Point(3,3));
// Second polyline that cuts the first one in 2
cdtp.insert_constraint(Point(1,1), Point(1,2));
cdtp.insert_constraint(Point(1,2), Point(1,3));
// Third polyline
cdtp.insert_constraint(Point(10,10), Point(20,20));
cdtp.insert_constraint(Point(20,20), Point(30,30));
// Fourth polyline
cdtp.insert_constraint(Point(100,100), Point(200,200));
// Segment soup of 8 segments as input
std::cout << "Input CDT+ has " << cdtp.number_of_constraints() << " constraints/subconstraints" << std::endl;
std::cout << "Splitting subconstraints graph into constraints" << std::endl;
cdtp.split_subconstraint_graph_into_constraints();
// 5 polylines as output
std::cout << "Output CDT+ has " << cdtp.number_of_constraints() << " constraints:" << std::endl;
for (CDTP::Constraint_id cid : cdtp.constraints())
{
std::cout << " *";
for (CDTP::Vertex_handle vh : cdtp.vertices_in_constraint(cid))
std::cout << " (" << vh->point() << ")";
std::cout << std::endl;
}
return EXIT_SUCCESS;
}

View File

@ -21,6 +21,7 @@
#include <CGAL/triangulation_assertions.h>
#include <CGAL/Polygon_2.h>
#include <CGAL/Triangulation_2/internal/Polyline_constraint_hierarchy_2.h>
#include <CGAL/Triangulation_2/internal/CTP2_subconstraint_graph.h>
#include <boost/tuple/tuple.hpp>
#include <boost/type_traits/is_same.hpp>
@ -315,6 +316,22 @@ public:
return n;
}
*/
void split_subconstraint_graph_into_constraints(const std::function<bool(Vertex_handle)>& is_terminal
= std::function<bool(Vertex_handle)>())
{
internal::CTP2_graph_visitor<Self> visitor(*this);
if (is_terminal)
CGAL::split_graph_into_polylines (internal::CTP2_subconstraint_graph<Self>(*this), visitor,
[&is_terminal](Vertex_handle vh,
const internal::CTP2_subconstraint_graph<Self>&) -> bool
{
return is_terminal(vh);
});
else
CGAL::split_graph_into_polylines (internal::CTP2_subconstraint_graph<Self>(*this), visitor);
}
Vertex_handle push_back(const Point& p)
{
return insert(p);

View File

@ -0,0 +1,126 @@
// Copyright (c) 2020 GeometryFactory (France). All rights reserved.
//
// This file is part of CGAL (www.cgal.org)
//
// $URL$
// $Id$
// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial
//
//
// Author(s) : Simon Giraudot
#ifndef CGAL_CTP2_SUBCONSTRAINT_GRAPH_H
#define CGAL_CTP2_SUBCONSTRAINT_GRAPH_H
#include <CGAL/license/Triangulation_2.h>
#include <CGAL/boost/graph/internal/graph_traits_2D_triangulation_helper.h>
#include <CGAL/boost/graph/split_graph_into_polylines.h>
#include <CGAL/property_map.h>
namespace CGAL
{
namespace internal
{
template <typename CTP2>
class CTP2_subconstraint_graph
{
CTP2& ctp2;
public:
typedef typename CTP2::Vertex_handle vertex_descriptor;
typedef typename CTP2::Subconstraint edge_descriptor;
typedef boost::undirected_tag directed_category;
typedef boost::disallow_parallel_edge_tag edge_parallel_category;
struct CTP2_graph_traversal_category :
public virtual boost::bidirectional_graph_tag,
public virtual boost::adjacency_graph_tag,
public virtual boost::edge_list_graph_tag,
public virtual boost::vertex_list_graph_tag
{ };
typedef CTP2_graph_traversal_category traversal_category;
typedef internal::Dereference_to_handle_enforcer<
CTP2,
typename CTP2::Finite_vertices_iterator,
vertex_descriptor> vertex_iterator;
typedef typename CTP2::Subconstraint_iterator::value_type Subconstr_it_v_t;
typedef First_of_pair_property_map<Subconstr_it_v_t> Subconstr_map;
typedef Property_map_to_unary_function<Subconstr_map> Subconstr_uf;
typedef boost::transform_iterator<Subconstr_uf, typename CTP2::Subconstraint_iterator> edge_iterator;
CTP2_subconstraint_graph (CTP2& ctp2) : ctp2(ctp2) { }
friend Iterator_range<vertex_iterator> vertices (const CTP2_subconstraint_graph& g)
{
return make_range (vertex_iterator(g.ctp2.finite_vertices_begin()),
vertex_iterator(g.ctp2.finite_vertices_end()));
}
friend Iterator_range<edge_iterator> edges (const CTP2_subconstraint_graph& g)
{
return make_range (boost::make_transform_iterator(g.ctp2.subconstraints_begin(), Subconstr_uf(Subconstr_map())),
boost::make_transform_iterator(g.ctp2.subconstraints_end(), Subconstr_uf(Subconstr_map())));
}
friend vertex_descriptor source (edge_descriptor ed, const CTP2_subconstraint_graph&)
{
return ed.first;
}
friend vertex_descriptor target (edge_descriptor ed, const CTP2_subconstraint_graph&)
{
return ed.second;
}
};
template <typename CTP2>
class CTP2_graph_visitor
{
private:
CTP2& ctp2;
std::vector<typename CTP2::Constraint_id> to_remove;
typename CTP2::Constraint_id current;
typename CTP2::Vertex_handle latest_vertex;
public:
CTP2_graph_visitor (CTP2& ctp2) : ctp2 (ctp2) { }
void start_new_polyline()
{
latest_vertex = typename CTP2::Vertex_handle();
current = typename CTP2::Constraint_id();
}
void add_node (typename CTP2::Vertex_handle vh)
{
if (latest_vertex != typename CTP2::Vertex_handle())
{
to_remove.push_back (ctp2.context(latest_vertex, vh).id());
typename CTP2::Constraint_id cid = ctp2.insert_constraint(latest_vertex, vh);
if (current == typename CTP2::Constraint_id())
current = cid;
else
current = ctp2.concatenate (current, cid);
}
latest_vertex = vh;
}
void end_polyline()
{
for (typename CTP2::Constraint_id id : to_remove)
ctp2.remove_constraint(id);
to_remove.clear();
}
};
} // namespace internal
} // namespace CGAL
#endif // CGAL_CTP2_SUBCONSTRAINT_GRAPH_H