mirror of https://github.com/CGAL/cgal
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:
commit
1d6fcd84c8
|
|
@ -1,5 +1,6 @@
|
|||
Algebraic_foundations
|
||||
Arithmetic_kernel
|
||||
BGL
|
||||
Cartesian_kernel
|
||||
Circulator
|
||||
Distance_2
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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>`
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ STL_Extension
|
|||
Algebraic_foundations
|
||||
Circulator
|
||||
Stream_support
|
||||
BGL
|
||||
TDS_2
|
||||
Triangulation_3
|
||||
Spatial_sorting
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
Loading…
Reference in New Issue