diff --git a/Polyline_simplification_2/package_info/Polyline_simplification_2/dependencies b/Polyline_simplification_2/package_info/Polyline_simplification_2/dependencies index ba5bb8645f3..46b60927a44 100644 --- a/Polyline_simplification_2/package_info/Polyline_simplification_2/dependencies +++ b/Polyline_simplification_2/package_info/Polyline_simplification_2/dependencies @@ -1,5 +1,6 @@ Algebraic_foundations Arithmetic_kernel +BGL Cartesian_kernel Circulator Distance_2 diff --git a/Triangulation_2/doc/Triangulation_2/CGAL/Constrained_triangulation_plus_2.h b/Triangulation_2/doc/Triangulation_2/CGAL/Constrained_triangulation_plus_2.h index 821d59c2d42..7f8eeddc547 100644 --- a/Triangulation_2/doc/Triangulation_2/CGAL/Constrained_triangulation_plus_2.h +++ b/Triangulation_2/doc/Triangulation_2/CGAL/Constrained_triangulation_plus_2.h @@ -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& is_terminal); + /*! removes the constraint `cid`, without removing the points from the triangulation. */ diff --git a/Triangulation_2/doc/Triangulation_2/Triangulation_2.txt b/Triangulation_2/doc/Triangulation_2/Triangulation_2.txt index 3c7e043b29a..90446677a4c 100644 --- a/Triangulation_2/doc/Triangulation_2/Triangulation_2.txt +++ b/Triangulation_2/doc/Triangulation_2/Triangulation_2.txt @@ -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` diff --git a/Triangulation_2/doc/Triangulation_2/dependencies b/Triangulation_2/doc/Triangulation_2/dependencies index 84dba85f07d..22ae69dcfef 100644 --- a/Triangulation_2/doc/Triangulation_2/dependencies +++ b/Triangulation_2/doc/Triangulation_2/dependencies @@ -4,6 +4,7 @@ STL_Extension Algebraic_foundations Circulator Stream_support +BGL TDS_2 Triangulation_3 Spatial_sorting diff --git a/Triangulation_2/doc/Triangulation_2/examples.txt b/Triangulation_2/doc/Triangulation_2/examples.txt index 45128d71309..7061593de13 100644 --- a/Triangulation_2/doc/Triangulation_2/examples.txt +++ b/Triangulation_2/doc/Triangulation_2/examples.txt @@ -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 */ diff --git a/Triangulation_2/examples/Triangulation_2/segment_soup_to_polylines.cpp b/Triangulation_2/examples/Triangulation_2/segment_soup_to_polylines.cpp new file mode 100644 index 00000000000..5eadd29090f --- /dev/null +++ b/Triangulation_2/examples/Triangulation_2/segment_soup_to_polylines.cpp @@ -0,0 +1,51 @@ +#include +#include +#include + +typedef CGAL::Exact_predicates_exact_constructions_kernel K; +typedef CGAL::Constrained_Delaunay_triangulation_2 CDT; +typedef CGAL::Constrained_triangulation_plus_2 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; +} diff --git a/Triangulation_2/include/CGAL/Constrained_triangulation_plus_2.h b/Triangulation_2/include/CGAL/Constrained_triangulation_plus_2.h index 51d291d1454..0b19a9a5698 100644 --- a/Triangulation_2/include/CGAL/Constrained_triangulation_plus_2.h +++ b/Triangulation_2/include/CGAL/Constrained_triangulation_plus_2.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -315,6 +316,22 @@ public: return n; } */ + + void split_subconstraint_graph_into_constraints(const std::function& is_terminal + = std::function()) + { + internal::CTP2_graph_visitor visitor(*this); + if (is_terminal) + CGAL::split_graph_into_polylines (internal::CTP2_subconstraint_graph(*this), visitor, + [&is_terminal](Vertex_handle vh, + const internal::CTP2_subconstraint_graph&) -> bool + { + return is_terminal(vh); + }); + else + CGAL::split_graph_into_polylines (internal::CTP2_subconstraint_graph(*this), visitor); + } + Vertex_handle push_back(const Point& p) { return insert(p); diff --git a/Triangulation_2/include/CGAL/Triangulation_2/internal/CTP2_subconstraint_graph.h b/Triangulation_2/include/CGAL/Triangulation_2/internal/CTP2_subconstraint_graph.h new file mode 100644 index 00000000000..77e212b9f04 --- /dev/null +++ b/Triangulation_2/include/CGAL/Triangulation_2/internal/CTP2_subconstraint_graph.h @@ -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 + +#include +#include + +#include + +namespace CGAL +{ + +namespace internal +{ + +template +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_map; + typedef Property_map_to_unary_function Subconstr_uf; + typedef boost::transform_iterator edge_iterator; + + CTP2_subconstraint_graph (CTP2& ctp2) : ctp2(ctp2) { } + + friend Iterator_range 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 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 +class CTP2_graph_visitor +{ +private: + CTP2& ctp2; + std::vector 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