summaryrefslogtreecommitdiff
path: root/boost/geometry/algorithms/detail
diff options
context:
space:
mode:
Diffstat (limited to 'boost/geometry/algorithms/detail')
-rw-r--r--boost/geometry/algorithms/detail/as_range.hpp107
-rw-r--r--boost/geometry/algorithms/detail/assign_box_corners.hpp93
-rw-r--r--boost/geometry/algorithms/detail/assign_indexed_point.hpp94
-rw-r--r--boost/geometry/algorithms/detail/assign_values.hpp443
-rw-r--r--boost/geometry/algorithms/detail/calculate_null.hpp38
-rw-r--r--boost/geometry/algorithms/detail/calculate_sum.hpp64
-rw-r--r--boost/geometry/algorithms/detail/convert_indexed_to_indexed.hpp80
-rw-r--r--boost/geometry/algorithms/detail/convert_point_to_point.hpp68
-rw-r--r--boost/geometry/algorithms/detail/disjoint.hpp225
-rw-r--r--boost/geometry/algorithms/detail/equals/collect_vectors.hpp315
-rw-r--r--boost/geometry/algorithms/detail/for_each_range.hpp148
-rw-r--r--boost/geometry/algorithms/detail/has_self_intersections.hpp120
-rw-r--r--boost/geometry/algorithms/detail/not.hpp50
-rw-r--r--boost/geometry/algorithms/detail/overlay/add_rings.hpp134
-rw-r--r--boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp53
-rw-r--r--boost/geometry/algorithms/detail/overlay/assign_parents.hpp337
-rw-r--r--boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp170
-rw-r--r--boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp55
-rw-r--r--boost/geometry/algorithms/detail/overlay/check_enrich.hpp172
-rw-r--r--boost/geometry/algorithms/detail/overlay/clip_linestring.hpp242
-rw-r--r--boost/geometry/algorithms/detail/overlay/convert_ring.hpp99
-rw-r--r--boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp295
-rw-r--r--boost/geometry/algorithms/detail/overlay/copy_segments.hpp328
-rw-r--r--boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp64
-rw-r--r--boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp523
-rw-r--r--boost/geometry/algorithms/detail/overlay/enrichment_info.hpp76
-rw-r--r--boost/geometry/algorithms/detail/overlay/follow.hpp416
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp146
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_relative_order.hpp108
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_ring.hpp102
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_turn_info.hpp956
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_turns.hpp866
-rw-r--r--boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp672
-rw-r--r--boost/geometry/algorithms/detail/overlay/intersection_insert.hpp690
-rw-r--r--boost/geometry/algorithms/detail/overlay/overlay.hpp301
-rw-r--r--boost/geometry/algorithms/detail/overlay/overlay_type.hpp29
-rw-r--r--boost/geometry/algorithms/detail/overlay/ring_properties.hpp78
-rw-r--r--boost/geometry/algorithms/detail/overlay/segment_identifier.hpp91
-rw-r--r--boost/geometry/algorithms/detail/overlay/select_rings.hpp295
-rw-r--r--boost/geometry/algorithms/detail/overlay/self_turn_points.hpp308
-rw-r--r--boost/geometry/algorithms/detail/overlay/stream_info.hpp75
-rw-r--r--boost/geometry/algorithms/detail/overlay/traversal_info.hpp47
-rw-r--r--boost/geometry/algorithms/detail/overlay/traverse.hpp395
-rw-r--r--boost/geometry/algorithms/detail/overlay/turn_info.hpp142
-rw-r--r--boost/geometry/algorithms/detail/overlay/visit_info.hpp136
-rw-r--r--boost/geometry/algorithms/detail/partition.hpp425
-rw-r--r--boost/geometry/algorithms/detail/point_on_border.hpp243
-rw-r--r--boost/geometry/algorithms/detail/ring_identifier.hpp70
-rw-r--r--boost/geometry/algorithms/detail/sections/range_by_section.hpp131
-rw-r--r--boost/geometry/algorithms/detail/sections/sectionalize.hpp648
-rw-r--r--boost/geometry/algorithms/detail/throw_on_empty_input.hpp53
51 files changed, 11816 insertions, 0 deletions
diff --git a/boost/geometry/algorithms/detail/as_range.hpp b/boost/geometry/algorithms/detail/as_range.hpp
new file mode 100644
index 0000000000..d0dfb07e43
--- /dev/null
+++ b/boost/geometry/algorithms/detail/as_range.hpp
@@ -0,0 +1,107 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_AS_RANGE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_AS_RANGE_HPP
+
+
+#include <boost/type_traits.hpp>
+
+#include <boost/geometry/core/exterior_ring.hpp>
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/util/add_const_if_c.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template <typename GeometryTag, typename Geometry, typename Range, bool IsConst>
+struct as_range
+{
+ static inline typename add_const_if_c<IsConst, Range>::type& get(
+ typename add_const_if_c<IsConst, Geometry>::type& input)
+ {
+ return input;
+ }
+};
+
+
+template <typename Geometry, typename Range, bool IsConst>
+struct as_range<polygon_tag, Geometry, Range, IsConst>
+{
+ static inline typename add_const_if_c<IsConst, Range>::type& get(
+ typename add_const_if_c<IsConst, Geometry>::type& input)
+ {
+ return exterior_ring(input);
+ }
+};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+// Will probably be replaced by the more generic "view_as", therefore in detail
+namespace detail
+{
+
+/*!
+\brief Function getting either the range (ring, linestring) itself
+or the outer ring (polygon)
+\details Utility to handle polygon's outer ring as a range
+\ingroup utility
+*/
+template <typename Range, typename Geometry>
+inline Range& as_range(Geometry& input)
+{
+ return dispatch::as_range
+ <
+ typename tag<Geometry>::type,
+ Geometry,
+ Range,
+ false
+ >::get(input);
+}
+
+
+/*!
+\brief Function getting either the range (ring, linestring) itself
+or the outer ring (polygon), const version
+\details Utility to handle polygon's outer ring as a range
+\ingroup utility
+*/
+template <typename Range, typename Geometry>
+inline Range const& as_range(Geometry const& input)
+{
+ return dispatch::as_range
+ <
+ typename tag<Geometry>::type,
+ Geometry,
+ Range,
+ true
+ >::get(input);
+}
+
+}
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_AS_RANGE_HPP
diff --git a/boost/geometry/algorithms/detail/assign_box_corners.hpp b/boost/geometry/algorithms/detail/assign_box_corners.hpp
new file mode 100644
index 0000000000..1fd41733f2
--- /dev/null
+++ b/boost/geometry/algorithms/detail/assign_box_corners.hpp
@@ -0,0 +1,93 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ASSIGN_BOX_CORNERS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ASSIGN_BOX_CORNERS_HPP
+
+
+#include <cstddef>
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+#include <boost/geometry/algorithms/detail/assign_values.hpp>
+
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail
+{
+// Note: this is moved to namespace detail because the names and parameter orders
+// are not yet 100% clear.
+
+/*!
+\brief Assign the four points of a 2D box
+\ingroup assign
+\note The order is crucial. Most logical is LOWER, UPPER and sub-order LEFT, RIGHT
+ so this is how it is implemented.
+\tparam Box \tparam_box
+\tparam Point \tparam_point
+\param box \param_box
+\param lower_left point being assigned to lower left coordinates of the box
+\param lower_right point being assigned to lower right coordinates of the box
+\param upper_left point being assigned to upper left coordinates of the box
+\param upper_right point being assigned to upper right coordinates of the box
+
+\qbk{
+[heading Example]
+[assign_box_corners] [assign_box_corners_output]
+}
+*/
+template <typename Box, typename Point>
+inline void assign_box_corners(Box const& box,
+ Point& lower_left, Point& lower_right,
+ Point& upper_left, Point& upper_right)
+{
+ concept::check<Box const>();
+ concept::check<Point>();
+
+ detail::assign::assign_box_2d_corner
+ <min_corner, min_corner>(box, lower_left);
+ detail::assign::assign_box_2d_corner
+ <max_corner, min_corner>(box, lower_right);
+ detail::assign::assign_box_2d_corner
+ <min_corner, max_corner>(box, upper_left);
+ detail::assign::assign_box_2d_corner
+ <max_corner, max_corner>(box, upper_right);
+}
+
+template <bool Reverse, typename Box, typename Range>
+inline void assign_box_corners_oriented(Box const& box, Range& corners)
+{
+ if (Reverse)
+ {
+ // make counterclockwise ll,lr,ur,ul
+ assign_box_corners(box, corners[0], corners[1], corners[3], corners[2]);
+ }
+ else
+ {
+ // make clockwise ll,ul,ur,lr
+ assign_box_corners(box, corners[0], corners[3], corners[1], corners[2]);
+ }
+}
+
+
+} // namespace detail
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ASSIGN_BOX_CORNERS_HPP
diff --git a/boost/geometry/algorithms/detail/assign_indexed_point.hpp b/boost/geometry/algorithms/detail/assign_indexed_point.hpp
new file mode 100644
index 0000000000..a1cffb80a7
--- /dev/null
+++ b/boost/geometry/algorithms/detail/assign_indexed_point.hpp
@@ -0,0 +1,94 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_ASSIGN_INDEXED_POINT_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_ASSIGN_INDEXED_POINT_HPP
+
+
+#include <cstddef>
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+#include <boost/geometry/algorithms/detail/assign_values.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail
+{
+
+/*!
+\brief Assign a box or segment with the value of a point
+\ingroup assign
+\tparam Index indicates which box-corner, min_corner (0) or max_corner (1)
+ or which point of segment (0/1)
+\tparam Point \tparam_point
+\tparam Geometry \tparam_box_or_segment
+\param point \param_point
+\param geometry \param_box_or_segment
+
+\qbk{
+[heading Example]
+[assign_point_to_index] [assign_point_to_index_output]
+}
+*/
+template <std::size_t Index, typename Geometry, typename Point>
+inline void assign_point_to_index(Point const& point, Geometry& geometry)
+{
+ concept::check<Point const>();
+ concept::check<Geometry>();
+
+ detail::assign::assign_point_to_index
+ <
+ Geometry, Point, Index, 0, dimension<Geometry>::type::value
+ >::apply(point, geometry);
+}
+
+
+/*!
+\brief Assign a point with a point of a box or segment
+\ingroup assign
+\tparam Index indicates which box-corner, min_corner (0) or max_corner (1)
+ or which point of segment (0/1)
+\tparam Geometry \tparam_box_or_segment
+\tparam Point \tparam_point
+\param geometry \param_box_or_segment
+\param point \param_point
+
+\qbk{
+[heading Example]
+[assign_point_from_index] [assign_point_from_index_output]
+}
+*/
+template <std::size_t Index, typename Point, typename Geometry>
+inline void assign_point_from_index(Geometry const& geometry, Point& point)
+{
+ concept::check<Geometry const>();
+ concept::check<Point>();
+
+ detail::assign::assign_point_from_index
+ <
+ Geometry, Point, Index, 0, dimension<Geometry>::type::value
+ >::apply(geometry, point);
+}
+
+
+} // namespace detail
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_ASSIGN_INDEXED_POINT_HPP
diff --git a/boost/geometry/algorithms/detail/assign_values.hpp b/boost/geometry/algorithms/detail/assign_values.hpp
new file mode 100644
index 0000000000..ed4713493f
--- /dev/null
+++ b/boost/geometry/algorithms/detail/assign_values.hpp
@@ -0,0 +1,443 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_ASSIGN_VALUES_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_ASSIGN_VALUES_HPP
+
+
+#include <cstddef>
+
+#include <boost/concept/requires.hpp>
+#include <boost/concept_check.hpp>
+#include <boost/mpl/assert.hpp>
+#include <boost/mpl/if.hpp>
+#include <boost/numeric/conversion/bounds.hpp>
+#include <boost/numeric/conversion/cast.hpp>
+#include <boost/type_traits.hpp>
+
+#include <boost/geometry/arithmetic/arithmetic.hpp>
+#include <boost/geometry/algorithms/append.hpp>
+#include <boost/geometry/algorithms/clear.hpp>
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/exterior_ring.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+
+
+#include <boost/geometry/util/for_each_coordinate.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace assign
+{
+
+
+template
+<
+ typename Box, std::size_t Index,
+ std::size_t Dimension, std::size_t DimensionCount
+>
+struct initialize
+{
+ typedef typename coordinate_type<Box>::type coordinate_type;
+
+ static inline void apply(Box& box, coordinate_type const& value)
+ {
+ geometry::set<Index, Dimension>(box, value);
+ initialize<Box, Index, Dimension + 1, DimensionCount>::apply(box, value);
+ }
+};
+
+
+template <typename Box, std::size_t Index, std::size_t DimensionCount>
+struct initialize<Box, Index, DimensionCount, DimensionCount>
+{
+ typedef typename coordinate_type<Box>::type coordinate_type;
+
+ static inline void apply(Box&, coordinate_type const& )
+ {}
+};
+
+
+template <typename Point>
+struct assign_zero_point
+{
+ static inline void apply(Point& point)
+ {
+ geometry::assign_value(point, 0);
+ }
+};
+
+
+template <typename BoxOrSegment>
+struct assign_inverse_box_or_segment
+{
+ typedef typename point_type<BoxOrSegment>::type point_type;
+
+ static inline void apply(BoxOrSegment& geometry)
+ {
+ typedef typename coordinate_type<point_type>::type bound_type;
+
+ initialize
+ <
+ BoxOrSegment, 0, 0, dimension<BoxOrSegment>::type::value
+ >::apply(
+ geometry, boost::numeric::bounds<bound_type>::highest());
+ initialize
+ <
+ BoxOrSegment, 1, 0, dimension<BoxOrSegment>::type::value
+ >::apply(
+ geometry, boost::numeric::bounds<bound_type>::lowest());
+ }
+};
+
+
+template <typename BoxOrSegment>
+struct assign_zero_box_or_segment
+{
+ static inline void apply(BoxOrSegment& geometry)
+ {
+ typedef typename coordinate_type<BoxOrSegment>::type coordinate_type;
+
+ initialize
+ <
+ BoxOrSegment, 0, 0, dimension<BoxOrSegment>::type::value
+ >::apply(geometry, coordinate_type());
+ initialize
+ <
+ BoxOrSegment, 1, 0, dimension<BoxOrSegment>::type::value
+ >::apply(geometry, coordinate_type());
+ }
+};
+
+
+template
+<
+ std::size_t Corner1, std::size_t Corner2,
+ typename Box, typename Point
+>
+inline void assign_box_2d_corner(Box const& box, Point& point)
+{
+ // Be sure both are 2-Dimensional
+ assert_dimension<Box, 2>();
+ assert_dimension<Point, 2>();
+
+ // Copy coordinates
+ typedef typename coordinate_type<Point>::type coordinate_type;
+
+ geometry::set<0>(point, boost::numeric_cast<coordinate_type>(get<Corner1, 0>(box)));
+ geometry::set<1>(point, boost::numeric_cast<coordinate_type>(get<Corner2, 1>(box)));
+}
+
+
+
+template
+<
+ typename Geometry, typename Point,
+ std::size_t Index,
+ std::size_t Dimension, std::size_t DimensionCount
+>
+struct assign_point_to_index
+{
+
+ static inline void apply(Point const& point, Geometry& geometry)
+ {
+ geometry::set<Index, Dimension>(geometry, boost::numeric_cast
+ <
+ typename coordinate_type<Geometry>::type
+ >(geometry::get<Dimension>(point)));
+
+ assign_point_to_index
+ <
+ Geometry, Point, Index, Dimension + 1, DimensionCount
+ >::apply(point, geometry);
+ }
+};
+
+template
+<
+ typename Geometry, typename Point,
+ std::size_t Index,
+ std::size_t DimensionCount
+>
+struct assign_point_to_index
+ <
+ Geometry, Point,
+ Index,
+ DimensionCount, DimensionCount
+ >
+{
+ static inline void apply(Point const& , Geometry& )
+ {
+ }
+};
+
+
+template
+<
+ typename Geometry, typename Point,
+ std::size_t Index,
+ std::size_t Dimension, std::size_t DimensionCount
+>
+struct assign_point_from_index
+{
+
+ static inline void apply(Geometry const& geometry, Point& point)
+ {
+ geometry::set<Dimension>( point, boost::numeric_cast
+ <
+ typename coordinate_type<Point>::type
+ >(geometry::get<Index, Dimension>(geometry)));
+
+ assign_point_from_index
+ <
+ Geometry, Point, Index, Dimension + 1, DimensionCount
+ >::apply(geometry, point);
+ }
+};
+
+template
+<
+ typename Geometry, typename Point,
+ std::size_t Index,
+ std::size_t DimensionCount
+>
+struct assign_point_from_index
+ <
+ Geometry, Point,
+ Index,
+ DimensionCount, DimensionCount
+ >
+{
+ static inline void apply(Geometry const&, Point&)
+ {
+ }
+};
+
+
+template <typename Geometry>
+struct assign_2d_box_or_segment
+{
+ typedef typename coordinate_type<Geometry>::type coordinate_type;
+
+ // Here we assign 4 coordinates to a box of segment
+ // -> Most logical is: x1,y1,x2,y2
+ // In case the user reverses x1/x2 or y1/y2, for a box, we could reverse them (THAT IS NOT IMPLEMENTED)
+
+ template <typename Type>
+ static inline void apply(Geometry& geometry,
+ Type const& x1, Type const& y1, Type const& x2, Type const& y2)
+ {
+ geometry::set<0, 0>(geometry, boost::numeric_cast<coordinate_type>(x1));
+ geometry::set<0, 1>(geometry, boost::numeric_cast<coordinate_type>(y1));
+ geometry::set<1, 0>(geometry, boost::numeric_cast<coordinate_type>(x2));
+ geometry::set<1, 1>(geometry, boost::numeric_cast<coordinate_type>(y2));
+ }
+};
+
+
+}} // namespace detail::assign
+#endif // DOXYGEN_NO_DETAIL
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+template <typename GeometryTag, typename Geometry, std::size_t DimensionCount>
+struct assign
+{
+ BOOST_MPL_ASSERT_MSG
+ (
+ false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
+ , (types<Geometry>)
+ );
+};
+
+template <typename Point>
+struct assign<point_tag, Point, 2>
+{
+ typedef typename coordinate_type<Point>::type coordinate_type;
+
+ template <typename T>
+ static inline void apply(Point& point, T const& c1, T const& c2)
+ {
+ set<0>(point, boost::numeric_cast<coordinate_type>(c1));
+ set<1>(point, boost::numeric_cast<coordinate_type>(c2));
+ }
+};
+
+template <typename Point>
+struct assign<point_tag, Point, 3>
+{
+ typedef typename coordinate_type<Point>::type coordinate_type;
+
+ template <typename T>
+ static inline void apply(Point& point, T const& c1, T const& c2, T const& c3)
+ {
+ set<0>(point, boost::numeric_cast<coordinate_type>(c1));
+ set<1>(point, boost::numeric_cast<coordinate_type>(c2));
+ set<2>(point, boost::numeric_cast<coordinate_type>(c3));
+ }
+};
+
+template <typename Box>
+struct assign<box_tag, Box, 2>
+ : detail::assign::assign_2d_box_or_segment<Box>
+{};
+
+template <typename Segment>
+struct assign<segment_tag, Segment, 2>
+ : detail::assign::assign_2d_box_or_segment<Segment>
+{};
+
+
+
+template <typename GeometryTag, typename Geometry>
+struct assign_zero {};
+
+
+template <typename Point>
+struct assign_zero<point_tag, Point>
+ : detail::assign::assign_zero_point<Point>
+{};
+
+template <typename Box>
+struct assign_zero<box_tag, Box>
+ : detail::assign::assign_zero_box_or_segment<Box>
+{};
+
+template <typename Segment>
+struct assign_zero<segment_tag, Segment>
+ : detail::assign::assign_zero_box_or_segment<Segment>
+{};
+
+
+template <typename GeometryTag, typename Geometry>
+struct assign_inverse {};
+
+template <typename Box>
+struct assign_inverse<box_tag, Box>
+ : detail::assign::assign_inverse_box_or_segment<Box>
+{};
+
+template <typename Segment>
+struct assign_inverse<segment_tag, Segment>
+ : detail::assign::assign_inverse_box_or_segment<Segment>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+/*!
+\brief Assign two coordinates to a geometry (usually a 2D point)
+\ingroup assign
+\tparam Geometry \tparam_geometry
+\tparam Type \tparam_numeric to specify the coordinates
+\param geometry \param_geometry
+\param c1 \param_x
+\param c2 \param_y
+
+\qbk{distinguish, 2 coordinate values}
+\qbk{
+[heading Example]
+[assign_2d_point] [assign_2d_point_output]
+
+[heading See also]
+\* [link geometry.reference.algorithms.make.make_2_2_coordinate_values make]
+}
+ */
+template <typename Geometry, typename Type>
+inline void assign_values(Geometry& geometry, Type const& c1, Type const& c2)
+{
+ concept::check<Geometry>();
+
+ dispatch::assign
+ <
+ typename tag<Geometry>::type,
+ Geometry,
+ geometry::dimension<Geometry>::type::value
+ >::apply(geometry, c1, c2);
+}
+
+/*!
+\brief Assign three values to a geometry (usually a 3D point)
+\ingroup assign
+\tparam Geometry \tparam_geometry
+\tparam Type \tparam_numeric to specify the coordinates
+\param geometry \param_geometry
+\param c1 \param_x
+\param c2 \param_y
+\param c3 \param_z
+
+\qbk{distinguish, 3 coordinate values}
+\qbk{
+[heading Example]
+[assign_3d_point] [assign_3d_point_output]
+
+[heading See also]
+\* [link geometry.reference.algorithms.make.make_3_3_coordinate_values make]
+}
+ */
+template <typename Geometry, typename Type>
+inline void assign_values(Geometry& geometry,
+ Type const& c1, Type const& c2, Type const& c3)
+{
+ concept::check<Geometry>();
+
+ dispatch::assign
+ <
+ typename tag<Geometry>::type,
+ Geometry,
+ geometry::dimension<Geometry>::type::value
+ >::apply(geometry, c1, c2, c3);
+}
+
+/*!
+\brief Assign four values to a geometry (usually a box or segment)
+\ingroup assign
+\tparam Geometry \tparam_geometry
+\tparam Type \tparam_numeric to specify the coordinates
+\param geometry \param_geometry
+\param c1 First coordinate (usually x1)
+\param c2 Second coordinate (usually y1)
+\param c3 Third coordinate (usually x2)
+\param c4 Fourth coordinate (usually y2)
+
+\qbk{distinguish, 4 coordinate values}
+ */
+template <typename Geometry, typename Type>
+inline void assign_values(Geometry& geometry,
+ Type const& c1, Type const& c2, Type const& c3, Type const& c4)
+{
+ concept::check<Geometry>();
+
+ dispatch::assign
+ <
+ typename tag<Geometry>::type,
+ Geometry,
+ geometry::dimension<Geometry>::type::value
+ >::apply(geometry, c1, c2, c3, c4);
+}
+
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_ASSIGN_VALUES_HPP
diff --git a/boost/geometry/algorithms/detail/calculate_null.hpp b/boost/geometry/algorithms/detail/calculate_null.hpp
new file mode 100644
index 0000000000..4b48d62fc2
--- /dev/null
+++ b/boost/geometry/algorithms/detail/calculate_null.hpp
@@ -0,0 +1,38 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_CALCULATE_NULL_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CALCULATE_NULL_HPP
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail
+{
+
+template<typename ReturnType, typename Geometry, typename Strategy>
+struct calculate_null
+{
+ static inline ReturnType apply(Geometry const& , Strategy const&)
+ {
+ return ReturnType();
+ }
+};
+
+} // namespace detail
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CALCULATE_NULL_HPP
diff --git a/boost/geometry/algorithms/detail/calculate_sum.hpp b/boost/geometry/algorithms/detail/calculate_sum.hpp
new file mode 100644
index 0000000000..2ad349080b
--- /dev/null
+++ b/boost/geometry/algorithms/detail/calculate_sum.hpp
@@ -0,0 +1,64 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_CALCULATE_SUM_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CALCULATE_SUM_HPP
+
+
+#include <boost/range.hpp>
+#include <boost/typeof/typeof.hpp>
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail
+{
+
+
+template
+<
+ typename ReturnType,
+ typename Polygon,
+ typename Strategy,
+ typename Policy
+>
+class calculate_polygon_sum
+{
+ template <typename Rings>
+ static inline ReturnType sum_interior_rings(Rings const& rings, Strategy const& strategy)
+ {
+ ReturnType sum = ReturnType();
+ for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
+ {
+ sum += Policy::apply(*it, strategy);
+ }
+ return sum;
+ }
+
+public :
+ static inline ReturnType apply(Polygon const& poly, Strategy const& strategy)
+ {
+ return Policy::apply(exterior_ring(poly), strategy)
+ + sum_interior_rings(interior_rings(poly), strategy)
+ ;
+ }
+};
+
+
+} // namespace detail
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CALCULATE_SUM_HPP
diff --git a/boost/geometry/algorithms/detail/convert_indexed_to_indexed.hpp b/boost/geometry/algorithms/detail/convert_indexed_to_indexed.hpp
new file mode 100644
index 0000000000..d39824a61d
--- /dev/null
+++ b/boost/geometry/algorithms/detail/convert_indexed_to_indexed.hpp
@@ -0,0 +1,80 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_CONVERT_INDEXED_TO_INDEXED_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CONVERT_INDEXED_TO_INDEXED_HPP
+
+
+#include <cstddef>
+
+#include <boost/numeric/conversion/cast.hpp>
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/coordinate_dimension.hpp>
+#include <boost/geometry/core/coordinate_type.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace conversion
+{
+
+
+template
+<
+ typename Source,
+ typename Destination,
+ std::size_t Dimension,
+ std::size_t DimensionCount
+>
+struct indexed_to_indexed
+{
+ static inline void apply(Source const& source, Destination& destination)
+ {
+ typedef typename coordinate_type<Destination>::type coordinate_type;
+
+ geometry::set<min_corner, Dimension>(destination,
+ boost::numeric_cast<coordinate_type>(
+ geometry::get<min_corner, Dimension>(source)));
+ geometry::set<max_corner, Dimension>(destination,
+ boost::numeric_cast<coordinate_type>(
+ geometry::get<max_corner, Dimension>(source)));
+
+ indexed_to_indexed
+ <
+ Source, Destination,
+ Dimension + 1, DimensionCount
+ >::apply(source, destination);
+ }
+};
+
+template
+<
+ typename Source,
+ typename Destination,
+ std::size_t DimensionCount
+>
+struct indexed_to_indexed<Source, Destination, DimensionCount, DimensionCount>
+{
+ static inline void apply(Source const& , Destination& )
+ {}
+};
+
+
+}} // namespace detail::conversion
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CONVERT_INDEXED_TO_INDEXED_HPP
diff --git a/boost/geometry/algorithms/detail/convert_point_to_point.hpp b/boost/geometry/algorithms/detail/convert_point_to_point.hpp
new file mode 100644
index 0000000000..c7d37b6ca4
--- /dev/null
+++ b/boost/geometry/algorithms/detail/convert_point_to_point.hpp
@@ -0,0 +1,68 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_CONVERT_POINT_TO_POINT_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CONVERT_POINT_TO_POINT_HPP
+
+// Note: extracted from "convert.hpp" to avoid circular references convert/append
+
+#include <cstddef>
+
+#include <boost/numeric/conversion/cast.hpp>
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/coordinate_dimension.hpp>
+#include <boost/geometry/core/coordinate_type.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace conversion
+{
+
+
+template <typename Source, typename Destination, std::size_t Dimension, std::size_t DimensionCount>
+struct point_to_point
+{
+ static inline void apply(Source const& source, Destination& destination)
+ {
+ typedef typename coordinate_type<Destination>::type coordinate_type;
+
+ set<Dimension>(destination, boost::numeric_cast<coordinate_type>(get<Dimension>(source)));
+ point_to_point<Source, Destination, Dimension + 1, DimensionCount>::apply(source, destination);
+ }
+};
+
+template <typename Source, typename Destination, std::size_t DimensionCount>
+struct point_to_point<Source, Destination, DimensionCount, DimensionCount>
+{
+ static inline void apply(Source const& , Destination& )
+ {}
+};
+
+
+template <typename Source, typename Destination>
+inline void convert_point_to_point(Source const& source, Destination& destination)
+{
+ point_to_point<Source, Destination, 0, dimension<Destination>::value>::apply(source, destination);
+}
+
+
+
+}} // namespace detail::conversion
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CONVERT_POINT_TO_POINT_HPP
diff --git a/boost/geometry/algorithms/detail/disjoint.hpp b/boost/geometry/algorithms/detail/disjoint.hpp
new file mode 100644
index 0000000000..2ced5b1ce3
--- /dev/null
+++ b/boost/geometry/algorithms/detail/disjoint.hpp
@@ -0,0 +1,225 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_HPP
+
+// Note: contrary to most files, the geometry::detail::disjoint namespace
+// is partly implemented in a separate file, to avoid circular references
+// disjoint -> get_turns -> disjoint
+
+#include <cstddef>
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/coordinate_dimension.hpp>
+#include <boost/geometry/core/reverse_dispatch.hpp>
+
+
+#include <boost/geometry/util/math.hpp>
+
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace disjoint
+{
+
+
+struct disjoint_interrupt_policy
+{
+ static bool const enabled = true;
+ bool has_intersections;
+
+ inline disjoint_interrupt_policy()
+ : has_intersections(false)
+ {}
+
+ template <typename Range>
+ inline bool apply(Range const& range)
+ {
+ // If there is any IP in the range, it is NOT disjoint
+ if (boost::size(range) > 0)
+ {
+ has_intersections = true;
+ return true;
+ }
+ return false;
+ }
+};
+
+
+
+template
+<
+ typename Point1, typename Point2,
+ std::size_t Dimension, std::size_t DimensionCount
+>
+struct point_point
+{
+ static inline bool apply(Point1 const& p1, Point2 const& p2)
+ {
+ if (! geometry::math::equals(get<Dimension>(p1), get<Dimension>(p2)))
+ {
+ return true;
+ }
+ return point_point
+ <
+ Point1, Point2,
+ Dimension + 1, DimensionCount
+ >::apply(p1, p2);
+ }
+};
+
+
+template <typename Point1, typename Point2, std::size_t DimensionCount>
+struct point_point<Point1, Point2, DimensionCount, DimensionCount>
+{
+ static inline bool apply(Point1 const& , Point2 const& )
+ {
+ return false;
+ }
+};
+
+
+template
+<
+ typename Point, typename Box,
+ std::size_t Dimension, std::size_t DimensionCount
+>
+struct point_box
+{
+ static inline bool apply(Point const& point, Box const& box)
+ {
+ if (get<Dimension>(point) < get<min_corner, Dimension>(box)
+ || get<Dimension>(point) > get<max_corner, Dimension>(box))
+ {
+ return true;
+ }
+ return point_box
+ <
+ Point, Box,
+ Dimension + 1, DimensionCount
+ >::apply(point, box);
+ }
+};
+
+
+template <typename Point, typename Box, std::size_t DimensionCount>
+struct point_box<Point, Box, DimensionCount, DimensionCount>
+{
+ static inline bool apply(Point const& , Box const& )
+ {
+ return false;
+ }
+};
+
+
+template
+<
+ typename Box1, typename Box2,
+ std::size_t Dimension, std::size_t DimensionCount
+>
+struct box_box
+{
+ static inline bool apply(Box1 const& box1, Box2 const& box2)
+ {
+ if (get<max_corner, Dimension>(box1) < get<min_corner, Dimension>(box2))
+ {
+ return true;
+ }
+ if (get<min_corner, Dimension>(box1) > get<max_corner, Dimension>(box2))
+ {
+ return true;
+ }
+ return box_box
+ <
+ Box1, Box2,
+ Dimension + 1, DimensionCount
+ >::apply(box1, box2);
+ }
+};
+
+
+template <typename Box1, typename Box2, std::size_t DimensionCount>
+struct box_box<Box1, Box2, DimensionCount, DimensionCount>
+{
+ static inline bool apply(Box1 const& , Box2 const& )
+ {
+ return false;
+ }
+};
+
+
+
+/*!
+ \brief Internal utility function to detect of boxes are disjoint
+ \note Is used from other algorithms, declared separately
+ to avoid circular references
+ */
+template <typename Box1, typename Box2>
+inline bool disjoint_box_box(Box1 const& box1, Box2 const& box2)
+{
+ return box_box
+ <
+ Box1, Box2,
+ 0, dimension<Box1>::type::value
+ >::apply(box1, box2);
+}
+
+
+
+/*!
+ \brief Internal utility function to detect of points are disjoint
+ \note To avoid circular references
+ */
+template <typename Point1, typename Point2>
+inline bool disjoint_point_point(Point1 const& point1, Point2 const& point2)
+{
+ return point_point
+ <
+ Point1, Point2,
+ 0, dimension<Point1>::type::value
+ >::apply(point1, point2);
+}
+
+
+}} // namespace detail::disjoint
+#endif // DOXYGEN_NO_DETAIL
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace equals
+{
+
+/*!
+ \brief Internal utility function to detect of points are disjoint
+ \note To avoid circular references
+ */
+template <typename Point1, typename Point2>
+inline bool equals_point_point(Point1 const& point1, Point2 const& point2)
+{
+ return ! detail::disjoint::disjoint_point_point(point1, point2);
+}
+
+
+}} // namespace detail::equals
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DISJOINT_HPP
diff --git a/boost/geometry/algorithms/detail/equals/collect_vectors.hpp b/boost/geometry/algorithms/detail/equals/collect_vectors.hpp
new file mode 100644
index 0000000000..9c2fe28057
--- /dev/null
+++ b/boost/geometry/algorithms/detail/equals/collect_vectors.hpp
@@ -0,0 +1,315 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_COLLECT_VECTORS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_COLLECT_VECTORS_HPP
+
+
+#include <boost/numeric/conversion/cast.hpp>
+#include <boost/range.hpp>
+#include <boost/typeof/typeof.hpp>
+
+#include <boost/geometry/multi/core/tags.hpp>
+
+#include <boost/geometry/core/cs.hpp>
+#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/geometries/concepts/check.hpp>
+
+#include <boost/geometry/util/math.hpp>
+
+
+
+namespace boost { namespace geometry
+{
+
+// TODO: if Boost.LA of Emil Dotchevski is accepted, adapt this
+template <typename T>
+struct collected_vector
+{
+ typedef T type;
+
+ inline collected_vector()
+ {}
+
+ inline collected_vector(T const& px, T const& py,
+ T const& pdx, T const& pdy)
+ : x(px)
+ , y(py)
+ , dx(pdx)
+ , dy(pdy)
+ , dx_0(T())
+ , dy_0(T())
+ {}
+
+ T x, y;
+ T dx, dy;
+ T dx_0, dy_0;
+
+ // For sorting
+ inline bool operator<(collected_vector<T> const& other) const
+ {
+ if (math::equals(x, other.x))
+ {
+ if (math::equals(y, other.y))
+ {
+ if (math::equals(dx, other.dx))
+ {
+ return dy < other.dy;
+ }
+ return dx < other.dx;
+ }
+ return y < other.y;
+ }
+ return x < other.x;
+ }
+
+ inline bool same_direction(collected_vector<T> const& other) const
+ {
+ // For high precision arithmetic, we have to be
+ // more relaxed then using ==
+ // Because 2/sqrt( (0,0)<->(2,2) ) == 1/sqrt( (0,0)<->(1,1) )
+ // is not always true (at least, it is not for ttmath)
+ return math::equals_with_epsilon(dx, other.dx)
+ && math::equals_with_epsilon(dy, other.dy);
+ }
+
+ // For std::equals
+ inline bool operator==(collected_vector<T> const& other) const
+ {
+ return math::equals(x, other.x)
+ && math::equals(y, other.y)
+ && same_direction(other);
+ }
+};
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace collect_vectors
+{
+
+
+template <typename Range, typename Collection>
+struct range_collect_vectors
+{
+ typedef typename boost::range_value<Collection>::type item_type;
+ typedef typename item_type::type calculation_type;
+
+ static inline void apply(Collection& collection, Range const& range)
+ {
+ if (boost::size(range) < 2)
+ {
+ return;
+ }
+
+ typedef typename boost::range_iterator<Range const>::type iterator;
+
+ bool first = true;
+ iterator it = boost::begin(range);
+
+ for (iterator prev = it++;
+ it != boost::end(range);
+ prev = it++)
+ {
+ typename boost::range_value<Collection>::type v;
+
+ v.x = get<0>(*prev);
+ v.y = get<1>(*prev);
+ v.dx = get<0>(*it) - v.x;
+ v.dy = get<1>(*it) - v.y;
+ v.dx_0 = v.dx;
+ v.dy_0 = v.dy;
+
+ // Normalize the vector -> this results in points+direction
+ // and is comparible between geometries
+ calculation_type magnitude = sqrt(
+ boost::numeric_cast<calculation_type>(v.dx * v.dx + v.dy * v.dy));
+
+ // Avoid non-duplicate points (AND division by zero)
+ if (magnitude > 0)
+ {
+ v.dx /= magnitude;
+ v.dy /= magnitude;
+
+ // Avoid non-direction changing points
+ if (first || ! v.same_direction(collection.back()))
+ {
+ collection.push_back(v);
+ }
+ first = false;
+ }
+ }
+
+ // If first one has same direction as last one, remove first one
+ if (boost::size(collection) > 1
+ && collection.front().same_direction(collection.back()))
+ {
+ collection.erase(collection.begin());
+ }
+ }
+};
+
+
+template <typename Box, typename Collection>
+struct box_collect_vectors
+{
+ // Calculate on coordinate type, but if it is integer,
+ // then use double
+ typedef typename boost::range_value<Collection>::type item_type;
+ typedef typename item_type::type calculation_type;
+
+ static inline void apply(Collection& collection, Box const& box)
+ {
+ typename point_type<Box>::type lower_left, lower_right,
+ upper_left, upper_right;
+ geometry::detail::assign_box_corners(box, lower_left, lower_right,
+ upper_left, upper_right);
+
+ typedef typename boost::range_value<Collection>::type item;
+
+ collection.push_back(item(get<0>(lower_left), get<1>(lower_left), 0, 1));
+ collection.push_back(item(get<0>(upper_left), get<1>(upper_left), 1, 0));
+ collection.push_back(item(get<0>(upper_right), get<1>(upper_right), 0, -1));
+ collection.push_back(item(get<0>(lower_right), get<1>(lower_right), -1, 0));
+ }
+};
+
+
+template <typename Polygon, typename Collection>
+struct polygon_collect_vectors
+{
+ static inline void apply(Collection& collection, Polygon const& polygon)
+ {
+ typedef typename geometry::ring_type<Polygon>::type ring_type;
+
+ typedef range_collect_vectors<ring_type, Collection> per_range;
+ per_range::apply(collection, exterior_ring(polygon));
+
+ typename interior_return_type<Polygon const>::type rings
+ = interior_rings(polygon);
+ for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
+ {
+ per_range::apply(collection, *it);
+ }
+ }
+};
+
+
+template <typename MultiGeometry, typename Collection, typename SinglePolicy>
+struct multi_collect_vectors
+{
+ static inline void apply(Collection& collection, MultiGeometry const& multi)
+ {
+ for (typename boost::range_iterator<MultiGeometry const>::type
+ it = boost::begin(multi);
+ it != boost::end(multi);
+ ++it)
+ {
+ SinglePolicy::apply(collection, *it);
+ }
+ }
+};
+
+
+}} // namespace detail::collect_vectors
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template
+<
+ typename Tag,
+ typename Collection,
+ typename Geometry
+>
+struct collect_vectors
+{
+ static inline void apply(Collection&, Geometry const&)
+ {}
+};
+
+
+template <typename Collection, typename Box>
+struct collect_vectors<box_tag, Collection, Box>
+ : detail::collect_vectors::box_collect_vectors<Box, Collection>
+{};
+
+
+
+template <typename Collection, typename Ring>
+struct collect_vectors<ring_tag, Collection, Ring>
+ : detail::collect_vectors::range_collect_vectors<Ring, Collection>
+{};
+
+
+template <typename Collection, typename LineString>
+struct collect_vectors<linestring_tag, Collection, LineString>
+ : detail::collect_vectors::range_collect_vectors<LineString, Collection>
+{};
+
+
+template <typename Collection, typename Polygon>
+struct collect_vectors<polygon_tag, Collection, Polygon>
+ : detail::collect_vectors::polygon_collect_vectors<Polygon, Collection>
+{};
+
+
+template <typename Collection, typename MultiPolygon>
+struct collect_vectors<multi_polygon_tag, Collection, MultiPolygon>
+ : detail::collect_vectors::multi_collect_vectors
+ <
+ MultiPolygon,
+ Collection,
+ detail::collect_vectors::polygon_collect_vectors
+ <
+ typename boost::range_value<MultiPolygon>::type,
+ Collection
+ >
+ >
+{};
+
+
+
+} // namespace dispatch
+#endif
+
+
+/*!
+ \ingroup collect_vectors
+ \tparam Collection Collection type, should be e.g. std::vector<>
+ \tparam Geometry geometry type
+ \param collection the collection of vectors
+ \param geometry the geometry to make collect_vectors
+*/
+template <typename Collection, typename Geometry>
+inline void collect_vectors(Collection& collection, Geometry const& geometry)
+{
+ concept::check<Geometry const>();
+
+ dispatch::collect_vectors
+ <
+ typename tag<Geometry>::type,
+ Collection,
+ Geometry
+ >::apply(collection, geometry);
+}
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_COLLECT_VECTORS_HPP
diff --git a/boost/geometry/algorithms/detail/for_each_range.hpp b/boost/geometry/algorithms/detail/for_each_range.hpp
new file mode 100644
index 0000000000..b10017c209
--- /dev/null
+++ b/boost/geometry/algorithms/detail/for_each_range.hpp
@@ -0,0 +1,148 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_FOR_EACH_RANGE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_FOR_EACH_RANGE_HPP
+
+
+#include <boost/mpl/assert.hpp>
+#include <boost/concept/requires.hpp>
+
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tag_cast.hpp>
+
+#include <boost/geometry/util/add_const_if_c.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace for_each
+{
+
+
+template <typename Range, typename Actor, bool IsConst>
+struct fe_range_range
+{
+ static inline void apply(
+ typename add_const_if_c<IsConst, Range>::type& range,
+ Actor& actor)
+ {
+ actor.apply(range);
+ }
+};
+
+
+template <typename Polygon, typename Actor, bool IsConst>
+struct fe_range_polygon
+{
+ static inline void apply(
+ typename add_const_if_c<IsConst, Polygon>::type& polygon,
+ Actor& actor)
+ {
+ actor.apply(exterior_ring(polygon));
+
+ // TODO: If some flag says true, also do the inner rings.
+ // for convex hull, it's not necessary
+ }
+};
+
+template <typename Box, typename Actor, bool IsConst>
+struct fe_range_box
+{
+ static inline void apply(
+ typename add_const_if_c<IsConst, Box>::type& box,
+ Actor& actor)
+ {
+ actor.apply(box_view<Box>(box));
+ }
+};
+
+
+}} // namespace detail::for_each
+#endif // DOXYGEN_NO_DETAIL
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template
+<
+ typename Tag,
+ typename Geometry,
+ typename Actor,
+ bool IsConst
+>
+struct for_each_range
+{
+ BOOST_MPL_ASSERT_MSG
+ (
+ false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
+ , (types<Geometry>)
+ );
+};
+
+
+template <typename Linestring, typename Actor, bool IsConst>
+struct for_each_range<linestring_tag, Linestring, Actor, IsConst>
+ : detail::for_each::fe_range_range<Linestring, Actor, IsConst>
+{};
+
+
+template <typename Ring, typename Actor, bool IsConst>
+struct for_each_range<ring_tag, Ring, Actor, IsConst>
+ : detail::for_each::fe_range_range<Ring, Actor, IsConst>
+{};
+
+
+template <typename Polygon, typename Actor, bool IsConst>
+struct for_each_range<polygon_tag, Polygon, Actor, IsConst>
+ : detail::for_each::fe_range_polygon<Polygon, Actor, IsConst>
+{};
+
+template <typename Box, typename Actor, bool IsConst>
+struct for_each_range<box_tag, Box, Actor, IsConst>
+ : detail::for_each::fe_range_box<Box, Actor, IsConst>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+namespace detail
+{
+
+template <typename Geometry, typename Actor>
+inline void for_each_range(Geometry const& geometry, Actor& actor)
+{
+ dispatch::for_each_range
+ <
+ typename tag<Geometry>::type,
+ Geometry,
+ Actor,
+ true
+ >::apply(geometry, actor);
+}
+
+
+}
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_FOR_EACH_RANGE_HPP
diff --git a/boost/geometry/algorithms/detail/has_self_intersections.hpp b/boost/geometry/algorithms/detail/has_self_intersections.hpp
new file mode 100644
index 0000000000..1e6215ed93
--- /dev/null
+++ b/boost/geometry/algorithms/detail/has_self_intersections.hpp
@@ -0,0 +1,120 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2011-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_HAS_SELF_INTERSECTIONS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_HAS_SELF_INTERSECTIONS_HPP
+
+#include <deque>
+
+#include <boost/range.hpp>
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
+#include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp>
+
+#include <boost/geometry/multi/algorithms/detail/overlay/self_turn_points.hpp>
+
+#ifdef BOOST_GEOMETRY_DEBUG_HAS_SELF_INTERSECTIONS
+# include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
+# include <boost/geometry/io/dsv/write.hpp>
+#endif
+
+
+namespace boost { namespace geometry
+{
+
+
+#if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW)
+
+/*!
+\brief Overlay Invalid Input Exception
+\ingroup overlay
+\details The overlay_invalid_input_exception is thrown at invalid input
+ */
+class overlay_invalid_input_exception : public geometry::exception
+{
+public:
+
+ inline overlay_invalid_input_exception() {}
+
+ virtual char const* what() const throw()
+ {
+ return "Boost.Geometry Overlay invalid input exception";
+ }
+};
+
+#endif
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+
+template <typename Geometry>
+inline bool has_self_intersections(Geometry const& geometry)
+{
+ typedef typename point_type<Geometry>::type point_type;
+ typedef detail::overlay::turn_info<point_type> turn_info;
+ std::deque<turn_info> turns;
+ detail::disjoint::disjoint_interrupt_policy policy;
+ geometry::self_turns<detail::overlay::assign_null_policy>(geometry, turns, policy);
+
+#ifdef BOOST_GEOMETRY_DEBUG_HAS_SELF_INTERSECTIONS
+ bool first = true;
+#endif
+ for(typename std::deque<turn_info>::const_iterator it = boost::begin(turns);
+ it != boost::end(turns); ++it)
+ {
+ turn_info const& info = *it;
+ bool const both_union_turn =
+ info.operations[0].operation == detail::overlay::operation_union
+ && info.operations[1].operation == detail::overlay::operation_union;
+ bool const both_intersection_turn =
+ info.operations[0].operation == detail::overlay::operation_intersection
+ && info.operations[1].operation == detail::overlay::operation_intersection;
+
+ bool const valid = (both_union_turn || both_intersection_turn)
+ && (info.method == detail::overlay::method_touch
+ || info.method == detail::overlay::method_touch_interior);
+
+ if (! valid)
+ {
+#ifdef BOOST_GEOMETRY_DEBUG_HAS_SELF_INTERSECTIONS
+ if (first)
+ {
+ std::cout << "turn points: " << std::endl;
+ first = false;
+ }
+ std::cout << method_char(info.method);
+ for (int i = 0; i < 2; i++)
+ {
+ std::cout << " " << operation_char(info.operations[i].operation);
+ }
+ std::cout << " " << geometry::dsv(info.point) << std::endl;
+#endif
+
+#if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW)
+ throw overlay_invalid_input_exception();
+#endif
+ }
+
+ }
+ return false;
+}
+
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_HAS_SELF_INTERSECTIONS_HPP
+
diff --git a/boost/geometry/algorithms/detail/not.hpp b/boost/geometry/algorithms/detail/not.hpp
new file mode 100644
index 0000000000..abc3a4e168
--- /dev/null
+++ b/boost/geometry/algorithms/detail/not.hpp
@@ -0,0 +1,50 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_NOT_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_NOT_HPP
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail
+{
+
+
+
+/*!
+\brief Structure negating the result of specified policy
+\tparam Geometry1 \tparam_geometry
+\tparam Geometry2 \tparam_geometry
+\tparam Policy
+\param geometry1 \param_geometry
+\param geometry2 \param_geometry
+\return Negation of the result of the policy
+ */
+template <typename Geometry1, typename Geometry2, typename Policy>
+struct not_
+{
+ static inline bool apply(Geometry1 const &geometry1, Geometry2 const& geometry2)
+ {
+ return ! Policy::apply(geometry1, geometry2);
+ }
+};
+
+
+} // namespace detail
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_NOT_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/add_rings.hpp b/boost/geometry/algorithms/detail/overlay/add_rings.hpp
new file mode 100644
index 0000000000..eb3e60e483
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/add_rings.hpp
@@ -0,0 +1,134 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ADD_RINGS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ADD_RINGS_HPP
+
+#include <boost/geometry/algorithms/detail/overlay/convert_ring.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_ring.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+template
+<
+ typename GeometryOut,
+ typename Geometry1,
+ typename Geometry2,
+ typename RingCollection
+>
+inline void convert_and_add(GeometryOut& result,
+ Geometry1 const& geometry1, Geometry2 const& geometry2,
+ RingCollection const& collection,
+ ring_identifier id,
+ bool reversed, bool append)
+{
+ typedef typename geometry::tag<Geometry1>::type tag1;
+ typedef typename geometry::tag<Geometry2>::type tag2;
+ typedef typename geometry::tag<GeometryOut>::type tag_out;
+
+ if (id.source_index == 0)
+ {
+ convert_ring<tag_out>::apply(result,
+ get_ring<tag1>::apply(id, geometry1),
+ append, reversed);
+ }
+ else if (id.source_index == 1)
+ {
+ convert_ring<tag_out>::apply(result,
+ get_ring<tag2>::apply(id, geometry2),
+ append, reversed);
+ }
+ else if (id.source_index == 2)
+ {
+ convert_ring<tag_out>::apply(result,
+ get_ring<void>::apply(id, collection),
+ append, reversed);
+ }
+}
+
+template
+<
+ typename GeometryOut,
+ typename SelectionMap,
+ typename Geometry1,
+ typename Geometry2,
+ typename RingCollection,
+ typename OutputIterator
+>
+inline OutputIterator add_rings(SelectionMap const& map,
+ Geometry1 const& geometry1, Geometry2 const& geometry2,
+ RingCollection const& collection,
+ OutputIterator out)
+{
+ typedef typename SelectionMap::const_iterator iterator;
+
+ for (iterator it = boost::begin(map);
+ it != boost::end(map);
+ ++it)
+ {
+ if (! it->second.discarded
+ && it->second.parent.source_index == -1)
+ {
+ GeometryOut result;
+ convert_and_add(result, geometry1, geometry2, collection,
+ it->first, it->second.reversed, false);
+
+ // Add children
+ for (typename std::vector<ring_identifier>::const_iterator child_it
+ = it->second.children.begin();
+ child_it != it->second.children.end();
+ ++child_it)
+ {
+ iterator mit = map.find(*child_it);
+ if (mit != map.end()
+ && ! mit->second.discarded)
+ {
+ convert_and_add(result, geometry1, geometry2, collection,
+ *child_it, mit->second.reversed, true);
+ }
+ }
+ *out++ = result;
+ }
+ }
+ return out;
+}
+
+
+template
+<
+ typename GeometryOut,
+ typename SelectionMap,
+ typename Geometry,
+ typename RingCollection,
+ typename OutputIterator
+>
+inline OutputIterator add_rings(SelectionMap const& map,
+ Geometry const& geometry,
+ RingCollection const& collection,
+ OutputIterator out)
+{
+ Geometry empty;
+ return add_rings<GeometryOut>(map, geometry, empty, collection, out);
+}
+
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ADD_RINGS_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp b/boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp
new file mode 100644
index 0000000000..2c0f88e2aa
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp
@@ -0,0 +1,53 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_APPEND_NO_DUPLICATES_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_APPEND_NO_DUPLICATES_HPP
+
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/algorithms/append.hpp>
+#include <boost/geometry/algorithms/detail/disjoint.hpp>
+
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+template <typename Range, typename Point>
+inline void append_no_duplicates(Range& range, Point const& point, bool force = false)
+{
+ if (boost::size(range) == 0
+ || force
+ || ! geometry::detail::equals::equals_point_point(*(boost::end(range)-1), point))
+ {
+#ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION
+ std::cout << " add: ("
+ << geometry::get<0>(point) << ", " << geometry::get<1>(point) << ")"
+ << std::endl;
+#endif
+ geometry::append(range, point);
+ }
+}
+
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_APPEND_NO_DUPLICATES_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/assign_parents.hpp b/boost/geometry/algorithms/detail/overlay/assign_parents.hpp
new file mode 100644
index 0000000000..133530563e
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/assign_parents.hpp
@@ -0,0 +1,337 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ASSIGN_PARENTS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ASSIGN_PARENTS_HPP
+
+#include <boost/geometry/algorithms/area.hpp>
+#include <boost/geometry/algorithms/envelope.hpp>
+#include <boost/geometry/algorithms/expand.hpp>
+#include <boost/geometry/algorithms/detail/partition.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_ring.hpp>
+#include <boost/geometry/algorithms/within.hpp>
+
+#include <boost/geometry/geometries/box.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+
+
+template
+<
+ typename Item,
+ typename Geometry1, typename Geometry2,
+ typename RingCollection
+>
+static inline bool within_selected_input(Item const& item2, ring_identifier const& ring_id,
+ Geometry1 const& geometry1, Geometry2 const& geometry2,
+ RingCollection const& collection)
+{
+ typedef typename geometry::tag<Geometry1>::type tag1;
+ typedef typename geometry::tag<Geometry2>::type tag2;
+
+ switch (ring_id.source_index)
+ {
+ case 0 :
+ return geometry::within(item2.point,
+ get_ring<tag1>::apply(ring_id, geometry1));
+ break;
+ case 1 :
+ return geometry::within(item2.point,
+ get_ring<tag2>::apply(ring_id, geometry2));
+ break;
+ case 2 :
+ return geometry::within(item2.point,
+ get_ring<void>::apply(ring_id, collection));
+ break;
+ }
+ return false;
+}
+
+
+template <typename Point>
+struct ring_info_helper
+{
+ typedef typename geometry::default_area_result<Point>::type area_type;
+
+ ring_identifier id;
+ area_type real_area;
+ area_type abs_area;
+ model::box<Point> envelope;
+
+ inline ring_info_helper()
+ : real_area(0), abs_area(0)
+ {}
+
+ inline ring_info_helper(ring_identifier i, area_type a)
+ : id(i), real_area(a), abs_area(geometry::math::abs(a))
+ {}
+};
+
+
+struct ring_info_helper_get_box
+{
+ template <typename Box, typename InputItem>
+ static inline void apply(Box& total, InputItem const& item)
+ {
+ geometry::expand(total, item.envelope);
+ }
+};
+
+struct ring_info_helper_ovelaps_box
+{
+ template <typename Box, typename InputItem>
+ static inline bool apply(Box const& box, InputItem const& item)
+ {
+ return ! geometry::detail::disjoint::disjoint_box_box(box, item.envelope);
+ }
+};
+
+template <typename Geometry1, typename Geometry2, typename Collection, typename RingMap>
+struct assign_visitor
+{
+ typedef typename RingMap::mapped_type ring_info_type;
+
+ Geometry1 const& m_geometry1;
+ Geometry2 const& m_geometry2;
+ Collection const& m_collection;
+ RingMap& m_ring_map;
+ bool m_check_for_orientation;
+
+
+ inline assign_visitor(Geometry1 const& g1, Geometry2 const& g2, Collection const& c,
+ RingMap& map, bool check)
+ : m_geometry1(g1)
+ , m_geometry2(g2)
+ , m_collection(c)
+ , m_ring_map(map)
+ , m_check_for_orientation(check)
+ {}
+
+ template <typename Item>
+ inline void apply(Item const& outer, Item const& inner, bool first = true)
+ {
+ if (first && outer.real_area < 0)
+ {
+ // Reverse arguments
+ apply(inner, outer, false);
+ return;
+ }
+
+ if (outer.real_area > 0)
+ {
+ if (inner.real_area < 0 || m_check_for_orientation)
+ {
+ ring_info_type& inner_in_map = m_ring_map[inner.id];
+
+ if (geometry::within(inner_in_map.point, outer.envelope)
+ && within_selected_input(inner_in_map, outer.id, m_geometry1, m_geometry2, m_collection)
+ )
+ {
+ // Only assign parent if that parent is smaller (or if it is the first)
+ if (inner_in_map.parent.source_index == -1
+ || outer.abs_area < inner_in_map.parent_area)
+ {
+ inner_in_map.parent = outer.id;
+ inner_in_map.parent_area = outer.abs_area;
+ }
+ }
+ }
+ }
+ }
+};
+
+
+
+
+template
+<
+ typename Geometry1, typename Geometry2,
+ typename RingCollection,
+ typename RingMap
+>
+inline void assign_parents(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ RingCollection const& collection,
+ RingMap& ring_map,
+ bool check_for_orientation = false)
+{
+ typedef typename geometry::tag<Geometry1>::type tag1;
+ typedef typename geometry::tag<Geometry2>::type tag2;
+
+ typedef typename RingMap::mapped_type ring_info_type;
+ typedef typename ring_info_type::point_type point_type;
+ typedef model::box<point_type> box_type;
+
+ typedef typename RingMap::iterator map_iterator_type;
+
+ {
+ typedef ring_info_helper<point_type> helper;
+ typedef std::vector<helper> vector_type;
+ typedef typename boost::range_iterator<vector_type const>::type vector_iterator_type;
+
+#ifdef BOOST_GEOMETRY_TIME_OVERLAY
+ boost::timer timer;
+#endif
+
+
+ std::size_t count_total = ring_map.size();
+ std::size_t count_positive = 0;
+ std::size_t index_positive = 0; // only used if count_positive>0
+ std::size_t index = 0;
+
+ // Copy to vector (with new approach this might be obsolete as well, using the map directly)
+ vector_type vector(count_total);
+
+ for (map_iterator_type it = boost::begin(ring_map);
+ it != boost::end(ring_map); ++it, ++index)
+ {
+ vector[index] = helper(it->first, it->second.get_area());
+ helper& item = vector[index];
+ switch(it->first.source_index)
+ {
+ case 0 :
+ geometry::envelope(get_ring<tag1>::apply(it->first, geometry1),
+ item.envelope);
+ break;
+ case 1 :
+ geometry::envelope(get_ring<tag2>::apply(it->first, geometry2),
+ item.envelope);
+ break;
+ case 2 :
+ geometry::envelope(get_ring<void>::apply(it->first, collection),
+ item.envelope);
+ break;
+ }
+ if (item.real_area > 0)
+ {
+ count_positive++;
+ index_positive = index;
+ }
+ }
+
+#ifdef BOOST_GEOMETRY_TIME_OVERLAY
+ std::cout << " ap: created helper vector: " << timer.elapsed() << std::endl;
+#endif
+
+ if (! check_for_orientation)
+ {
+ if (count_positive == count_total)
+ {
+ // Optimization for only positive rings
+ // -> no assignment of parents or reversal necessary, ready here.
+ return;
+ }
+
+ if (count_positive == 1)
+ {
+ // Optimization for one outer ring
+ // -> assign this as parent to all others (all interior rings)
+ // In unions, this is probably the most occuring case and gives
+ // a dramatic improvement (factor 5 for star_comb testcase)
+ ring_identifier id_of_positive = vector[index_positive].id;
+ ring_info_type& outer = ring_map[id_of_positive];
+ std::size_t index = 0;
+ for (vector_iterator_type it = boost::begin(vector);
+ it != boost::end(vector); ++it, ++index)
+ {
+ if (index != index_positive)
+ {
+ ring_info_type& inner = ring_map[it->id];
+ inner.parent = id_of_positive;
+ outer.children.push_back(it->id);
+ }
+ }
+ return;
+ }
+ }
+
+ assign_visitor
+ <
+ Geometry1, Geometry2,
+ RingCollection, RingMap
+ > visitor(geometry1, geometry2, collection, ring_map, check_for_orientation);
+
+ geometry::partition
+ <
+ box_type, ring_info_helper_get_box, ring_info_helper_ovelaps_box
+ >::apply(vector, visitor);
+
+#ifdef BOOST_GEOMETRY_TIME_OVERLAY
+ std::cout << " ap: quadradic loop: " << timer.elapsed() << std::endl;
+ std::cout << " ap: check_for_orientation " << check_for_orientation << std::endl;
+#endif
+ }
+
+ if (check_for_orientation)
+ {
+ for (map_iterator_type it = boost::begin(ring_map);
+ it != boost::end(ring_map); ++it)
+ {
+ if (geometry::math::equals(it->second.get_area(), 0))
+ {
+ it->second.discarded = true;
+ }
+ else if (it->second.parent.source_index >= 0 && it->second.get_area() > 0)
+ {
+ // Discard positive inner ring with parent
+ it->second.discarded = true;
+ it->second.parent.source_index = -1;
+ }
+ else if (it->second.parent.source_index < 0 && it->second.get_area() < 0)
+ {
+ // Reverse negative ring without parent
+ it->second.reversed = true;
+ }
+ }
+ }
+
+ // Assign childlist
+ for (map_iterator_type it = boost::begin(ring_map);
+ it != boost::end(ring_map); ++it)
+ {
+ if (it->second.parent.source_index >= 0)
+ {
+ ring_map[it->second.parent].children.push_back(it->first);
+ }
+ }
+}
+
+template
+<
+ typename Geometry,
+ typename RingCollection,
+ typename RingMap
+>
+inline void assign_parents(Geometry const& geometry,
+ RingCollection const& collection,
+ RingMap& ring_map)
+{
+ // Call it with an empty geometry
+ // (ring_map should be empty for source_id==1)
+
+ Geometry empty;
+ assign_parents(geometry, empty, collection, ring_map, true);
+}
+
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ASSIGN_PARENTS_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp b/boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp
new file mode 100644
index 0000000000..012b3aca30
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp
@@ -0,0 +1,170 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_BACKTRACK_CHECK_SI_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_BACKTRACK_CHECK_SI_HPP
+
+#include <cstddef>
+#include <string>
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+#include <boost/geometry/algorithms/detail/has_self_intersections.hpp>
+#if defined(BOOST_GEOMETRY_DEBUG_INTERSECTION) || defined(BOOST_GEOMETRY_OVERLAY_REPORT_WKT)
+# include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
+# include <boost/geometry/io/wkt/wkt.hpp>
+#endif
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+template <typename Turns>
+inline void clear_visit_info(Turns& turns)
+{
+ typedef typename boost::range_value<Turns>::type tp_type;
+
+ for (typename boost::range_iterator<Turns>::type
+ it = boost::begin(turns);
+ it != boost::end(turns);
+ ++it)
+ {
+ for (typename boost::range_iterator
+ <
+ typename tp_type::container_type
+ >::type op_it = boost::begin(it->operations);
+ op_it != boost::end(it->operations);
+ ++op_it)
+ {
+ op_it->visited.clear();
+ }
+ it->discarded = false;
+ }
+}
+
+struct backtrack_state
+{
+ bool m_good;
+
+ inline backtrack_state() : m_good(true) {}
+ inline void reset() { m_good = true; }
+ inline bool good() const { return m_good; }
+};
+
+
+template
+<
+ typename Geometry1,
+ typename Geometry2
+>
+class backtrack_check_self_intersections
+{
+ struct state : public backtrack_state
+ {
+ bool m_checked;
+ inline state()
+ : m_checked()
+ {}
+ };
+public :
+ typedef state state_type;
+
+ template <typename Operation, typename Rings, typename Turns>
+ static inline void apply(std::size_t size_at_start,
+ Rings& rings, typename boost::range_value<Rings>::type& ring,
+ Turns& turns, Operation& operation,
+ std::string const& ,
+ Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ state_type& state
+ )
+ {
+ state.m_good = false;
+
+ // Check self-intersections and throw exception if appropriate
+ if (! state.m_checked)
+ {
+ state.m_checked = true;
+ has_self_intersections(geometry1);
+ has_self_intersections(geometry2);
+ }
+
+ // Make bad output clean
+ rings.resize(size_at_start);
+ ring.clear();
+
+ // Reject this as a starting point
+ operation.visited.set_rejected();
+
+ // And clear all visit info
+ clear_visit_info(turns);
+ }
+};
+
+#ifdef BOOST_GEOMETRY_OVERLAY_REPORT_WKT
+template
+<
+ typename Geometry1,
+ typename Geometry2
+>
+class backtrack_debug
+{
+public :
+ typedef backtrack_state state_type;
+
+ template <typename Operation, typename Rings, typename Turns>
+ static inline void apply(std::size_t size_at_start,
+ Rings& rings, typename boost::range_value<Rings>::type& ring,
+ Turns& turns, Operation& operation,
+ std::string const& reason,
+ Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ state_type& state
+ )
+ {
+ std::cout << " REJECT " << reason << std::endl;
+
+ state.m_good = false;
+
+ rings.resize(size_at_start);
+ ring.clear();
+ operation.visited.set_rejected();
+ clear_visit_info(turns);
+
+ int c = 0;
+ for (int i = 0; i < turns.size(); i++)
+ {
+ for (int j = 0; j < 2; j++)
+ {
+ if (turns[i].operations[j].visited.rejected())
+ {
+ c++;
+ }
+ }
+ }
+ std::cout << "BACKTRACK (" << reason << " )"
+ << " " << c << " of " << turns.size() << " rejected"
+ << std::endl;
+ std::cout
+ << geometry::wkt(geometry1) << std::endl
+ << geometry::wkt(geometry2) << std::endl;
+ }
+};
+#endif // BOOST_GEOMETRY_OVERLAY_REPORT_WKT
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_BACKTRACK_CHECK_SI_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp b/boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp
new file mode 100644
index 0000000000..3e6a8897f5
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp
@@ -0,0 +1,55 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CALCULATE_DISTANCE_POLICY_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CALCULATE_DISTANCE_POLICY_HPP
+
+
+#include <boost/geometry/algorithms/comparable_distance.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+
+/*!
+ \brief Policy calculating distance
+ \details get_turn_info has an optional policy to get some
+ extra information.
+ This policy calculates the distance (using default distance strategy)
+ */
+struct calculate_distance_policy
+{
+ static bool const include_no_turn = false;
+ static bool const include_degenerate = false;
+
+ template <typename Point1, typename Point2, typename Info>
+ static inline void apply(Info& info, Point1 const& p1, Point2 const& p2)
+ {
+ info.operations[0].enriched.distance
+ = geometry::comparable_distance(info.point, p1);
+ info.operations[1].enriched.distance
+ = geometry::comparable_distance(info.point, p2);
+ }
+
+};
+
+
+}} // namespace detail::overlay
+#endif //DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CALCULATE_DISTANCE_POLICY_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/check_enrich.hpp b/boost/geometry/algorithms/detail/overlay/check_enrich.hpp
new file mode 100644
index 0000000000..b210fd04b1
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/check_enrich.hpp
@@ -0,0 +1,172 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CHECK_ENRICH_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CHECK_ENRICH_HPP
+
+
+#include <cstddef>
+
+
+#include <boost/assert.hpp>
+#include <boost/range.hpp>
+
+
+
+#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+
+template<typename Turn>
+struct meta_turn
+{
+ int index;
+ Turn const* turn;
+ bool handled[2];
+
+ inline meta_turn(int i, Turn const& t)
+ : index(i), turn(&t)
+ {
+ handled[0] = false;
+ handled[1] = false;
+ }
+};
+
+
+template <typename MetaTurn>
+inline void display(MetaTurn const& meta_turn, std::string const& reason = "")
+{
+#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
+ std::cout << meta_turn.index
+ << "\tMethods: " << method_char(meta_turn.turn->method)
+ << " operations: " << operation_char(meta_turn.turn->operations[0].operation)
+ << operation_char(meta_turn.turn->operations[1].operation)
+ << " travels to " << meta_turn.turn->operations[0].enriched.travels_to_ip_index
+ << " and " << meta_turn.turn->operations[1].enriched.travels_to_ip_index
+ //<< " -> " << op_index
+ << " " << reason
+ << std::endl;
+#endif
+}
+
+
+template <typename MetaTurns, typename MetaTurn>
+inline void check_detailed(MetaTurns& meta_turns, MetaTurn const& meta_turn,
+ int op_index, int cycle, int start, operation_type for_operation,
+ bool& error)
+{
+ display(meta_turn);
+ int const ip_index = meta_turn.turn->operations[op_index].enriched.travels_to_ip_index;
+ if (ip_index >= 0)
+ {
+ bool found = false;
+
+ if (ip_index == start)
+ {
+ display(meta_turns[ip_index], " FINISH");
+ return;
+ }
+
+ // check on continuing, or on same-operation-on-same-geometry
+ if (! meta_turns[ip_index].handled[op_index]
+ && (meta_turns[ip_index].turn->operations[op_index].operation == operation_continue
+ || meta_turns[ip_index].turn->operations[op_index].operation == for_operation)
+ )
+ {
+ meta_turns[ip_index].handled[op_index] = true;
+ check_detailed(meta_turns, meta_turns[ip_index], op_index, cycle, start, for_operation, error);
+ found = true;
+ }
+ // check on other geometry
+ if (! found)
+ {
+ int const other_index = 1 - op_index;
+ if (! meta_turns[ip_index].handled[other_index]
+ && meta_turns[ip_index].turn->operations[other_index].operation == for_operation)
+ {
+ meta_turns[ip_index].handled[other_index] = true;
+ check_detailed(meta_turns, meta_turns[ip_index], other_index, cycle, start, for_operation, error);
+ found = true;
+ }
+ }
+
+ if (! found)
+ {
+ display(meta_turns[ip_index], " STOP");
+ error = true;
+#ifndef BOOST_GEOMETRY_DEBUG_ENRICH
+ //std::cout << " STOP";
+#endif
+ }
+ }
+}
+
+
+template <typename TurnPoints>
+inline bool check_graph(TurnPoints& turn_points, operation_type for_operation)
+{
+ typedef typename boost::range_value<TurnPoints>::type turn_point_type;
+
+ bool error = false;
+ int index = 0;
+
+ std::vector<meta_turn<turn_point_type> > meta_turns;
+ for (typename boost::range_iterator<TurnPoints const>::type
+ it = boost::begin(turn_points);
+ it != boost::end(turn_points);
+ ++it, ++index)
+ {
+ meta_turns.push_back(meta_turn<turn_point_type>(index, *it));
+ }
+
+ int cycle = 0;
+ for (typename boost::range_iterator<std::vector<meta_turn<turn_point_type> > > ::type
+ it = boost::begin(meta_turns);
+ it != boost::end(meta_turns);
+ ++it)
+ {
+ if (! (it->turn->blocked() || it->turn->is_discarded()))
+ {
+ for (int i = 0 ; i < 2; i++)
+ {
+ if (! it->handled[i]
+ && it->turn->operations[i].operation == for_operation)
+ {
+#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
+ std::cout << "CYCLE " << cycle << std::endl;
+#endif
+ it->handled[i] = true;
+ check_detailed(meta_turns, *it, i, cycle++, it->index, for_operation, error);
+#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
+ std::cout <<" END CYCLE " << it->index << std::endl;
+#endif
+ }
+ }
+ }
+ }
+ return error;
+}
+
+
+
+}} // namespace detail::overlay
+#endif //DOXYGEN_NO_DETAIL
+
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CHECK_ENRICH_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/clip_linestring.hpp b/boost/geometry/algorithms/detail/overlay/clip_linestring.hpp
new file mode 100644
index 0000000000..fc4f657322
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/clip_linestring.hpp
@@ -0,0 +1,242 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CLIP_LINESTRING_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CLIP_LINESTRING_HPP
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/algorithms/clear.hpp>
+#include <boost/geometry/algorithms/convert.hpp>
+
+#include <boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp>
+
+#include <boost/geometry/util/select_coordinate_type.hpp>
+#include <boost/geometry/geometries/segment.hpp>
+
+namespace boost { namespace geometry
+{
+
+namespace strategy { namespace intersection
+{
+
+/*!
+ \brief Strategy: line clipping algorithm after Liang Barsky
+ \ingroup overlay
+ \details The Liang-Barsky line clipping algorithm clips a line with a clipping box.
+ It is slightly adapted in the sense that it returns which points are clipped
+ \tparam B input box type of clipping box
+ \tparam P input/output point-type of segments to be clipped
+ \note The algorithm is currently only implemented for 2D Cartesian points
+ \note Though it is implemented in namespace strategy, and theoretically another
+ strategy could be used, it is not (yet) updated to the general strategy concepts,
+ and not (yet) splitted into a file in folder strategies
+ \author Barend Gehrels, and the following recourses
+ - A tutorial: http://www.skytopia.com/project/articles/compsci/clipping.html
+ - a German applet (link broken): http://ls7-www.cs.uni-dortmund.de/students/projectgroups/acit/lineclip.shtml
+*/
+template<typename Box, typename Point>
+class liang_barsky
+{
+private:
+ typedef model::referring_segment<Point> segment_type;
+
+ template <typename T>
+ inline bool check_edge(T const& p, T const& q, T& t1, T& t2) const
+ {
+ bool visible = true;
+
+ if(p < 0)
+ {
+ T const r = q / p;
+ if (r > t2)
+ visible = false;
+ else if (r > t1)
+ t1 = r;
+ }
+ else if(p > 0)
+ {
+ T const r = q / p;
+ if (r < t1)
+ visible = false;
+ else if (r < t2)
+ t2 = r;
+ }
+ else
+ {
+ if (q < 0)
+ visible = false;
+ }
+
+ return visible;
+ }
+
+public:
+
+ inline bool clip_segment(Box const& b, segment_type& s, bool& sp1_clipped, bool& sp2_clipped) const
+ {
+ typedef typename select_coordinate_type<Box, Point>::type coordinate_type;
+
+ coordinate_type t1 = 0;
+ coordinate_type t2 = 1;
+
+ coordinate_type const dx = get<1, 0>(s) - get<0, 0>(s);
+ coordinate_type const dy = get<1, 1>(s) - get<0, 1>(s);
+
+ coordinate_type const p1 = -dx;
+ coordinate_type const p2 = dx;
+ coordinate_type const p3 = -dy;
+ coordinate_type const p4 = dy;
+
+ coordinate_type const q1 = get<0, 0>(s) - get<min_corner, 0>(b);
+ coordinate_type const q2 = get<max_corner, 0>(b) - get<0, 0>(s);
+ coordinate_type const q3 = get<0, 1>(s) - get<min_corner, 1>(b);
+ coordinate_type const q4 = get<max_corner, 1>(b) - get<0, 1>(s);
+
+ if (check_edge(p1, q1, t1, t2) // left
+ && check_edge(p2, q2, t1, t2) // right
+ && check_edge(p3, q3, t1, t2) // bottom
+ && check_edge(p4, q4, t1, t2)) // top
+ {
+ sp1_clipped = t1 > 0;
+ sp2_clipped = t2 < 1;
+
+ if (sp2_clipped)
+ {
+ set<1, 0>(s, get<0, 0>(s) + t2 * dx);
+ set<1, 1>(s, get<0, 1>(s) + t2 * dy);
+ }
+
+ if(sp1_clipped)
+ {
+ set<0, 0>(s, get<0, 0>(s) + t1 * dx);
+ set<0, 1>(s, get<0, 1>(s) + t1 * dy);
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ template<typename Linestring, typename OutputIterator>
+ inline void apply(Linestring& line_out, OutputIterator out) const
+ {
+ if (!boost::empty(line_out))
+ {
+ *out = line_out;
+ ++out;
+ geometry::clear(line_out);
+ }
+ }
+};
+
+
+}} // namespace strategy::intersection
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace intersection
+{
+
+/*!
+ \brief Clips a linestring with a box
+ \details A linestring is intersected (clipped) by the specified box
+ and the resulting linestring, or pieces of linestrings, are sent to the specified output operator.
+ \tparam OutputLinestring type of the output linestrings
+ \tparam OutputIterator an output iterator which outputs linestrings
+ \tparam Linestring linestring-type, for example a vector of points, matching the output-iterator type,
+ the points should also match the input-iterator type
+ \tparam Box box type
+ \tparam Strategy strategy, a clipping strategy which should implement the methods "clip_segment" and "apply"
+*/
+template
+<
+ typename OutputLinestring,
+ typename OutputIterator,
+ typename Range,
+ typename Box,
+ typename Strategy
+>
+OutputIterator clip_range_with_box(Box const& b, Range const& range,
+ OutputIterator out, Strategy const& strategy)
+{
+ if (boost::begin(range) == boost::end(range))
+ {
+ return out;
+ }
+
+ typedef typename point_type<OutputLinestring>::type point_type;
+
+ OutputLinestring line_out;
+
+ typedef typename boost::range_iterator<Range const>::type iterator_type;
+ iterator_type vertex = boost::begin(range);
+ for(iterator_type previous = vertex++;
+ vertex != boost::end(range);
+ ++previous, ++vertex)
+ {
+ point_type p1, p2;
+ geometry::convert(*previous, p1);
+ geometry::convert(*vertex, p2);
+
+ // Clip the segment. Five situations:
+ // 1. Segment is invisible, finish line if any (shouldn't occur)
+ // 2. Segment is completely visible. Add (p1)-p2 to line
+ // 3. Point 1 is invisible (clipped), point 2 is visible. Start new line from p1-p2...
+ // 4. Point 1 is visible, point 2 is invisible (clipped). End the line with ...p2
+ // 5. Point 1 and point 2 are both invisible (clipped). Start/finish an independant line p1-p2
+ //
+ // This results in:
+ // a. if p1 is clipped, start new line
+ // b. if segment is partly or completely visible, add the segment
+ // c. if p2 is clipped, end the line
+
+ bool c1 = false;
+ bool c2 = false;
+ model::referring_segment<point_type> s(p1, p2);
+
+ if (!strategy.clip_segment(b, s, c1, c2))
+ {
+ strategy.apply(line_out, out);
+ }
+ else
+ {
+ // a. If necessary, finish the line and add a start a new one
+ if (c1)
+ {
+ strategy.apply(line_out, out);
+ }
+
+ // b. Add p1 only if it is the first point, then add p2
+ if (boost::empty(line_out))
+ {
+ detail::overlay::append_no_duplicates(line_out, p1, true);
+ }
+ detail::overlay::append_no_duplicates(line_out, p2);
+
+ // c. If c2 is clipped, finish the line
+ if (c2)
+ {
+ strategy.apply(line_out, out);
+ }
+ }
+
+ }
+
+ // Add last part
+ strategy.apply(line_out, out);
+ return out;
+}
+
+}} // namespace detail::intersection
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CLIP_LINESTRING_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/convert_ring.hpp b/boost/geometry/algorithms/detail/overlay/convert_ring.hpp
new file mode 100644
index 0000000000..05bd721e7f
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/convert_ring.hpp
@@ -0,0 +1,99 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CONVERT_RING_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CONVERT_RING_HPP
+
+
+#include <boost/mpl/assert.hpp>
+#include <boost/range.hpp>
+#include <boost/range/algorithm/reverse.hpp>
+
+#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/core/exterior_ring.hpp>
+#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
+
+#include <boost/geometry/algorithms/convert.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+
+template<typename Tag>
+struct convert_ring
+{
+ BOOST_MPL_ASSERT_MSG
+ (
+ false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TAG
+ , (types<Tag>)
+ );
+};
+
+template<>
+struct convert_ring<ring_tag>
+{
+ template<typename Destination, typename Source>
+ static inline void apply(Destination& destination, Source const& source,
+ bool append, bool reverse)
+ {
+ if (! append)
+ {
+ geometry::convert(source, destination);
+ if (reverse)
+ {
+ boost::reverse(destination);
+ }
+ }
+ }
+};
+
+
+template<>
+struct convert_ring<polygon_tag>
+{
+ template<typename Destination, typename Source>
+ static inline void apply(Destination& destination, Source const& source,
+ bool append, bool reverse)
+ {
+ if (! append)
+ {
+ geometry::convert(source, exterior_ring(destination));
+ if (reverse)
+ {
+ boost::reverse(exterior_ring(destination));
+ }
+ }
+ else
+ {
+ interior_rings(destination).resize(
+ interior_rings(destination).size() + 1);
+ geometry::convert(source, interior_rings(destination).back());
+ if (reverse)
+ {
+ boost::reverse(interior_rings(destination).back());
+ }
+ }
+ }
+};
+
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CONVERT_RING_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp b/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp
new file mode 100644
index 0000000000..379444428f
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp
@@ -0,0 +1,295 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENT_POINT_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENT_POINT_HPP
+
+
+#include <boost/array.hpp>
+#include <boost/mpl/assert.hpp>
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/ring_type.hpp>
+#include <boost/geometry/core/exterior_ring.hpp>
+#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/algorithms/convert.hpp>
+#include <boost/geometry/geometries/concepts/check.hpp>
+#include <boost/geometry/views/closeable_view.hpp>
+#include <boost/geometry/views/reversible_view.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace copy_segments
+{
+
+
+template <typename Range, bool Reverse, typename SegmentIdentifier, typename PointOut>
+struct copy_segment_point_range
+{
+ typedef typename closeable_view
+ <
+ Range const,
+ closure<Range>::value
+ >::type cview_type;
+
+ typedef typename reversible_view
+ <
+ cview_type const,
+ Reverse ? iterate_reverse : iterate_forward
+ >::type rview_type;
+
+ static inline bool apply(Range const& range,
+ SegmentIdentifier const& seg_id, bool second,
+ PointOut& point)
+ {
+ int index = seg_id.segment_index;
+ if (second)
+ {
+ index++;
+ if (index >= boost::size(range))
+ {
+ index = 0;
+ }
+ }
+
+ // Exception?
+ if (index >= boost::size(range))
+ {
+ return false;
+ }
+
+ cview_type cview(range);
+ rview_type view(cview);
+
+
+ geometry::convert(*(boost::begin(view) + index), point);
+ return true;
+ }
+};
+
+
+template <typename Polygon, bool Reverse, typename SegmentIdentifier, typename PointOut>
+struct copy_segment_point_polygon
+{
+ static inline bool apply(Polygon const& polygon,
+ SegmentIdentifier const& seg_id, bool second,
+ PointOut& point)
+ {
+ // Call ring-version with the right ring
+ return copy_segment_point_range
+ <
+ typename geometry::ring_type<Polygon>::type,
+ Reverse,
+ SegmentIdentifier,
+ PointOut
+ >::apply
+ (
+ seg_id.ring_index < 0
+ ? geometry::exterior_ring(polygon)
+ : geometry::interior_rings(polygon)[seg_id.ring_index],
+ seg_id, second,
+ point
+ );
+ }
+};
+
+
+template <typename Box, bool Reverse, typename SegmentIdentifier, typename PointOut>
+struct copy_segment_point_box
+{
+ static inline bool apply(Box const& box,
+ SegmentIdentifier const& seg_id, bool second,
+ PointOut& point)
+ {
+ int index = seg_id.segment_index;
+ if (second)
+ {
+ index++;
+ }
+
+ boost::array<typename point_type<Box>::type, 4> bp;
+ assign_box_corners_oriented<Reverse>(box, bp);
+ point = bp[index % 4];
+ return true;
+ }
+};
+
+
+
+
+}} // namespace detail::copy_segments
+#endif // DOXYGEN_NO_DETAIL
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template
+<
+ typename Tag,
+ typename GeometryIn,
+ bool Reverse,
+ typename SegmentIdentifier,
+ typename PointOut
+>
+struct copy_segment_point
+{
+ BOOST_MPL_ASSERT_MSG
+ (
+ false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
+ , (types<GeometryIn>)
+ );
+};
+
+
+template <typename LineString, bool Reverse, typename SegmentIdentifier, typename PointOut>
+struct copy_segment_point<linestring_tag, LineString, Reverse, SegmentIdentifier, PointOut>
+ : detail::copy_segments::copy_segment_point_range
+ <
+ LineString, Reverse, SegmentIdentifier, PointOut
+ >
+{};
+
+
+template <typename Ring, bool Reverse, typename SegmentIdentifier, typename PointOut>
+struct copy_segment_point<ring_tag, Ring, Reverse, SegmentIdentifier, PointOut>
+ : detail::copy_segments::copy_segment_point_range
+ <
+ Ring, Reverse, SegmentIdentifier, PointOut
+ >
+{};
+
+template <typename Polygon, bool Reverse, typename SegmentIdentifier, typename PointOut>
+struct copy_segment_point<polygon_tag, Polygon, Reverse, SegmentIdentifier, PointOut>
+ : detail::copy_segments::copy_segment_point_polygon
+ <
+ Polygon, Reverse, SegmentIdentifier, PointOut
+ >
+{};
+
+
+template <typename Box, bool Reverse, typename SegmentIdentifier, typename PointOut>
+struct copy_segment_point<box_tag, Box, Reverse, SegmentIdentifier, PointOut>
+ : detail::copy_segments::copy_segment_point_box
+ <
+ Box, Reverse, SegmentIdentifier, PointOut
+ >
+{};
+
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+
+
+
+/*!
+ \brief Helper function, copies a point from a segment
+ \ingroup overlay
+ */
+template<bool Reverse, typename Geometry, typename SegmentIdentifier, typename PointOut>
+inline bool copy_segment_point(Geometry const& geometry,
+ SegmentIdentifier const& seg_id, bool second,
+ PointOut& point_out)
+{
+ concept::check<Geometry const>();
+
+ return dispatch::copy_segment_point
+ <
+ typename tag<Geometry>::type,
+ Geometry,
+ Reverse,
+ SegmentIdentifier,
+ PointOut
+ >::apply(geometry, seg_id, second, point_out);
+}
+
+
+/*!
+ \brief Helper function, to avoid the same construct several times,
+ copies a point, based on a source-index and two geometries
+ \ingroup overlay
+ */
+template
+<
+ bool Reverse1, bool Reverse2,
+ typename Geometry1, typename Geometry2,
+ typename SegmentIdentifier,
+ typename PointOut
+>
+inline bool copy_segment_point(Geometry1 const& geometry1, Geometry2 const& geometry2,
+ SegmentIdentifier const& seg_id, bool second,
+ PointOut& point_out)
+{
+ concept::check<Geometry1 const>();
+ concept::check<Geometry2 const>();
+
+ if (seg_id.source_index == 0)
+ {
+ return dispatch::copy_segment_point
+ <
+ typename tag<Geometry1>::type,
+ Geometry1,
+ Reverse1,
+ SegmentIdentifier,
+ PointOut
+ >::apply(geometry1, seg_id, second, point_out);
+ }
+ else if (seg_id.source_index == 1)
+ {
+ return dispatch::copy_segment_point
+ <
+ typename tag<Geometry2>::type,
+ Geometry2,
+ Reverse2,
+ SegmentIdentifier,
+ PointOut
+ >::apply(geometry2, seg_id, second, point_out);
+ }
+ // Exception?
+ return false;
+}
+
+
+/*!
+ \brief Helper function, to avoid the same construct several times,
+ copies a point, based on a source-index and two geometries
+ \ingroup overlay
+ */
+template
+<
+ bool Reverse1, bool Reverse2,
+ typename Geometry1, typename Geometry2,
+ typename SegmentIdentifier,
+ typename PointOut
+>
+inline bool copy_segment_points(Geometry1 const& geometry1, Geometry2 const& geometry2,
+ SegmentIdentifier const& seg_id,
+ PointOut& point1, PointOut& point2)
+{
+ concept::check<Geometry1 const>();
+ concept::check<Geometry2 const>();
+
+ return copy_segment_point<Reverse1, Reverse2>(geometry1, geometry2, seg_id, false, point1)
+ && copy_segment_point<Reverse1, Reverse2>(geometry1, geometry2, seg_id, true, point2);
+}
+
+
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENT_POINT_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/copy_segments.hpp b/boost/geometry/algorithms/detail/overlay/copy_segments.hpp
new file mode 100644
index 0000000000..b0183a3ac2
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/copy_segments.hpp
@@ -0,0 +1,328 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENTS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENTS_HPP
+
+
+#include <boost/array.hpp>
+#include <boost/mpl/assert.hpp>
+#include <vector>
+
+#include <boost/assert.hpp>
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/core/ring_type.hpp>
+#include <boost/geometry/core/exterior_ring.hpp>
+#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/geometries/concepts/check.hpp>
+#include <boost/geometry/iterators/ever_circling_iterator.hpp>
+#include <boost/geometry/views/closeable_view.hpp>
+#include <boost/geometry/views/reversible_view.hpp>
+
+#include <boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp>
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace copy_segments
+{
+
+
+template
+<
+ typename Ring,
+ bool Reverse,
+ typename SegmentIdentifier,
+ typename RangeOut
+>
+struct copy_segments_ring
+{
+ typedef typename closeable_view
+ <
+ Ring const,
+ closure<Ring>::value
+ >::type cview_type;
+
+ typedef typename reversible_view
+ <
+ cview_type const,
+ Reverse ? iterate_reverse : iterate_forward
+ >::type rview_type;
+
+ typedef typename boost::range_iterator<rview_type const>::type iterator;
+ typedef geometry::ever_circling_iterator<iterator> ec_iterator;
+
+ static inline void apply(Ring const& ring,
+ SegmentIdentifier const& seg_id, int to_index,
+ RangeOut& current_output)
+ {
+ cview_type cview(ring);
+ rview_type view(cview);
+
+ // The problem: sometimes we want to from "3" to "2"
+ // -> end = "3" -> end == begin
+ // This is not convenient with iterators.
+
+ // So we use the ever-circling iterator and determine when to step out
+
+ int const from_index = seg_id.segment_index + 1;
+
+ // Sanity check
+ BOOST_ASSERT(from_index < boost::size(view));
+
+ ec_iterator it(boost::begin(view), boost::end(view),
+ boost::begin(view) + from_index);
+
+ // [2..4] -> 4 - 2 + 1 = 3 -> {2,3,4} -> OK
+ // [4..2],size=6 -> 6 - 4 + 2 + 1 = 5 -> {4,5,0,1,2} -> OK
+ // [1..1], travel the whole ring round
+ typedef typename boost::range_difference<Ring>::type size_type;
+ size_type const count = from_index <= to_index
+ ? to_index - from_index + 1
+ : boost::size(view) - from_index + to_index + 1;
+
+ for (size_type i = 0; i < count; ++i, ++it)
+ {
+ detail::overlay::append_no_duplicates(current_output, *it);
+ }
+ }
+};
+
+template
+<
+ typename LineString,
+ bool Reverse,
+ typename SegmentIdentifier,
+ typename RangeOut
+>
+struct copy_segments_linestring
+{
+
+ typedef typename boost::range_iterator<LineString const>::type iterator;
+
+ static inline void apply(LineString const& ls,
+ SegmentIdentifier const& seg_id, int to_index,
+ RangeOut& current_output)
+ {
+ int const from_index = seg_id.segment_index + 1;
+
+ // Sanity check
+ if (from_index > to_index || from_index < 0 || to_index >= boost::size(ls))
+ {
+ return;
+ }
+
+ typedef typename boost::range_difference<LineString>::type size_type;
+ size_type const count = to_index - from_index + 1;
+
+ typename boost::range_iterator<LineString const>::type it = boost::begin(ls) + from_index;
+
+ for (size_type i = 0; i < count; ++i, ++it)
+ {
+ detail::overlay::append_no_duplicates(current_output, *it);
+ }
+ }
+};
+
+template
+<
+ typename Polygon,
+ bool Reverse,
+ typename SegmentIdentifier,
+ typename RangeOut
+>
+struct copy_segments_polygon
+{
+ static inline void apply(Polygon const& polygon,
+ SegmentIdentifier const& seg_id, int to_index,
+ RangeOut& current_output)
+ {
+ // Call ring-version with the right ring
+ copy_segments_ring
+ <
+ typename geometry::ring_type<Polygon>::type,
+ Reverse,
+ SegmentIdentifier,
+ RangeOut
+ >::apply
+ (
+ seg_id.ring_index < 0
+ ? geometry::exterior_ring(polygon)
+ : geometry::interior_rings(polygon)[seg_id.ring_index],
+ seg_id, to_index,
+ current_output
+ );
+ }
+};
+
+
+template
+<
+ typename Box,
+ bool Reverse,
+ typename SegmentIdentifier,
+ typename RangeOut
+>
+struct copy_segments_box
+{
+ static inline void apply(Box const& box,
+ SegmentIdentifier const& seg_id, int to_index,
+ RangeOut& current_output)
+ {
+ int index = seg_id.segment_index + 1;
+ BOOST_ASSERT(index < 5);
+
+ int const count = index <= to_index
+ ? to_index - index + 1
+ : 5 - index + to_index + 1;
+
+ // Create array of points, the fifth one closes it
+ boost::array<typename point_type<Box>::type, 5> bp;
+ assign_box_corners_oriented<Reverse>(box, bp);
+ bp[4] = bp[0];
+
+ // (possibly cyclic) copy to output
+ // (see comments in ring-version)
+ for (int i = 0; i < count; i++, index++)
+ {
+ detail::overlay::append_no_duplicates(current_output, bp[index % 5]);
+
+ }
+ }
+};
+
+
+}} // namespace detail::copy_segments
+#endif // DOXYGEN_NO_DETAIL
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+template
+<
+ typename Tag,
+ typename GeometryIn,
+ bool Reverse,
+ typename SegmentIdentifier,
+ typename RangeOut
+>
+struct copy_segments
+{
+ BOOST_MPL_ASSERT_MSG
+ (
+ false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
+ , (types<GeometryIn>)
+ );
+};
+
+
+template
+<
+ typename Ring,
+ bool Reverse,
+ typename SegmentIdentifier,
+ typename RangeOut
+>
+struct copy_segments<ring_tag, Ring, Reverse, SegmentIdentifier, RangeOut>
+ : detail::copy_segments::copy_segments_ring
+ <
+ Ring, Reverse, SegmentIdentifier, RangeOut
+ >
+{};
+
+
+
+template
+<
+ typename LineString,
+ bool Reverse,
+ typename SegmentIdentifier,
+ typename RangeOut
+>
+struct copy_segments<linestring_tag, LineString, Reverse, SegmentIdentifier, RangeOut>
+ : detail::copy_segments::copy_segments_linestring
+ <
+ LineString, Reverse, SegmentIdentifier, RangeOut
+ >
+{};
+
+template
+<
+ typename Polygon,
+ bool Reverse,
+ typename SegmentIdentifier,
+ typename RangeOut
+>
+struct copy_segments<polygon_tag, Polygon, Reverse, SegmentIdentifier, RangeOut>
+ : detail::copy_segments::copy_segments_polygon
+ <
+ Polygon, Reverse, SegmentIdentifier, RangeOut
+ >
+{};
+
+
+template
+<
+ typename Box,
+ bool Reverse,
+ typename SegmentIdentifier,
+ typename RangeOut
+>
+struct copy_segments<box_tag, Box, Reverse, SegmentIdentifier, RangeOut>
+ : detail::copy_segments::copy_segments_box
+ <
+ Box, Reverse, SegmentIdentifier, RangeOut
+ >
+{};
+
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+/*!
+ \brief Copy segments from a geometry, starting with the specified segment (seg_id)
+ until the specified index (to_index)
+ \ingroup overlay
+ */
+template
+<
+ bool Reverse,
+ typename Geometry,
+ typename SegmentIdentifier,
+ typename RangeOut
+>
+inline void copy_segments(Geometry const& geometry,
+ SegmentIdentifier const& seg_id, int to_index,
+ RangeOut& range_out)
+{
+ concept::check<Geometry const>();
+
+ dispatch::copy_segments
+ <
+ typename tag<Geometry>::type,
+ Geometry,
+ Reverse,
+ SegmentIdentifier,
+ RangeOut
+ >::apply(geometry, seg_id, to_index, range_out);
+}
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_COPY_SEGMENTS_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp b/boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp
new file mode 100644
index 0000000000..0bec816946
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp
@@ -0,0 +1,64 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_DEBUG_TURN_INFO_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_DEBUG_TURN_INFO_HPP
+
+#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/visit_info.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+inline char method_char(detail::overlay::method_type const& method)
+{
+ using namespace detail::overlay;
+ switch(method)
+ {
+ case method_none : return '-';
+ case method_disjoint : return 'd';
+ case method_crosses : return 'i';
+ case method_touch : return 't';
+ case method_touch_interior : return 'm';
+ case method_collinear : return 'c';
+ case method_equal : return 'e';
+ default : return '?';
+ }
+}
+
+inline char operation_char(detail::overlay::operation_type const& operation)
+{
+ using namespace detail::overlay;
+ switch(operation)
+ {
+ case operation_none : return '-';
+ case operation_union : return 'u';
+ case operation_intersection : return 'i';
+ case operation_blocked : return 'x';
+ case operation_continue : return 'c';
+ default : return '?';
+ }
+}
+
+inline char visited_char(detail::overlay::visit_info const& v)
+{
+ if (v.rejected()) return 'R';
+ if (v.started()) return 's';
+ if (v.visited()) return 'v';
+ if (v.none()) return '-';
+ if (v.finished()) return 'f';
+ return '?';
+}
+
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_DEBUG_TURN_INFO_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp b/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp
new file mode 100644
index 0000000000..e4842d35f1
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp
@@ -0,0 +1,523 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ENRICH_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ENRICH_HPP
+
+#include <cstddef>
+#include <algorithm>
+#include <map>
+#include <set>
+#include <vector>
+
+#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
+# include <iostream>
+# include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
+# include <boost/geometry/io/wkt/wkt.hpp>
+# define BOOST_GEOMETRY_DEBUG_IDENTIFIER
+#endif
+
+#include <boost/assert.hpp>
+#include <boost/range.hpp>
+
+#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
+#include <boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_relative_order.hpp>
+#include <boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp>
+#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
+# include <boost/geometry/algorithms/detail/overlay/check_enrich.hpp>
+#endif
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+// Wraps "turn_operation" from turn_info.hpp,
+// giving it extra information
+template <typename TurnOperation>
+struct indexed_turn_operation
+{
+ typedef TurnOperation type;
+
+ int index;
+ int operation_index;
+ bool discarded;
+ TurnOperation subject;
+
+ inline indexed_turn_operation(int i, int oi, TurnOperation const& s)
+ : index(i)
+ , operation_index(oi)
+ , discarded(false)
+ , subject(s)
+ {}
+};
+
+template <typename IndexedTurnOperation>
+struct remove_discarded
+{
+ inline bool operator()(IndexedTurnOperation const& operation) const
+ {
+ return operation.discarded;
+ }
+};
+
+
+template
+<
+ typename TurnPoints,
+ typename Indexed,
+ typename Geometry1, typename Geometry2,
+ bool Reverse1, bool Reverse2,
+ typename Strategy
+>
+struct sort_on_segment_and_distance
+{
+ inline sort_on_segment_and_distance(TurnPoints const& turn_points
+ , Geometry1 const& geometry1
+ , Geometry2 const& geometry2
+ , Strategy const& strategy
+ , bool* clustered)
+ : m_turn_points(turn_points)
+ , m_geometry1(geometry1)
+ , m_geometry2(geometry2)
+ , m_strategy(strategy)
+ , m_clustered(clustered)
+ {
+ }
+
+private :
+
+ TurnPoints const& m_turn_points;
+ Geometry1 const& m_geometry1;
+ Geometry2 const& m_geometry2;
+ Strategy const& m_strategy;
+ mutable bool* m_clustered;
+
+ inline bool consider_relative_order(Indexed const& left,
+ Indexed const& right) const
+ {
+ typedef typename geometry::point_type<Geometry1>::type point_type;
+ point_type pi, pj, ri, rj, si, sj;
+
+ geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
+ left.subject.seg_id,
+ pi, pj);
+ geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
+ left.subject.other_id,
+ ri, rj);
+ geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
+ right.subject.other_id,
+ si, sj);
+
+ int const order = get_relative_order
+ <
+ point_type
+ >::apply(pi, pj,ri, rj, si, sj);
+ //debug("r/o", order == -1);
+ return order == -1;
+ }
+
+public :
+
+ // Note that left/right do NOT correspond to m_geometry1/m_geometry2
+ // but to the "indexed_turn_operation"
+ inline bool operator()(Indexed const& left, Indexed const& right) const
+ {
+ segment_identifier const& sl = left.subject.seg_id;
+ segment_identifier const& sr = right.subject.seg_id;
+
+ if (sl == sr
+ && geometry::math::equals(left.subject.enriched.distance
+ , right.subject.enriched.distance))
+ {
+ // Both left and right are located on the SAME segment.
+
+ // First check "real" intersection (crosses)
+ // -> distance zero due to precision, solve it by sorting
+ if (m_turn_points[left.index].method == method_crosses
+ && m_turn_points[right.index].method == method_crosses)
+ {
+ return consider_relative_order(left, right);
+ }
+
+ // If that is not the case, cluster it later on.
+ // Indicate that this is necessary.
+ *m_clustered = true;
+
+ return left.index < right.index;
+ }
+ return sl == sr
+ ? left.subject.enriched.distance < right.subject.enriched.distance
+ : sl < sr;
+
+ }
+};
+
+
+template<typename Turns, typename Operations>
+inline void update_discarded(Turns& turn_points, Operations& operations)
+{
+ // Vice-versa, set discarded to true for discarded operations;
+ // AND set discarded points to true
+ for (typename boost::range_iterator<Operations>::type it = boost::begin(operations);
+ it != boost::end(operations);
+ ++it)
+ {
+ if (turn_points[it->index].discarded)
+ {
+ it->discarded = true;
+ }
+ else if (it->discarded)
+ {
+ turn_points[it->index].discarded = true;
+ }
+ }
+}
+
+
+// Sorts IP-s of this ring on segment-identifier, and if on same segment,
+// on distance.
+// Then assigns for each IP which is the next IP on this segment,
+// plus the vertex-index to travel to, plus the next IP
+// (might be on another segment)
+template
+<
+ typename IndexType,
+ bool Reverse1, bool Reverse2,
+ typename Container,
+ typename TurnPoints,
+ typename Geometry1, typename Geometry2,
+ typename Strategy
+>
+inline void enrich_sort(Container& operations,
+ TurnPoints& turn_points,
+ operation_type for_operation,
+ Geometry1 const& geometry1, Geometry2 const& geometry2,
+ Strategy const& strategy)
+{
+ typedef typename IndexType::type operations_type;
+
+ bool clustered = false;
+ std::sort(boost::begin(operations),
+ boost::end(operations),
+ sort_on_segment_and_distance
+ <
+ TurnPoints,
+ IndexType,
+ Geometry1, Geometry2,
+ Reverse1, Reverse2,
+ Strategy
+ >(turn_points, geometry1, geometry2, strategy, &clustered));
+
+ // DONT'T discard xx / (for union) ix / ii / (for intersection) ux / uu here
+ // It would give way to "lonely" ui turn points, traveling all
+ // the way round. See #105
+
+ if (clustered)
+ {
+ typedef typename boost::range_iterator<Container>::type nc_iterator;
+ nc_iterator it = boost::begin(operations);
+ nc_iterator begin_cluster = boost::end(operations);
+ for (nc_iterator prev = it++;
+ it != boost::end(operations);
+ prev = it++)
+ {
+ operations_type& prev_op = turn_points[prev->index]
+ .operations[prev->operation_index];
+ operations_type& op = turn_points[it->index]
+ .operations[it->operation_index];
+
+ if (prev_op.seg_id == op.seg_id
+ && (turn_points[prev->index].method != method_crosses
+ || turn_points[it->index].method != method_crosses)
+ && geometry::math::equals(prev_op.enriched.distance,
+ op.enriched.distance))
+ {
+ if (begin_cluster == boost::end(operations))
+ {
+ begin_cluster = prev;
+ }
+ }
+ else if (begin_cluster != boost::end(operations))
+ {
+ handle_cluster<IndexType, Reverse1, Reverse2>(begin_cluster, it, turn_points,
+ for_operation, geometry1, geometry2, strategy);
+ begin_cluster = boost::end(operations);
+ }
+ }
+ if (begin_cluster != boost::end(operations))
+ {
+ handle_cluster<IndexType, Reverse1, Reverse2>(begin_cluster, it, turn_points,
+ for_operation, geometry1, geometry2, strategy);
+ }
+ }
+
+ update_discarded(turn_points, operations);
+}
+
+
+template
+<
+ typename IndexType,
+ typename Container,
+ typename TurnPoints
+>
+inline void enrich_discard(Container& operations, TurnPoints& turn_points)
+{
+ update_discarded(turn_points, operations);
+
+ // Then delete discarded operations from vector
+ remove_discarded<IndexType> predicate;
+ operations.erase(
+ std::remove_if(boost::begin(operations),
+ boost::end(operations),
+ predicate),
+ boost::end(operations));
+}
+
+template
+<
+ typename IndexType,
+ typename Container,
+ typename TurnPoints,
+ typename Geometry1,
+ typename Geometry2,
+ typename Strategy
+>
+inline void enrich_assign(Container& operations,
+ TurnPoints& turn_points,
+ operation_type ,
+ Geometry1 const& , Geometry2 const& ,
+ Strategy const& )
+{
+ typedef typename IndexType::type operations_type;
+ typedef typename boost::range_iterator<Container const>::type iterator_type;
+
+
+ if (operations.size() > 0)
+ {
+ // Assign travel-to-vertex/ip index for each turning point.
+ // Because IP's are circular, PREV starts at the very last one,
+ // being assigned from the first one.
+ // "next ip on same segment" should not be considered circular.
+ bool first = true;
+ iterator_type it = boost::begin(operations);
+ for (iterator_type prev = it + (boost::size(operations) - 1);
+ it != boost::end(operations);
+ prev = it++)
+ {
+ operations_type& prev_op
+ = turn_points[prev->index].operations[prev->operation_index];
+ operations_type& op
+ = turn_points[it->index].operations[it->operation_index];
+
+ prev_op.enriched.travels_to_ip_index
+ = it->index;
+ prev_op.enriched.travels_to_vertex_index
+ = it->subject.seg_id.segment_index;
+
+ if (! first
+ && prev_op.seg_id.segment_index == op.seg_id.segment_index)
+ {
+ prev_op.enriched.next_ip_index = it->index;
+ }
+ first = false;
+ }
+ }
+
+ // DEBUG
+#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
+ {
+ for (iterator_type it = boost::begin(operations);
+ it != boost::end(operations);
+ ++it)
+ {
+ operations_type& op = turn_points[it->index]
+ .operations[it->operation_index];
+
+ std::cout << it->index
+ << " meth: " << method_char(turn_points[it->index].method)
+ << " seg: " << op.seg_id
+ << " dst: " << boost::numeric_cast<double>(op.enriched.distance)
+ << " op: " << operation_char(turn_points[it->index].operations[0].operation)
+ << operation_char(turn_points[it->index].operations[1].operation)
+ << " dsc: " << (turn_points[it->index].discarded ? "T" : "F")
+ << " ->vtx " << op.enriched.travels_to_vertex_index
+ << " ->ip " << op.enriched.travels_to_ip_index
+ << " ->nxt ip " << op.enriched.next_ip_index
+ //<< " vis: " << visited_char(op.visited)
+ << std::endl;
+ ;
+ }
+ }
+#endif
+ // END DEBUG
+
+}
+
+
+template <typename IndexedType, typename TurnPoints, typename MappedVector>
+inline void create_map(TurnPoints const& turn_points, MappedVector& mapped_vector)
+{
+ typedef typename boost::range_value<TurnPoints>::type turn_point_type;
+ typedef typename turn_point_type::container_type container_type;
+
+ int index = 0;
+ for (typename boost::range_iterator<TurnPoints const>::type
+ it = boost::begin(turn_points);
+ it != boost::end(turn_points);
+ ++it, ++index)
+ {
+ // Add operations on this ring, but skip discarded ones
+ if (! it->discarded)
+ {
+ int op_index = 0;
+ for (typename boost::range_iterator<container_type const>::type
+ op_it = boost::begin(it->operations);
+ op_it != boost::end(it->operations);
+ ++op_it, ++op_index)
+ {
+ // We should NOT skip blocked operations here
+ // because they can be relevant for "the other side"
+ // NOT if (op_it->operation != operation_blocked)
+
+ ring_identifier ring_id
+ (
+ op_it->seg_id.source_index,
+ op_it->seg_id.multi_index,
+ op_it->seg_id.ring_index
+ );
+ mapped_vector[ring_id].push_back
+ (
+ IndexedType(index, op_index, *op_it)
+ );
+ }
+ }
+ }
+}
+
+
+}} // namespace detail::overlay
+#endif //DOXYGEN_NO_DETAIL
+
+
+
+/*!
+\brief All intersection points are enriched with successor information
+\ingroup overlay
+\tparam TurnPoints type of intersection container
+ (e.g. vector of "intersection/turn point"'s)
+\tparam Geometry1 \tparam_geometry
+\tparam Geometry2 \tparam_geometry
+\tparam Strategy side strategy type
+\param turn_points container containing intersectionpoints
+\param for_operation operation_type (union or intersection)
+\param geometry1 \param_geometry
+\param geometry2 \param_geometry
+\param strategy strategy
+ */
+template
+<
+ bool Reverse1, bool Reverse2,
+ typename TurnPoints,
+ typename Geometry1, typename Geometry2,
+ typename Strategy
+>
+inline void enrich_intersection_points(TurnPoints& turn_points,
+ detail::overlay::operation_type for_operation,
+ Geometry1 const& geometry1, Geometry2 const& geometry2,
+ Strategy const& strategy)
+{
+ typedef typename boost::range_value<TurnPoints>::type turn_point_type;
+ typedef typename turn_point_type::turn_operation_type turn_operation_type;
+ typedef detail::overlay::indexed_turn_operation
+ <
+ turn_operation_type
+ > indexed_turn_operation;
+
+ typedef std::map
+ <
+ ring_identifier,
+ std::vector<indexed_turn_operation>
+ > mapped_vector_type;
+
+ // DISCARD ALL UU
+ // #76 is the reason that this is necessary...
+ // With uu, at all points there is the risk that rings are being traversed twice or more.
+ // Without uu, all rings having only uu will be untouched and gathered by assemble
+ for (typename boost::range_iterator<TurnPoints>::type
+ it = boost::begin(turn_points);
+ it != boost::end(turn_points);
+ ++it)
+ {
+ if (it->both(detail::overlay::operation_union))
+ {
+ it->discarded = true;
+ }
+ }
+
+
+ // Create a map of vectors of indexed operation-types to be able
+ // to sort intersection points PER RING
+ mapped_vector_type mapped_vector;
+
+ detail::overlay::create_map<indexed_turn_operation>(turn_points, mapped_vector);
+
+
+ // No const-iterator; contents of mapped copy is temporary,
+ // and changed by enrich
+ for (typename mapped_vector_type::iterator mit
+ = mapped_vector.begin();
+ mit != mapped_vector.end();
+ ++mit)
+ {
+#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
+ std::cout << "ENRICH-sort Ring "
+ << mit->first << std::endl;
+#endif
+ detail::overlay::enrich_sort<indexed_turn_operation, Reverse1, Reverse2>(mit->second, turn_points, for_operation,
+ geometry1, geometry2, strategy);
+ }
+
+ for (typename mapped_vector_type::iterator mit
+ = mapped_vector.begin();
+ mit != mapped_vector.end();
+ ++mit)
+ {
+#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
+ std::cout << "ENRICH-discard Ring "
+ << mit->first << std::endl;
+#endif
+ detail::overlay::enrich_discard<indexed_turn_operation>(mit->second, turn_points);
+ }
+
+ for (typename mapped_vector_type::iterator mit
+ = mapped_vector.begin();
+ mit != mapped_vector.end();
+ ++mit)
+ {
+#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
+ std::cout << "ENRICH-assign Ring "
+ << mit->first << std::endl;
+#endif
+ detail::overlay::enrich_assign<indexed_turn_operation>(mit->second, turn_points, for_operation,
+ geometry1, geometry2, strategy);
+ }
+
+#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
+ //detail::overlay::check_graph(turn_points, for_operation);
+#endif
+
+}
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ENRICH_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp b/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp
new file mode 100644
index 0000000000..8c8ed96189
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp
@@ -0,0 +1,76 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ENRICHMENT_INFO_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ENRICHMENT_INFO_HPP
+
+
+#include <boost/geometry/strategies/distance.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+
+/*!
+\brief Keeps info to enrich intersection info (per source)
+\details Class to keep information necessary for traversal phase (a phase
+ of the overlay process). The information is gathered during the
+ enrichment phase
+ */
+template<typename P>
+struct enrichment_info
+{
+ typedef typename strategy::distance::services::return_type
+ <
+ typename strategy::distance::services::comparable_type
+ <
+ typename strategy::distance::services::default_strategy
+ <
+ point_tag,
+ P
+ >::type
+ >::type
+ >::type distance_type;
+
+ inline enrichment_info()
+ : travels_to_vertex_index(-1)
+ , travels_to_ip_index(-1)
+ , next_ip_index(-1)
+ , distance(distance_type())
+ {}
+
+ // vertex to which is free travel after this IP,
+ // so from "segment_index+1" to "travels_to_vertex_index", without IP-s,
+ // can be -1
+ int travels_to_vertex_index;
+
+ // same but now IP index, so "next IP index" but not on THIS segment
+ int travels_to_ip_index;
+
+ // index of next IP on this segment, -1 if there is no one
+ int next_ip_index;
+
+ distance_type distance; // distance-measurement from segment.first to IP
+};
+
+
+}} // namespace detail::overlay
+#endif //DOXYGEN_NO_DETAIL
+
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ENRICHMENT_INFO_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/follow.hpp b/boost/geometry/algorithms/detail/overlay/follow.hpp
new file mode 100644
index 0000000000..087092a5f2
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/follow.hpp
@@ -0,0 +1,416 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_HPP
+
+#include <cstddef>
+
+#include <boost/range.hpp>
+#include <boost/mpl/assert.hpp>
+
+#include <boost/geometry/algorithms/detail/point_on_border.hpp>
+#include <boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp>
+#include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp>
+#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+
+#include <boost/geometry/algorithms/covered_by.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+namespace following
+{
+
+template <typename Turn, typename Operation>
+static inline bool is_entering(Turn const& /* TODO remove this parameter */, Operation const& op)
+{
+ // (Blocked means: blocked for polygon/polygon intersection, because
+ // they are reversed. But for polygon/line it is similar to continue)
+ return op.operation == operation_intersection
+ || op.operation == operation_continue
+ || op.operation == operation_blocked
+ ;
+}
+
+template
+<
+ typename Turn,
+ typename Operation,
+ typename LineString,
+ typename Polygon
+>
+static inline bool last_covered_by(Turn const& turn, Operation const& op,
+ LineString const& linestring, Polygon const& polygon)
+{
+ // Check any point between the this one and the first IP
+ typedef typename geometry::point_type<LineString>::type point_type;
+ point_type point_in_between;
+ detail::point_on_border::midpoint_helper
+ <
+ point_type,
+ 0, dimension<point_type>::value
+ >::apply(point_in_between, linestring[op.seg_id.segment_index], turn.point);
+
+ return geometry::covered_by(point_in_between, polygon);
+}
+
+
+template
+<
+ typename Turn,
+ typename Operation,
+ typename LineString,
+ typename Polygon
+>
+static inline bool is_leaving(Turn const& turn, Operation const& op,
+ bool entered, bool first,
+ LineString const& linestring, Polygon const& polygon)
+{
+ if (op.operation == operation_union)
+ {
+ return entered
+ || turn.method == method_crosses
+ || (first && last_covered_by(turn, op, linestring, polygon))
+ ;
+ }
+ return false;
+}
+
+
+template
+<
+ typename Turn,
+ typename Operation,
+ typename LineString,
+ typename Polygon
+>
+static inline bool is_staying_inside(Turn const& turn, Operation const& op,
+ bool entered, bool first,
+ LineString const& linestring, Polygon const& polygon)
+{
+ if (turn.method == method_crosses)
+ {
+ // The normal case, this is completely covered with entering/leaving
+ // so stay out of this time consuming "covered_by"
+ return false;
+ }
+
+ if (is_entering(turn, op))
+ {
+ return entered || (first && last_covered_by(turn, op, linestring, polygon));
+ }
+
+ return false;
+}
+
+template
+<
+ typename Turn,
+ typename Operation,
+ typename Linestring,
+ typename Polygon
+>
+static inline bool was_entered(Turn const& turn, Operation const& op, bool first,
+ Linestring const& linestring, Polygon const& polygon)
+{
+ if (first && (turn.method == method_collinear || turn.method == method_equal))
+ {
+ return last_covered_by(turn, op, linestring, polygon);
+ }
+ return false;
+}
+
+
+// Template specialization structure to call the right actions for the right type
+template<overlay_type OverlayType>
+struct action_selector
+{
+ // If you get here the overlay type is not intersection or difference
+ // BOOST_MPL_ASSERT(false);
+};
+
+// Specialization for intersection, containing the implementation
+template<>
+struct action_selector<overlay_intersection>
+{
+ template
+ <
+ typename OutputIterator,
+ typename LineStringOut,
+ typename LineString,
+ typename Point,
+ typename Operation
+ >
+ static inline void enter(LineStringOut& current_piece,
+ LineString const& ,
+ segment_identifier& segment_id,
+ int , Point const& point,
+ Operation const& operation, OutputIterator& )
+ {
+ // On enter, append the intersection point and remember starting point
+ detail::overlay::append_no_duplicates(current_piece, point);
+ segment_id = operation.seg_id;
+ }
+
+ template
+ <
+ typename OutputIterator,
+ typename LineStringOut,
+ typename LineString,
+ typename Point,
+ typename Operation
+ >
+ static inline void leave(LineStringOut& current_piece,
+ LineString const& linestring,
+ segment_identifier& segment_id,
+ int index, Point const& point,
+ Operation const& , OutputIterator& out)
+ {
+ // On leave, copy all segments from starting point, append the intersection point
+ // and add the output piece
+ geometry::copy_segments<false>(linestring, segment_id, index, current_piece);
+ detail::overlay::append_no_duplicates(current_piece, point);
+ if (current_piece.size() > 1)
+ {
+ *out++ = current_piece;
+ }
+ current_piece.clear();
+ }
+
+ static inline bool is_entered(bool entered)
+ {
+ return entered;
+ }
+
+ template <typename Point, typename Geometry>
+ static inline bool included(Point const& point, Geometry const& geometry)
+ {
+ return geometry::covered_by(point, geometry);
+ }
+
+};
+
+// Specialization for difference, which reverses these actions
+template<>
+struct action_selector<overlay_difference>
+{
+ typedef action_selector<overlay_intersection> normal_action;
+
+ template
+ <
+ typename OutputIterator,
+ typename LineStringOut,
+ typename LineString,
+ typename Point,
+ typename Operation
+ >
+ static inline void enter(LineStringOut& current_piece,
+ LineString const& linestring,
+ segment_identifier& segment_id,
+ int index, Point const& point,
+ Operation const& operation, OutputIterator& out)
+ {
+ normal_action::leave(current_piece, linestring, segment_id, index,
+ point, operation, out);
+ }
+
+ template
+ <
+ typename OutputIterator,
+ typename LineStringOut,
+ typename LineString,
+ typename Point,
+ typename Operation
+ >
+ static inline void leave(LineStringOut& current_piece,
+ LineString const& linestring,
+ segment_identifier& segment_id,
+ int index, Point const& point,
+ Operation const& operation, OutputIterator& out)
+ {
+ normal_action::enter(current_piece, linestring, segment_id, index,
+ point, operation, out);
+ }
+
+ static inline bool is_entered(bool entered)
+ {
+ return ! normal_action::is_entered(entered);
+ }
+
+ template <typename Point, typename Geometry>
+ static inline bool included(Point const& point, Geometry const& geometry)
+ {
+ return ! normal_action::included(point, geometry);
+ }
+
+};
+
+}
+
+/*!
+\brief Follows a linestring from intersection point to intersection point, outputting which
+ is inside, or outside, a ring or polygon
+\ingroup overlay
+ */
+template
+<
+ typename LineStringOut,
+ typename LineString,
+ typename Polygon,
+ overlay_type OverlayType
+>
+class follow
+{
+
+ template<typename Turn>
+ struct sort_on_segment
+ {
+ // In case of turn point at the same location, we want to have continue/blocked LAST
+ // because that should be followed (intersection) or skipped (difference).
+ // By chance the enumeration is ordered like that but we keep the safe way here.
+ inline int operation_order(Turn const& turn) const
+ {
+ operation_type const& operation = turn.operations[0].operation;
+ switch(operation)
+ {
+ case operation_none : return 0;
+ case operation_union : return 1;
+ case operation_intersection : return 2;
+ case operation_blocked : return 3;
+ case operation_continue : return 4;
+ }
+ return -1;
+ };
+
+ inline bool use_operation(Turn const& left, Turn const& right) const
+ {
+ // If they are the same, OK.
+ return operation_order(left) < operation_order(right);
+ }
+
+ inline bool use_distance(Turn const& left, Turn const& right) const
+ {
+ return geometry::math::equals(left.operations[0].enriched.distance, right.operations[0].enriched.distance)
+ ? use_operation(left, right)
+ : left.operations[0].enriched.distance < right.operations[0].enriched.distance
+ ;
+ }
+
+ inline bool operator()(Turn const& left, Turn const& right) const
+ {
+ segment_identifier const& sl = left.operations[0].seg_id;
+ segment_identifier const& sr = right.operations[0].seg_id;
+
+ return sl == sr
+ ? use_distance(left, right)
+ : sl < sr
+ ;
+
+ }
+ };
+
+
+
+public :
+
+ template <typename Point, typename Geometry>
+ static inline bool included(Point const& point, Geometry const& geometry)
+ {
+ return following::action_selector<OverlayType>::included(point, geometry);
+ }
+
+ template<typename Turns, typename OutputIterator>
+ static inline OutputIterator apply(LineString const& linestring, Polygon const& polygon,
+ detail::overlay::operation_type , // TODO: this parameter might be redundant
+ Turns& turns, OutputIterator out)
+ {
+ typedef typename boost::range_iterator<Turns>::type turn_iterator;
+ typedef typename boost::range_value<Turns>::type turn_type;
+ typedef typename boost::range_iterator
+ <
+ typename turn_type::container_type
+ >::type turn_operation_iterator_type;
+
+ typedef following::action_selector<OverlayType> action;
+
+ // Sort intersection points on segments-along-linestring, and distance
+ // (like in enrich is done for poly/poly)
+ std::sort(boost::begin(turns), boost::end(turns), sort_on_segment<turn_type>());
+
+ LineStringOut current_piece;
+ geometry::segment_identifier current_segment_id(0, -1, -1, -1);
+
+ // Iterate through all intersection points (they are ordered along the line)
+ bool entered = false;
+ bool first = true;
+ for (turn_iterator it = boost::begin(turns); it != boost::end(turns); ++it)
+ {
+ turn_operation_iterator_type iit = boost::begin(it->operations);
+
+ if (following::was_entered(*it, *iit, first, linestring, polygon))
+ {
+ debug_traverse(*it, *iit, "-> Was entered");
+ entered = true;
+ }
+
+ if (following::is_staying_inside(*it, *iit, entered, first, linestring, polygon))
+ {
+ debug_traverse(*it, *iit, "-> Staying inside");
+
+ entered = true;
+ }
+ else if (following::is_entering(*it, *iit))
+ {
+ debug_traverse(*it, *iit, "-> Entering");
+
+ entered = true;
+ action::enter(current_piece, linestring, current_segment_id, iit->seg_id.segment_index, it->point, *iit, out);
+ }
+ else if (following::is_leaving(*it, *iit, entered, first, linestring, polygon))
+ {
+ debug_traverse(*it, *iit, "-> Leaving");
+
+ entered = false;
+ action::leave(current_piece, linestring, current_segment_id, iit->seg_id.segment_index, it->point, *iit, out);
+ }
+ first = false;
+ }
+
+ if (action::is_entered(entered))
+ {
+ geometry::copy_segments<false>(linestring, current_segment_id,
+ boost::size(linestring) - 1,
+ current_piece);
+ }
+
+ // Output the last one, if applicable
+ if (current_piece.size() > 1)
+ {
+ *out++ = current_piece;
+ }
+ return out;
+ }
+
+};
+
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp b/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp
new file mode 100644
index 0000000000..019c3ba3f9
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp
@@ -0,0 +1,146 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_INTERSECTION_POINTS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_INTERSECTION_POINTS_HPP
+
+
+#include <cstddef>
+
+#include <boost/geometry/algorithms/convert.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
+
+#include <boost/geometry/geometries/segment.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace get_intersection_points
+{
+
+
+template
+<
+ typename Point1,
+ typename Point2,
+ typename TurnInfo
+>
+struct get_turn_without_info
+{
+ typedef strategy_intersection
+ <
+ typename cs_tag<typename TurnInfo::point_type>::type,
+ Point1,
+ Point2,
+ typename TurnInfo::point_type
+ > si;
+
+ typedef typename si::segment_intersection_strategy_type strategy;
+
+
+
+ template <typename OutputIterator>
+ static inline OutputIterator apply(
+ Point1 const& pi, Point1 const& pj, Point1 const& pk,
+ Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ TurnInfo const& ,
+ OutputIterator out)
+ {
+ typedef model::referring_segment<Point1 const> segment_type1;
+ typedef model::referring_segment<Point1 const> segment_type2;
+ segment_type1 p1(pi, pj), p2(pj, pk);
+ segment_type2 q1(qi, qj), q2(qj, qk);
+
+ //
+ typename strategy::return_type result = strategy::apply(p1, q1);
+
+ for (std::size_t i = 0; i < result.template get<0>().count; i++)
+ {
+
+ TurnInfo tp;
+ geometry::convert(result.template get<0>().intersections[i], tp.point);
+ *out++ = tp;
+ }
+
+ return out;
+ }
+};
+
+}} // namespace detail::get_intersection_points
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+
+template
+<
+ typename Geometry1,
+ typename Geometry2,
+ typename Turns
+>
+inline void get_intersection_points(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Turns& turns)
+{
+ concept::check_concepts_and_equal_dimensions<Geometry1 const, Geometry2 const>();
+
+ typedef detail::get_intersection_points::get_turn_without_info
+ <
+ typename point_type<Geometry1>::type,
+ typename point_type<Geometry2>::type,
+ typename boost::range_value<Turns>::type
+ > TurnPolicy;
+
+ typedef typename strategy_intersection
+ <
+ typename cs_tag<Geometry1>::type,
+ Geometry1,
+ Geometry2,
+ typename boost::range_value<Turns>::type
+ >::segment_intersection_strategy_type segment_intersection_strategy_type;
+
+ detail::get_turns::no_interrupt_policy interrupt_policy;
+
+ boost::mpl::if_c
+ <
+ reverse_dispatch<Geometry1, Geometry2>::type::value,
+ dispatch::get_turns_reversed
+ <
+ typename tag<Geometry1>::type,
+ typename tag<Geometry2>::type,
+ Geometry1, Geometry2,
+ false, false,
+ Turns, TurnPolicy,
+ //segment_intersection_strategy_type,
+ detail::get_turns::no_interrupt_policy
+ >,
+ dispatch::get_turns
+ <
+ typename tag<Geometry1>::type,
+ typename tag<Geometry2>::type,
+ Geometry1, Geometry2,
+ false, false,
+ Turns, TurnPolicy,
+ //segment_intersection_strategy_type,
+ detail::get_turns::no_interrupt_policy
+ >
+ >::type::apply(
+ 0, geometry1,
+ 1, geometry2,
+ turns, interrupt_policy);
+}
+
+
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_INTERSECTION_POINTS_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/get_relative_order.hpp b/boost/geometry/algorithms/detail/overlay/get_relative_order.hpp
new file mode 100644
index 0000000000..522ef68382
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/get_relative_order.hpp
@@ -0,0 +1,108 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_RELATIVE_ORDER_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_RELATIVE_ORDER_HPP
+
+
+#include <boost/geometry/algorithms/distance.hpp>
+
+#include <boost/geometry/strategies/intersection.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+
+/*!
+ \brief Get relative order
+ \details Can indicate which of two segments R and S,
+ both crossing a common segment P, comes first.
+ If the two segments cross P very close (e.g. in a spike),
+ the distance between the intersection points can be zero,
+ but we still need to know which comes first.
+ Therefore, it is useful that using sides we are able to discover this.
+ */
+template <typename Point1>
+struct get_relative_order
+{
+ typedef strategy_intersection
+ <
+ typename cs_tag<Point1>::type,
+ Point1,
+ Point1,
+ Point1
+ > si;
+
+ typedef typename si::side_strategy_type strategy;
+
+ template <typename Point>
+ static inline int value_via_product(Point const& ti, Point const& tj,
+ Point const& ui, Point const& uj, int factor)
+ {
+ int const side_ti_u = strategy::apply(ti, tj, ui);
+ int const side_tj_u = strategy::apply(ti, tj, uj);
+
+#ifdef BOOST_GEOMETRY_DEBUG_RELATIVE_ORDER
+ std::cout << (factor == 1 ? " r//s " : " s//r ")
+ << side_ti_u << " / " << side_tj_u;
+#endif
+
+ return side_ti_u * side_tj_u >= 0
+ ? factor * (side_ti_u != 0 ? side_ti_u : side_tj_u)
+ : 0;
+ }
+
+
+ static inline int apply(
+ Point1 const& pi, Point1 const& pj,
+ Point1 const& ri, Point1 const& rj,
+ Point1 const& si, Point1 const& sj)
+ {
+ int const side_ri_p = strategy::apply(pi, pj, ri);
+ int const side_si_p = strategy::apply(pi, pj, si);
+
+#ifdef BOOST_GEOMETRY_DEBUG_RELATIVE_ORDER
+ int const side_rj_p = strategy::apply(pi, pj, rj);
+ int const side_sj_p = strategy::apply(pi, pj, sj);
+ std::cout << "r//p: " << side_ri_p << " / " << side_rj_p;
+ std::cout << " s//p: " << side_si_p << " / " << side_sj_p;
+#endif
+
+ int value = value_via_product(si, sj, ri, rj, 1);
+ if (value == 0)
+ {
+ value = value_via_product(ri, rj, si, sj, -1);
+ }
+
+ int const order = side_ri_p * side_ri_p * side_si_p * value;
+
+#ifdef BOOST_GEOMETRY_DEBUG_RELATIVE_ORDER
+ std::cout
+ << " o: " << order
+ << std::endl << std::endl;
+#endif
+
+ return order;
+ }
+};
+
+
+}} // namespace detail::overlay
+#endif //DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_RELATIVE_ORDER_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/get_ring.hpp b/boost/geometry/algorithms/detail/overlay/get_ring.hpp
new file mode 100644
index 0000000000..ad47665500
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/get_ring.hpp
@@ -0,0 +1,102 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_RING_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_RING_HPP
+
+
+#include <boost/assert.hpp>
+#include <boost/range.hpp>
+
+
+#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/core/exterior_ring.hpp>
+#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+
+template<typename Tag>
+struct get_ring
+{};
+
+// A container of rings (multi-ring but that does not exist)
+// gets the "void" tag and is dispatched here.
+template<>
+struct get_ring<void>
+{
+ template<typename Container>
+ static inline typename boost::range_value<Container>::type const&
+ apply(ring_identifier const& id, Container const& container)
+ {
+ return container[id.multi_index];
+ }
+};
+
+
+
+
+template<>
+struct get_ring<ring_tag>
+{
+ template<typename Ring>
+ static inline Ring const& apply(ring_identifier const& , Ring const& ring)
+ {
+ return ring;
+ }
+};
+
+
+template<>
+struct get_ring<box_tag>
+{
+ template<typename Box>
+ static inline Box const& apply(ring_identifier const& ,
+ Box const& box)
+ {
+ return box;
+ }
+};
+
+
+template<>
+struct get_ring<polygon_tag>
+{
+ template<typename Polygon>
+ static inline typename ring_return_type<Polygon const>::type const apply(
+ ring_identifier const& id,
+ Polygon const& polygon)
+ {
+ BOOST_ASSERT
+ (
+ id.ring_index >= -1
+ && id.ring_index < boost::size(interior_rings(polygon))
+ );
+ return id.ring_index < 0
+ ? exterior_ring(polygon)
+ : interior_rings(polygon)[id.ring_index];
+ }
+};
+
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_RING_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp
new file mode 100644
index 0000000000..663d70d9af
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp
@@ -0,0 +1,956 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HPP
+
+
+#include <boost/assert.hpp>
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/strategies/intersection.hpp>
+
+#include <boost/geometry/algorithms/convert.hpp>
+#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+
+#include <boost/geometry/geometries/segment.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW)
+class turn_info_exception : public geometry::exception
+{
+ std::string message;
+public:
+
+ // NOTE: "char" will be replaced by enum in future version
+ inline turn_info_exception(char const method)
+ {
+ message = "Boost.Geometry Turn exception: ";
+ message += method;
+ }
+
+ virtual ~turn_info_exception() throw()
+ {}
+
+ virtual char const* what() const throw()
+ {
+ return message.c_str();
+ }
+};
+#endif
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+
+struct base_turn_handler
+{
+ // Returns true if both sides are opposite
+ static inline bool opposite(int side1, int side2)
+ {
+ // We cannot state side1 == -side2, because 0 == -0
+ // So either side1*side2==-1 or side1==-side2 && side1 != 0
+ return side1 * side2 == -1;
+ }
+
+ // Same side of a segment (not being 0)
+ static inline bool same(int side1, int side2)
+ {
+ return side1 * side2 == 1;
+ }
+
+ // Both continue
+ template <typename TurnInfo>
+ static inline void both(TurnInfo& ti, operation_type const op)
+ {
+ ti.operations[0].operation = op;
+ ti.operations[1].operation = op;
+ }
+
+ // If condition, first union/second intersection, else vice versa
+ template <typename TurnInfo>
+ static inline void ui_else_iu(bool condition, TurnInfo& ti)
+ {
+ ti.operations[0].operation = condition
+ ? operation_union : operation_intersection;
+ ti.operations[1].operation = condition
+ ? operation_intersection : operation_union;
+ }
+
+ // If condition, both union, else both intersection
+ template <typename TurnInfo>
+ static inline void uu_else_ii(bool condition, TurnInfo& ti)
+ {
+ both(ti, condition ? operation_union : operation_intersection);
+ }
+};
+
+
+template
+<
+ typename TurnInfo,
+ typename SideStrategy
+>
+struct touch_interior : public base_turn_handler
+{
+ // Index: 0, P is the interior, Q is touching and vice versa
+ template
+ <
+ int Index,
+ typename Point1,
+ typename Point2,
+ typename IntersectionInfo,
+ typename DirInfo
+ >
+ static inline void apply(
+ Point1 const& pi, Point1 const& pj, Point1 const& ,
+ Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ TurnInfo& ti,
+ IntersectionInfo const& intersection_info,
+ DirInfo const& dir_info)
+ {
+ ti.method = method_touch_interior;
+ geometry::convert(intersection_info.intersections[0], ti.point);
+
+ // Both segments of q touch segment p somewhere in its interior
+ // 1) We know: if q comes from LEFT or RIGHT
+ // (i.e. dir_info.sides.get<Index,0>() == 1 or -1)
+ // 2) Important is: if q_k goes to LEFT, RIGHT, COLLINEAR
+ // and, if LEFT/COLL, if it is lying LEFT or RIGHT w.r.t. q_i
+
+ static int const index_p = Index;
+ static int const index_q = 1 - Index;
+
+ int const side_qi_p = dir_info.sides.template get<index_q, 0>();
+ int const side_qk_p = SideStrategy::apply(pi, pj, qk);
+
+ if (side_qi_p == -side_qk_p)
+ {
+ // Q crosses P from left->right or from right->left (test "ML1")
+ // Union: folow P (left->right) or Q (right->left)
+ // Intersection: other turn
+ int index = side_qk_p == -1 ? index_p : index_q;
+ ti.operations[index].operation = operation_union;
+ ti.operations[1 - index].operation = operation_intersection;
+ return;
+ }
+
+ int const side_qk_q = SideStrategy::apply(qi, qj, qk);
+
+ if (side_qi_p == -1 && side_qk_p == -1 && side_qk_q == 1)
+ {
+ // Q turns left on the right side of P (test "MR3")
+ // Both directions for "intersection"
+ both(ti, operation_intersection);
+ }
+ else if (side_qi_p == 1 && side_qk_p == 1 && side_qk_q == -1)
+ {
+ // Q turns right on the left side of P (test "ML3")
+ // Union: take both operation
+ // Intersection: skip
+ both(ti, operation_union);
+ }
+ else if (side_qi_p == side_qk_p && side_qi_p == side_qk_q)
+ {
+ // Q turns left on the left side of P (test "ML2")
+ // or Q turns right on the right side of P (test "MR2")
+ // Union: take left turn (Q if Q turns left, P if Q turns right)
+ // Intersection: other turn
+ int index = side_qk_q == 1 ? index_q : index_p;
+ ti.operations[index].operation = operation_union;
+ ti.operations[1 - index].operation = operation_intersection;
+ }
+ else if (side_qk_p == 0)
+ {
+ // Q intersects on interior of P and continues collinearly
+ if (side_qk_q == side_qi_p)
+ {
+ // Collinearly in the same direction
+ // (Q comes from left of P and turns left,
+ // OR Q comes from right of P and turns right)
+ // Omit intersection point.
+ // Union: just continue
+ // Intersection: just continue
+ both(ti, operation_continue);
+ }
+ else
+ {
+ // Opposite direction, which is never travelled.
+ // If Q turns left, P continues for intersection
+ // If Q turns right, P continues for union
+ ti.operations[Index].operation = side_qk_q == 1
+ ? operation_intersection
+ : operation_union;
+ ti.operations[1 - Index].operation = operation_blocked;
+ }
+ }
+ else
+ {
+ // Should not occur!
+ ti.method = method_error;
+ }
+ }
+};
+
+
+template
+<
+ typename TurnInfo,
+ typename SideStrategy
+>
+struct touch : public base_turn_handler
+{
+ static inline bool between(int side1, int side2, int turn)
+ {
+ return side1 == side2 && ! opposite(side1, turn);
+ }
+
+ /*static inline void block_second(bool block, TurnInfo& ti)
+ {
+ if (block)
+ {
+ ti.operations[1].operation = operation_blocked;
+ }
+ }*/
+
+
+ template
+ <
+ typename Point1,
+ typename Point2,
+ typename IntersectionInfo,
+ typename DirInfo
+ >
+ static inline void apply(
+ Point1 const& pi, Point1 const& pj, Point1 const& pk,
+ Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ TurnInfo& ti,
+ IntersectionInfo const& intersection_info,
+ DirInfo const& dir_info)
+ {
+ ti.method = method_touch;
+ geometry::convert(intersection_info.intersections[0], ti.point);
+
+ int const side_qi_p1 = dir_info.sides.template get<1, 0>();
+ int const side_qk_p1 = SideStrategy::apply(pi, pj, qk);
+
+
+ // If Qi and Qk are both at same side of Pi-Pj,
+ // or collinear (so: not opposite sides)
+ if (! opposite(side_qi_p1, side_qk_p1))
+ {
+ int const side_pk_q2 = SideStrategy::apply(qj, qk, pk);
+ int const side_pk_p = SideStrategy::apply(pi, pj, pk);
+ int const side_qk_q = SideStrategy::apply(qi, qj, qk);
+ bool const q_turns_left = side_qk_q == 1;
+ bool const block_q = side_qk_p1 == 0
+ && ! same(side_qi_p1, side_qk_q);
+
+ // If Pk at same side as Qi/Qk
+ // (the "or" is for collinear case)
+ // or Q is fully collinear && P turns not to left
+ if (side_pk_p == side_qi_p1
+ || side_pk_p == side_qk_p1
+ || (side_qi_p1 == 0 && side_qk_p1 == 0 && side_pk_p != -1)
+ )
+ {
+ // Collinear -> lines join, continue
+ // (#BRL2)
+ if (side_pk_q2 == 0 && ! block_q)
+ {
+ both(ti, operation_continue);
+ return;
+ }
+
+ int const side_pk_q1 = SideStrategy::apply(qi, qj, pk);
+
+
+ // Collinear opposite case -> block P
+ // (#BRL4, #BLR8)
+ if (side_pk_q1 == 0)
+ {
+ ti.operations[0].operation = operation_blocked;
+ // Q turns right -> union (both independant),
+ // Q turns left -> intersection
+ ti.operations[1].operation = block_q ? operation_blocked
+ : q_turns_left ? operation_intersection
+ : operation_union;
+ return;
+ }
+
+ // Pk between Qi and Qk
+ // (#BRL3, #BRL7)
+ if (between(side_pk_q1, side_pk_q2, side_qk_q))
+ {
+ ui_else_iu(q_turns_left, ti);
+ if (block_q)
+ {
+ ti.operations[1].operation = operation_blocked;
+ }
+ //block_second(block_q, ti);
+ return;
+ }
+
+ // Pk between Qk and P, so left of Qk (if Q turns right) and vv
+ // (#BRL1)
+ if (side_pk_q2 == -side_qk_q)
+ {
+ ui_else_iu(! q_turns_left, ti);
+ return;
+ }
+
+ //
+ // (#BRL5, #BRL9)
+ if (side_pk_q1 == -side_qk_q)
+ {
+ uu_else_ii(! q_turns_left, ti);
+ if (block_q)
+ {
+ ti.operations[1].operation = operation_blocked;
+ }
+ //block_second(block_q, ti);
+ return;
+ }
+ }
+ else
+ {
+ // Pk at other side than Qi/Pk
+ int const side_qk_q = SideStrategy::apply(qi, qj, qk);
+ bool const q_turns_left = side_qk_q == 1;
+
+ ti.operations[0].operation = q_turns_left
+ ? operation_intersection
+ : operation_union;
+ ti.operations[1].operation = block_q
+ ? operation_blocked
+ : side_qi_p1 == 1 || side_qk_p1 == 1
+ ? operation_union
+ : operation_intersection;
+
+ return;
+ }
+ }
+ else
+ {
+ // From left to right or from right to left
+ int const side_pk_p = SideStrategy::apply(pi, pj, pk);
+ bool const right_to_left = side_qk_p1 == 1;
+
+ // If p turns into direction of qi (1,2)
+ if (side_pk_p == side_qi_p1)
+ {
+ int const side_pk_q1 = SideStrategy::apply(qi, qj, pk);
+
+ // Collinear opposite case -> block P
+ if (side_pk_q1 == 0)
+ {
+ ti.operations[0].operation = operation_blocked;
+ ti.operations[1].operation = right_to_left
+ ? operation_union : operation_intersection;
+ return;
+ }
+
+ if (side_pk_q1 == side_qk_p1)
+ {
+ uu_else_ii(right_to_left, ti);
+ return;
+ }
+ }
+
+ // If p turns into direction of qk (4,5)
+ if (side_pk_p == side_qk_p1)
+ {
+ int const side_pk_q2 = SideStrategy::apply(qj, qk, pk);
+
+ // Collinear case -> lines join, continue
+ if (side_pk_q2 == 0)
+ {
+ both(ti, operation_continue);
+ return;
+ }
+ if (side_pk_q2 == side_qk_p1)
+ {
+ ui_else_iu(right_to_left, ti);
+ return;
+ }
+ }
+ // otherwise (3)
+ ui_else_iu(! right_to_left, ti);
+ return;
+ }
+
+#ifdef BOOST_GEOMETRY_DEBUG_GET_TURNS
+ // Normally a robustness issue.
+ // TODO: more research if still occuring
+ std::cout << "Not yet handled" << std::endl
+ << "pi " << get<0>(pi) << " , " << get<1>(pi)
+ << " pj " << get<0>(pj) << " , " << get<1>(pj)
+ << " pk " << get<0>(pk) << " , " << get<1>(pk)
+ << std::endl
+ << "qi " << get<0>(qi) << " , " << get<1>(qi)
+ << " qj " << get<0>(qj) << " , " << get<1>(qj)
+ << " qk " << get<0>(qk) << " , " << get<1>(qk)
+ << std::endl;
+#endif
+
+ }
+};
+
+
+template
+<
+ typename TurnInfo,
+ typename SideStrategy
+>
+struct equal : public base_turn_handler
+{
+ template
+ <
+ typename Point1,
+ typename Point2,
+ typename IntersectionInfo,
+ typename DirInfo
+ >
+ static inline void apply(
+ Point1 const& pi, Point1 const& pj, Point1 const& pk,
+ Point2 const& , Point2 const& qj, Point2 const& qk,
+ TurnInfo& ti,
+ IntersectionInfo const& intersection_info,
+ DirInfo const& )
+ {
+ ti.method = method_equal;
+ // Copy the SECOND intersection point
+ geometry::convert(intersection_info.intersections[1], ti.point);
+
+ int const side_pk_q2 = SideStrategy::apply(qj, qk, pk);
+ int const side_pk_p = SideStrategy::apply(pi, pj, pk);
+ int const side_qk_p = SideStrategy::apply(pi, pj, qk);
+
+ // If pk is collinear with qj-qk, they continue collinearly.
+ // This can be on either side of p1 (== q1), or collinear
+ // The second condition checks if they do not continue
+ // oppositely
+ if (side_pk_q2 == 0 && side_pk_p == side_qk_p)
+ {
+ both(ti, operation_continue);
+ return;
+ }
+
+
+ // If they turn to same side (not opposite sides)
+ if (! opposite(side_pk_p, side_qk_p))
+ {
+ int const side_pk_q2 = SideStrategy::apply(qj, qk, pk);
+
+ // If pk is left of q2 or collinear: p: union, q: intersection
+ ui_else_iu(side_pk_q2 != -1, ti);
+ }
+ else
+ {
+ // They turn opposite sides. If p turns left (or collinear),
+ // p: union, q: intersection
+ ui_else_iu(side_pk_p != -1, ti);
+ }
+ }
+};
+
+
+template
+<
+ typename TurnInfo,
+ typename SideStrategy
+>
+struct collinear : public base_turn_handler
+{
+ /*
+ arrival P pk//p1 qk//q1 product* case result
+ 1 1 1 CLL1 ui
+ -1 1 -1 CLL2 iu
+ 1 1 1 CLR1 ui
+ -1 -1 1 CLR2 ui
+
+ 1 -1 -1 CRL1 iu
+ -1 1 -1 CRL2 iu
+ 1 -1 -1 CRR1 iu
+ -1 -1 1 CRR2 ui
+
+ 1 0 0 CC1 cc
+ -1 0 0 CC2 cc
+
+ *product = arrival * (pk//p1 or qk//q1)
+
+ Stated otherwise:
+ - if P arrives: look at turn P
+ - if Q arrives: look at turn Q
+ - if P arrives and P turns left: union for P
+ - if P arrives and P turns right: intersection for P
+ - if Q arrives and Q turns left: union for Q (=intersection for P)
+ - if Q arrives and Q turns right: intersection for Q (=union for P)
+ */
+ template
+ <
+ typename Point1,
+ typename Point2,
+ typename IntersectionInfo,
+ typename DirInfo
+ >
+ static inline void apply(
+ Point1 const& pi, Point1 const& pj, Point1 const& pk,
+ Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ TurnInfo& ti,
+ IntersectionInfo const& intersection_info,
+ DirInfo const& dir_info)
+ {
+ ti.method = method_collinear;
+ geometry::convert(intersection_info.intersections[1], ti.point);
+
+ int const arrival = dir_info.arrival[0];
+ // Should not be 0, this is checked before
+ BOOST_ASSERT(arrival != 0);
+
+ // If p arrives, use p, else use q
+ int const side_p_or_q = arrival == 1
+ ? SideStrategy::apply(pi, pj, pk)
+ : SideStrategy::apply(qi, qj, qk)
+ ;
+
+ // See comments above,
+ // resulting in a strange sort of mathematic rule here:
+ // The arrival-info multiplied by the relevant side
+ // delivers a consistent result.
+
+ int const product = arrival * side_p_or_q;
+
+ if(product == 0)
+ {
+ both(ti, operation_continue);
+ }
+ else
+ {
+ ui_else_iu(product == 1, ti);
+ }
+ }
+};
+
+template
+<
+ typename TurnInfo,
+ typename SideStrategy,
+ typename AssignPolicy
+>
+struct collinear_opposite : public base_turn_handler
+{
+private :
+ /*
+ arrival P arrival Q pk//p1 qk//q1 case result2 result
+ --------------------------------------------------------------
+ 1 1 1 -1 CLO1 ix xu
+ 1 1 1 0 CLO2 ix (xx)
+ 1 1 1 1 CLO3 ix xi
+
+ 1 1 0 -1 CCO1 (xx) xu
+ 1 1 0 0 CCO2 (xx) (xx)
+ 1 1 0 1 CCO3 (xx) xi
+
+ 1 1 -1 -1 CRO1 ux xu
+ 1 1 -1 0 CRO2 ux (xx)
+ 1 1 -1 1 CRO3 ux xi
+
+ -1 1 -1 CXO1 xu
+ -1 1 0 CXO2 (xx)
+ -1 1 1 CXO3 xi
+
+ 1 -1 1 CXO1 ix
+ 1 -1 0 CXO2 (xx)
+ 1 -1 -1 CXO3 ux
+ */
+
+ template
+ <
+ int Index,
+ typename Point,
+ typename IntersectionInfo
+ >
+ static inline bool set_tp(Point const& ri, Point const& rj, Point const& rk,
+ TurnInfo& tp, IntersectionInfo const& intersection_info)
+ {
+ int const side_rk_r = SideStrategy::apply(ri, rj, rk);
+ switch(side_rk_r)
+ {
+
+ case 1 :
+ // Turning left on opposite collinear: intersection
+ tp.operations[Index].operation = operation_intersection;
+ break;
+ case -1 :
+ // Turning right on opposite collinear: union
+ tp.operations[Index].operation = operation_union;
+ break;
+ case 0 :
+ // No turn on opposite collinear: block, do not traverse
+ // But this "xx" is ignored here, it is useless to include
+ // two operation blocked, so the whole point does not need
+ // to be generated.
+ // So return false to indicate nothing is to be done.
+ return false;
+ }
+
+ // The other direction is always blocked when collinear opposite
+ tp.operations[1 - Index].operation = operation_blocked;
+
+ // If P arrives within Q, set info on P (which is done above, index=0),
+ // this turn-info belongs to the second intersection point, index=1
+ // (see e.g. figure CLO1)
+ geometry::convert(intersection_info.intersections[1 - Index], tp.point);
+ return true;
+ }
+
+public:
+ template
+ <
+ typename Point1,
+ typename Point2,
+ typename OutputIterator,
+ typename IntersectionInfo,
+ typename DirInfo
+ >
+ static inline void apply(
+ Point1 const& pi, Point1 const& pj, Point1 const& pk,
+ Point2 const& qi, Point2 const& qj, Point2 const& qk,
+
+ // Opposite collinear can deliver 2 intersection points,
+ TurnInfo const& tp_model,
+ OutputIterator& out,
+
+ IntersectionInfo const& intersection_info,
+ DirInfo const& dir_info)
+ {
+ /*
+ std::cout << "arrivals: "
+ << dir_info.arrival[0]
+ << "/" << dir_info.arrival[1]
+ << std::endl;
+ */
+
+ TurnInfo tp = tp_model;
+
+ tp.method = method_collinear;
+
+ // If P arrives within Q, there is a turn dependant on P
+ if (dir_info.arrival[0] == 1
+ && set_tp<0>(pi, pj, pk, tp, intersection_info))
+ {
+ AssignPolicy::apply(tp, pi, qi);
+ *out++ = tp;
+ }
+
+ // If Q arrives within P, there is a turn dependant on Q
+ if (dir_info.arrival[1] == 1
+ && set_tp<1>(qi, qj, qk, tp, intersection_info))
+ {
+ AssignPolicy::apply(tp, pi, qi);
+ *out++ = tp;
+ }
+ }
+};
+
+
+template
+<
+ typename TurnInfo,
+ typename SideStrategy
+>
+struct crosses : public base_turn_handler
+{
+ template
+ <
+ typename Point1,
+ typename Point2,
+ typename IntersectionInfo,
+ typename DirInfo
+ >
+ static inline void apply(
+ Point1 const& , Point1 const& , Point1 const& ,
+ Point2 const& , Point2 const& , Point2 const& ,
+ TurnInfo& ti,
+ IntersectionInfo const& intersection_info,
+ DirInfo const& dir_info)
+ {
+ ti.method = method_crosses;
+ geometry::convert(intersection_info.intersections[0], ti.point);
+
+ // In all casees:
+ // If Q crosses P from left to right
+ // Union: take P
+ // Intersection: take Q
+ // Otherwise: vice versa
+ int const side_qi_p1 = dir_info.sides.template get<1, 0>();
+ int const index = side_qi_p1 == 1 ? 0 : 1;
+ ti.operations[index].operation = operation_union;
+ ti.operations[1 - index].operation = operation_intersection;
+ }
+};
+
+template<typename TurnInfo>
+struct only_convert
+{
+ template<typename IntersectionInfo>
+ static inline void apply(TurnInfo& ti, IntersectionInfo const& intersection_info)
+ {
+ ti.method = method_collinear;
+ geometry::convert(intersection_info.intersections[0], ti.point);
+ ti.operations[0].operation = operation_continue;
+ ti.operations[1].operation = operation_continue;
+ }
+};
+
+/*!
+\brief Policy doing nothing
+\details get_turn_info can have an optional policy to get/assign some
+ extra information. By default it does not, and this class
+ is that default.
+ */
+struct assign_null_policy
+{
+ static bool const include_no_turn = false;
+ static bool const include_degenerate = false;
+
+ template <typename Point1, typename Point2, typename Info>
+ static inline void apply(Info& , Point1 const& , Point2 const& )
+ {}
+
+};
+
+
+/*!
+ \brief Turn information: intersection point, method, and turn information
+ \details Information necessary for traversal phase (a phase
+ of the overlay process). The information is gathered during the
+ get_turns (segment intersection) phase.
+ \tparam Point1 point type of first segment
+ \tparam Point2 point type of second segment
+ \tparam TurnInfo type of class getting intersection and turn info
+ \tparam AssignPolicy policy to assign extra info,
+ e.g. to calculate distance from segment's first points
+ to intersection points.
+ It also defines if a certain class of points
+ (degenerate, non-turns) should be included.
+ */
+template
+<
+ typename Point1,
+ typename Point2,
+ typename TurnInfo,
+ typename AssignPolicy
+>
+struct get_turn_info
+{
+ typedef strategy_intersection
+ <
+ typename cs_tag<typename TurnInfo::point_type>::type,
+ Point1,
+ Point2,
+ typename TurnInfo::point_type
+ > si;
+
+ typedef typename si::segment_intersection_strategy_type strategy;
+
+
+
+ template <typename OutputIterator>
+ static inline OutputIterator apply(
+ Point1 const& pi, Point1 const& pj, Point1 const& pk,
+ Point2 const& qi, Point2 const& qj, Point2 const& qk,
+ TurnInfo const& tp_model,
+ OutputIterator out)
+ {
+ typedef model::referring_segment<Point1 const> segment_type1;
+ typedef model::referring_segment<Point1 const> segment_type2;
+ segment_type1 p1(pi, pj), p2(pj, pk);
+ segment_type2 q1(qi, qj), q2(qj, qk);
+
+ typename strategy::return_type result = strategy::apply(p1, q1);
+
+ char const method = result.template get<1>().how;
+
+ // Copy, to copy possibly extended fields
+ TurnInfo tp = tp_model;
+
+
+ // Select method and apply
+ switch(method)
+ {
+ case 'a' : // collinear, "at"
+ case 'f' : // collinear, "from"
+ case 's' : // starts from the middle
+ if (AssignPolicy::include_no_turn
+ && result.template get<0>().count > 0)
+ {
+ only_convert<TurnInfo>::apply(tp,
+ result.template get<0>());
+ AssignPolicy::apply(tp, pi, qi);
+ *out++ = tp;
+ }
+ break;
+
+ case 'd' : // disjoint: never do anything
+ break;
+
+ case 'm' :
+ {
+ typedef touch_interior
+ <
+ TurnInfo,
+ typename si::side_strategy_type
+ > policy;
+
+ // If Q (1) arrives (1)
+ if (result.template get<1>().arrival[1] == 1)
+ {
+ policy::template apply<0>(pi, pj, pk, qi, qj, qk,
+ tp, result.template get<0>(), result.template get<1>());
+ }
+ else
+ {
+ // Swap p/q
+ policy::template apply<1>(qi, qj, qk, pi, pj, pk,
+ tp, result.template get<0>(), result.template get<1>());
+ }
+ AssignPolicy::apply(tp, pi, qi);
+ *out++ = tp;
+ }
+ break;
+ case 'i' :
+ {
+ typedef crosses
+ <
+ TurnInfo,
+ typename si::side_strategy_type
+ > policy;
+
+ policy::apply(pi, pj, pk, qi, qj, qk,
+ tp, result.template get<0>(), result.template get<1>());
+ AssignPolicy::apply(tp, pi, qi);
+ *out++ = tp;
+ }
+ break;
+ case 't' :
+ {
+ // Both touch (both arrive there)
+ typedef touch
+ <
+ TurnInfo,
+ typename si::side_strategy_type
+ > policy;
+
+ policy::apply(pi, pj, pk, qi, qj, qk,
+ tp, result.template get<0>(), result.template get<1>());
+ AssignPolicy::apply(tp, pi, qi);
+ *out++ = tp;
+ }
+ break;
+ case 'e':
+ {
+ if (! result.template get<1>().opposite)
+ {
+ // Both equal
+ // or collinear-and-ending at intersection point
+ typedef equal
+ <
+ TurnInfo,
+ typename si::side_strategy_type
+ > policy;
+
+ policy::apply(pi, pj, pk, qi, qj, qk,
+ tp, result.template get<0>(), result.template get<1>());
+ AssignPolicy::apply(tp, pi, qi);
+ *out++ = tp;
+ }
+ // If they ARE opposite, don't do anything.
+ }
+ break;
+ case 'c' :
+ {
+ // Collinear
+ if (! result.template get<1>().opposite)
+ {
+
+ if (result.template get<1>().arrival[0] == 0)
+ {
+ // Collinear, but similar thus handled as equal
+ equal
+ <
+ TurnInfo,
+ typename si::side_strategy_type
+ >::apply(pi, pj, pk, qi, qj, qk,
+ tp, result.template get<0>(), result.template get<1>());
+
+ // override assigned method
+ tp.method = method_collinear;
+ }
+ else
+ {
+ collinear
+ <
+ TurnInfo,
+ typename si::side_strategy_type
+ >::apply(pi, pj, pk, qi, qj, qk,
+ tp, result.template get<0>(), result.template get<1>());
+ }
+
+ AssignPolicy::apply(tp, pi, qi);
+ *out++ = tp;
+ }
+ else
+ {
+ collinear_opposite
+ <
+ TurnInfo,
+ typename si::side_strategy_type,
+ AssignPolicy
+ >::apply(pi, pj, pk, qi, qj, qk,
+ tp, out, result.template get<0>(), result.template get<1>());
+ }
+ }
+ break;
+ case '0' :
+ {
+ // degenerate points
+ if (AssignPolicy::include_degenerate)
+ {
+ only_convert<TurnInfo>::apply(tp, result.template get<0>());
+ AssignPolicy::apply(tp, pi, qi);
+ *out++ = tp;
+ }
+ }
+ break;
+ default :
+ {
+#if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW)
+ throw turn_info_exception(method);
+#endif
+ }
+ break;
+ }
+
+ return out;
+ }
+};
+
+
+}} // namespace detail::overlay
+#endif //DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/get_turns.hpp b/boost/geometry/algorithms/detail/overlay/get_turns.hpp
new file mode 100644
index 0000000000..5740a8b7ba
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/get_turns.hpp
@@ -0,0 +1,866 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURNS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURNS_HPP
+
+
+#include <cstddef>
+#include <map>
+
+#include <boost/array.hpp>
+#include <boost/mpl/if.hpp>
+#include <boost/range.hpp>
+#include <boost/typeof/typeof.hpp>
+
+#include <boost/tuple/tuple.hpp>
+
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/coordinate_dimension.hpp>
+#include <boost/geometry/core/reverse_dispatch.hpp>
+
+#include <boost/geometry/core/exterior_ring.hpp>
+#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/core/ring_type.hpp>
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+
+#include <boost/geometry/util/math.hpp>
+#include <boost/geometry/views/closeable_view.hpp>
+#include <boost/geometry/views/reversible_view.hpp>
+#include <boost/geometry/views/detail/range_type.hpp>
+
+#include <boost/geometry/geometries/box.hpp>
+#include <boost/geometry/geometries/segment.hpp>
+
+#include <boost/geometry/iterators/ever_circling_iterator.hpp>
+
+#include <boost/geometry/strategies/cartesian/cart_intersect.hpp>
+#include <boost/geometry/strategies/intersection.hpp>
+#include <boost/geometry/strategies/intersection_result.hpp>
+
+#include <boost/geometry/algorithms/detail/disjoint.hpp>
+#include <boost/geometry/algorithms/detail/partition.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
+
+#include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
+
+
+#include <boost/geometry/algorithms/detail/sections/range_by_section.hpp>
+
+#include <boost/geometry/algorithms/expand.hpp>
+#include <boost/geometry/algorithms/detail/sections/sectionalize.hpp>
+
+#ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION
+# include <sstream>
+# include <boost/geometry/io/dsv/write.hpp>
+#endif
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace get_turns
+{
+
+
+struct no_interrupt_policy
+{
+ static bool const enabled = false;
+
+ template <typename Range>
+ static inline bool apply(Range const&)
+ {
+ return false;
+ }
+};
+
+
+template
+<
+ typename Geometry1, typename Geometry2,
+ bool Reverse1, bool Reverse2,
+ typename Section1, typename Section2,
+ typename Turns,
+ typename TurnPolicy,
+ typename InterruptPolicy
+>
+class get_turns_in_sections
+{
+ typedef typename closeable_view
+ <
+ typename range_type<Geometry1>::type const,
+ closure<Geometry1>::value
+ >::type cview_type1;
+ typedef typename closeable_view
+ <
+ typename range_type<Geometry2>::type const,
+ closure<Geometry2>::value
+ >::type cview_type2;
+
+ typedef typename reversible_view
+ <
+ cview_type1 const,
+ Reverse1 ? iterate_reverse : iterate_forward
+ >::type view_type1;
+ typedef typename reversible_view
+ <
+ cview_type2 const,
+ Reverse2 ? iterate_reverse : iterate_forward
+ >::type view_type2;
+
+ typedef typename boost::range_iterator
+ <
+ view_type1 const
+ >::type range1_iterator;
+
+ typedef typename boost::range_iterator
+ <
+ view_type2 const
+ >::type range2_iterator;
+
+
+ template <typename Geometry, typename Section>
+ static inline bool neighbouring(Section const& section,
+ int index1, int index2)
+ {
+ // About n-2:
+ // (square: range_count=5, indices 0,1,2,3
+ // -> 0-3 are adjacent, don't check on intersections)
+ // Also tested for open polygons, and/or duplicates
+ // About first condition: will be optimized by compiler (static)
+ // It checks if it is areal (box,ring,(multi)polygon
+ int const n = int(section.range_count);
+ return boost::is_same
+ <
+ typename tag_cast
+ <
+ typename geometry::point_type<Geometry1>::type,
+ areal_tag
+ >::type,
+ areal_tag
+ >::value
+ && index1 == 0
+ && index2 >= n - 2
+ ;
+ }
+
+
+public :
+ // Returns true if terminated, false if interrupted
+ static inline bool apply(
+ int source_id1, Geometry1 const& geometry1, Section1 const& sec1,
+ int source_id2, Geometry2 const& geometry2, Section2 const& sec2,
+ bool skip_larger,
+ Turns& turns,
+ InterruptPolicy& interrupt_policy)
+ {
+ cview_type1 cview1(range_by_section(geometry1, sec1));
+ cview_type2 cview2(range_by_section(geometry2, sec2));
+ view_type1 view1(cview1);
+ view_type2 view2(cview2);
+
+ range1_iterator begin_range_1 = boost::begin(view1);
+ range1_iterator end_range_1 = boost::end(view1);
+
+ range2_iterator begin_range_2 = boost::begin(view2);
+ range2_iterator end_range_2 = boost::end(view2);
+
+ int const dir1 = sec1.directions[0];
+ int const dir2 = sec2.directions[0];
+ int index1 = sec1.begin_index;
+ int ndi1 = sec1.non_duplicate_index;
+
+ bool const same_source =
+ source_id1 == source_id2
+ && sec1.ring_id.multi_index == sec2.ring_id.multi_index
+ && sec1.ring_id.ring_index == sec2.ring_id.ring_index;
+
+ range1_iterator prev1, it1, end1;
+
+ get_start_point_iterator(sec1, view1, prev1, it1, end1,
+ index1, ndi1, dir1, sec2.bounding_box);
+
+ // We need a circular iterator because it might run through the closing point.
+ // One circle is actually enough but this one is just convenient.
+ ever_circling_iterator<range1_iterator> next1(begin_range_1, end_range_1, it1, true);
+ next1++;
+
+ // Walk through section and stop if we exceed the other box
+ // section 2: [--------------]
+ // section 1: |----|---|---|---|---|
+ for (prev1 = it1++, next1++;
+ it1 != end1 && ! exceeding<0>(dir1, *prev1, sec2.bounding_box);
+ ++prev1, ++it1, ++index1, ++next1, ++ndi1)
+ {
+ ever_circling_iterator<range1_iterator> nd_next1(
+ begin_range_1, end_range_1, next1, true);
+ advance_to_non_duplicate_next(nd_next1, it1, sec1);
+
+ int index2 = sec2.begin_index;
+ int ndi2 = sec2.non_duplicate_index;
+
+ range2_iterator prev2, it2, end2;
+
+ get_start_point_iterator(sec2, view2, prev2, it2, end2,
+ index2, ndi2, dir2, sec1.bounding_box);
+ ever_circling_iterator<range2_iterator> next2(begin_range_2, end_range_2, it2, true);
+ next2++;
+
+ for (prev2 = it2++, next2++;
+ it2 != end2 && ! exceeding<0>(dir2, *prev2, sec1.bounding_box);
+ ++prev2, ++it2, ++index2, ++next2, ++ndi2)
+ {
+ bool skip = same_source;
+ if (skip)
+ {
+ // If sources are the same (possibly self-intersecting):
+ // skip if it is a neighbouring segment.
+ // (including first-last segment
+ // and two segments with one or more degenerate/duplicate
+ // (zero-length) segments in between)
+
+ // Also skip if index1 < index2 to avoid getting all
+ // intersections twice (only do this on same source!)
+
+ skip = (skip_larger && index1 >= index2)
+ || ndi2 == ndi1 + 1
+ || neighbouring<Geometry1>(sec1, index1, index2)
+ ;
+ }
+
+ if (! skip)
+ {
+ // Move to the "non duplicate next"
+ ever_circling_iterator<range2_iterator> nd_next2(
+ begin_range_2, end_range_2, next2, true);
+ advance_to_non_duplicate_next(nd_next2, it2, sec2);
+
+ typedef typename boost::range_value<Turns>::type turn_info;
+ typedef typename turn_info::point_type ip;
+
+ turn_info ti;
+ ti.operations[0].seg_id = segment_identifier(source_id1,
+ sec1.ring_id.multi_index, sec1.ring_id.ring_index, index1),
+ ti.operations[1].seg_id = segment_identifier(source_id2,
+ sec2.ring_id.multi_index, sec2.ring_id.ring_index, index2),
+
+ ti.operations[0].other_id = ti.operations[1].seg_id;
+ ti.operations[1].other_id = ti.operations[0].seg_id;
+
+ std::size_t const size_before = boost::size(turns);
+
+ TurnPolicy::apply(*prev1, *it1, *nd_next1, *prev2, *it2, *nd_next2,
+ ti, std::back_inserter(turns));
+
+ if (InterruptPolicy::enabled)
+ {
+ if (interrupt_policy.apply(
+ std::make_pair(boost::begin(turns) + size_before,
+ boost::end(turns))))
+ {
+ return false;
+ }
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+
+private :
+ typedef typename geometry::point_type<Geometry1>::type point1_type;
+ typedef typename geometry::point_type<Geometry2>::type point2_type;
+ typedef typename model::referring_segment<point1_type const> segment1_type;
+ typedef typename model::referring_segment<point2_type const> segment2_type;
+
+
+ template <size_t Dim, typename Point, typename Box>
+ static inline bool preceding(int dir, Point const& point, Box const& box)
+ {
+ return (dir == 1 && get<Dim>(point) < get<min_corner, Dim>(box))
+ || (dir == -1 && get<Dim>(point) > get<max_corner, Dim>(box));
+ }
+
+ template <size_t Dim, typename Point, typename Box>
+ static inline bool exceeding(int dir, Point const& point, Box const& box)
+ {
+ return (dir == 1 && get<Dim>(point) > get<max_corner, Dim>(box))
+ || (dir == -1 && get<Dim>(point) < get<min_corner, Dim>(box));
+ }
+
+ template <typename Iterator, typename RangeIterator, typename Section>
+ static inline void advance_to_non_duplicate_next(Iterator& next,
+ RangeIterator const& it, Section const& section)
+ {
+ // To see where the next segments bend to, in case of touch/intersections
+ // on end points, we need (in case of degenerate/duplicate points) an extra
+ // iterator which moves to the REAL next point, so non duplicate.
+ // This needs an extra comparison (disjoint).
+ // (Note that within sections, non duplicate points are already asserted,
+ // by the sectionalize process).
+
+ // So advance to the "non duplicate next"
+ // (the check is defensive, to avoid endless loops)
+ std::size_t check = 0;
+ while(! detail::disjoint::disjoint_point_point(*it, *next)
+ && check++ < section.range_count)
+ {
+ next++;
+ }
+ }
+
+ // It is NOT possible to have section-iterators here
+ // because of the logistics of "index" (the section-iterator automatically
+ // skips to the begin-point, we loose the index or have to recalculate it)
+ // So we mimic it here
+ template <typename Range, typename Section, typename Box>
+ static inline void get_start_point_iterator(Section & section,
+ Range const& range,
+ typename boost::range_iterator<Range const>::type& it,
+ typename boost::range_iterator<Range const>::type& prev,
+ typename boost::range_iterator<Range const>::type& end,
+ int& index, int& ndi,
+ int dir, Box const& other_bounding_box)
+ {
+ it = boost::begin(range) + section.begin_index;
+ end = boost::begin(range) + section.end_index + 1;
+
+ // Mimic section-iterator:
+ // Skip to point such that section interects other box
+ prev = it++;
+ for(; it != end && preceding<0>(dir, *it, other_bounding_box);
+ prev = it++, index++, ndi++)
+ {}
+ // Go back one step because we want to start completely preceding
+ it = prev;
+ }
+};
+
+struct get_section_box
+{
+ template <typename Box, typename InputItem>
+ static inline void apply(Box& total, InputItem const& item)
+ {
+ geometry::expand(total, item.bounding_box);
+ }
+};
+
+struct ovelaps_section_box
+{
+ template <typename Box, typename InputItem>
+ static inline bool apply(Box const& box, InputItem const& item)
+ {
+ return ! detail::disjoint::disjoint_box_box(box, item.bounding_box);
+ }
+};
+
+template
+<
+ typename Geometry1, typename Geometry2,
+ bool Reverse1, bool Reverse2,
+ typename Turns,
+ typename TurnPolicy,
+ typename InterruptPolicy
+>
+struct section_visitor
+{
+ int m_source_id1;
+ Geometry1 const& m_geometry1;
+ int m_source_id2;
+ Geometry2 const& m_geometry2;
+ Turns& m_turns;
+ InterruptPolicy& m_interrupt_policy;
+
+ section_visitor(int id1, Geometry1 const& g1,
+ int id2, Geometry2 const& g2,
+ Turns& turns, InterruptPolicy& ip)
+ : m_source_id1(id1), m_geometry1(g1)
+ , m_source_id2(id2), m_geometry2(g2)
+ , m_turns(turns)
+ , m_interrupt_policy(ip)
+ {}
+
+ template <typename Section>
+ inline bool apply(Section const& sec1, Section const& sec2)
+ {
+ if (! detail::disjoint::disjoint_box_box(sec1.bounding_box, sec2.bounding_box))
+ {
+ return get_turns_in_sections
+ <
+ Geometry1,
+ Geometry2,
+ Reverse1, Reverse2,
+ Section, Section,
+ Turns,
+ TurnPolicy,
+ InterruptPolicy
+ >::apply(
+ m_source_id1, m_geometry1, sec1,
+ m_source_id2, m_geometry2, sec2,
+ false,
+ m_turns, m_interrupt_policy);
+ }
+ return true;
+ }
+
+};
+
+template
+<
+ typename Geometry1, typename Geometry2,
+ bool Reverse1, bool Reverse2,
+ typename Turns,
+ typename TurnPolicy,
+ typename InterruptPolicy
+>
+class get_turns_generic
+{
+
+public:
+ static inline void apply(
+ int source_id1, Geometry1 const& geometry1,
+ int source_id2, Geometry2 const& geometry2,
+ Turns& turns, InterruptPolicy& interrupt_policy)
+ {
+ // First create monotonic sections...
+ typedef typename boost::range_value<Turns>::type ip_type;
+ typedef typename ip_type::point_type point_type;
+ typedef model::box<point_type> box_type;
+ typedef typename geometry::sections<box_type, 2> sections_type;
+
+ sections_type sec1, sec2;
+
+ geometry::sectionalize<Reverse1>(geometry1, sec1, 0);
+ geometry::sectionalize<Reverse2>(geometry2, sec2, 1);
+
+ // ... and then partition them, intersecting overlapping sections in visitor method
+ section_visitor
+ <
+ Geometry1, Geometry2,
+ Reverse1, Reverse2,
+ Turns, TurnPolicy, InterruptPolicy
+ > visitor(source_id1, geometry1, source_id2, geometry2, turns, interrupt_policy);
+
+ geometry::partition
+ <
+ box_type, get_section_box, ovelaps_section_box
+ >::apply(sec1, sec2, visitor);
+ }
+};
+
+
+// Get turns for a range with a box, following Cohen-Sutherland (cs) approach
+template
+<
+ typename Range, typename Box,
+ bool ReverseRange, bool ReverseBox,
+ typename Turns,
+ typename TurnPolicy,
+ typename InterruptPolicy
+>
+struct get_turns_cs
+{
+ typedef typename boost::range_value<Turns>::type turn_info;
+ typedef typename geometry::point_type<Range>::type point_type;
+ typedef typename geometry::point_type<Box>::type box_point_type;
+
+ typedef typename closeable_view
+ <
+ Range const,
+ closure<Range>::value
+ >::type cview_type;
+
+ typedef typename reversible_view
+ <
+ cview_type const,
+ ReverseRange ? iterate_reverse : iterate_forward
+ >::type view_type;
+
+ typedef typename boost::range_iterator
+ <
+ view_type const
+ >::type iterator_type;
+
+
+ static inline void apply(
+ int source_id1, Range const& range,
+ int source_id2, Box const& box,
+ Turns& turns,
+ InterruptPolicy& ,
+ int multi_index = -1, int ring_index = -1)
+ {
+ if (boost::size(range) <= 1)
+ {
+ return;
+ }
+
+ boost::array<box_point_type,4> bp;
+ assign_box_corners_oriented<ReverseBox>(box, bp);
+
+ cview_type cview(range);
+ view_type view(cview);
+
+ iterator_type it = boost::begin(view);
+
+ ever_circling_iterator<iterator_type> next(
+ boost::begin(view), boost::end(view), it, true);
+ next++;
+ next++;
+
+ //bool first = true;
+
+ //char previous_side[2] = {0, 0};
+
+ int index = 0;
+
+ for (iterator_type prev = it++;
+ it != boost::end(view);
+ prev = it++, next++, index++)
+ {
+ segment_identifier seg_id(source_id1,
+ multi_index, ring_index, index);
+
+ /*if (first)
+ {
+ previous_side[0] = get_side<0>(box, *prev);
+ previous_side[1] = get_side<1>(box, *prev);
+ }
+
+ char current_side[2];
+ current_side[0] = get_side<0>(box, *it);
+ current_side[1] = get_side<1>(box, *it);
+
+ // There can NOT be intersections if
+ // 1) EITHER the two points are lying on one side of the box (! 0 && the same)
+ // 2) OR same in Y-direction
+ // 3) OR all points are inside the box (0)
+ if (! (
+ (current_side[0] != 0 && current_side[0] == previous_side[0])
+ || (current_side[1] != 0 && current_side[1] == previous_side[1])
+ || (current_side[0] == 0
+ && current_side[1] == 0
+ && previous_side[0] == 0
+ && previous_side[1] == 0)
+ )
+ )*/
+ if (true)
+ {
+ get_turns_with_box(seg_id, source_id2,
+ *prev, *it, *next,
+ bp[0], bp[1], bp[2], bp[3],
+ turns);
+ // Future performance enhancement:
+ // return if told by the interrupt policy
+ }
+ }
+ }
+
+private:
+ template<std::size_t Index, typename Point>
+ static inline int get_side(Box const& box, Point const& point)
+ {
+ // Inside -> 0
+ // Outside -> -1 (left/below) or 1 (right/above)
+ // On border -> -2 (left/lower) or 2 (right/upper)
+ // The only purpose of the value is to not be the same,
+ // and to denote if it is inside (0)
+
+ typename coordinate_type<Point>::type const& c = get<Index>(point);
+ typename coordinate_type<Box>::type const& left = get<min_corner, Index>(box);
+ typename coordinate_type<Box>::type const& right = get<max_corner, Index>(box);
+
+ if (geometry::math::equals(c, left)) return -2;
+ else if (geometry::math::equals(c, right)) return 2;
+ else if (c < left) return -1;
+ else if (c > right) return 1;
+ else return 0;
+ }
+
+ static inline void get_turns_with_box(segment_identifier const& seg_id, int source_id2,
+ // Points from a range:
+ point_type const& rp0,
+ point_type const& rp1,
+ point_type const& rp2,
+ // Points from the box
+ box_point_type const& bp0,
+ box_point_type const& bp1,
+ box_point_type const& bp2,
+ box_point_type const& bp3,
+ // Output
+ Turns& turns)
+ {
+ // Depending on code some relations can be left out
+
+ typedef typename boost::range_value<Turns>::type turn_info;
+
+ turn_info ti;
+ ti.operations[0].seg_id = seg_id;
+ ti.operations[0].other_id = ti.operations[1].seg_id;
+ ti.operations[1].other_id = seg_id;
+
+ ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 0);
+ TurnPolicy::apply(rp0, rp1, rp2, bp0, bp1, bp2,
+ ti, std::back_inserter(turns));
+
+ ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 1);
+ TurnPolicy::apply(rp0, rp1, rp2, bp1, bp2, bp3,
+ ti, std::back_inserter(turns));
+
+ ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 2);
+ TurnPolicy::apply(rp0, rp1, rp2, bp2, bp3, bp0,
+ ti, std::back_inserter(turns));
+
+ ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 3);
+ TurnPolicy::apply(rp0, rp1, rp2, bp3, bp0, bp1,
+ ti, std::back_inserter(turns));
+ }
+
+};
+
+
+template
+<
+ typename Polygon, typename Box,
+ bool Reverse, bool ReverseBox,
+ typename Turns,
+ typename TurnPolicy,
+ typename InterruptPolicy
+>
+struct get_turns_polygon_cs
+{
+ static inline void apply(
+ int source_id1, Polygon const& polygon,
+ int source_id2, Box const& box,
+ Turns& turns, InterruptPolicy& interrupt_policy,
+ int multi_index = -1)
+ {
+ typedef typename geometry::ring_type<Polygon>::type ring_type;
+
+ typedef detail::get_turns::get_turns_cs
+ <
+ ring_type, Box,
+ Reverse, ReverseBox,
+ Turns,
+ TurnPolicy,
+ InterruptPolicy
+ > intersector_type;
+
+ intersector_type::apply(
+ source_id1, geometry::exterior_ring(polygon),
+ source_id2, box, turns, interrupt_policy,
+ multi_index, -1);
+
+ int i = 0;
+
+ typename interior_return_type<Polygon const>::type rings
+ = interior_rings(polygon);
+ for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings);
+ ++it, ++i)
+ {
+ intersector_type::apply(
+ source_id1, *it,
+ source_id2, box, turns, interrupt_policy,
+ multi_index, i);
+ }
+
+ }
+};
+
+}} // namespace detail::get_turns
+#endif // DOXYGEN_NO_DETAIL
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+// Because this is "detail" method, and most implementations will use "generic",
+// we take the freedom to derive it from "generic".
+template
+<
+ typename GeometryTag1, typename GeometryTag2,
+ typename Geometry1, typename Geometry2,
+ bool Reverse1, bool Reverse2,
+ typename Turns,
+ typename TurnPolicy,
+ typename InterruptPolicy
+>
+struct get_turns
+ : detail::get_turns::get_turns_generic
+ <
+ Geometry1, Geometry2,
+ Reverse1, Reverse2,
+ Turns,
+ TurnPolicy,
+ InterruptPolicy
+ >
+{};
+
+
+template
+<
+ typename Polygon, typename Box,
+ bool ReversePolygon, bool ReverseBox,
+ typename Turns,
+ typename TurnPolicy,
+ typename InterruptPolicy
+>
+struct get_turns
+ <
+ polygon_tag, box_tag,
+ Polygon, Box,
+ ReversePolygon, ReverseBox,
+ Turns,
+ TurnPolicy,
+ InterruptPolicy
+ > : detail::get_turns::get_turns_polygon_cs
+ <
+ Polygon, Box,
+ ReversePolygon, ReverseBox,
+ Turns, TurnPolicy, InterruptPolicy
+ >
+{};
+
+
+template
+<
+ typename Ring, typename Box,
+ bool ReverseRing, bool ReverseBox,
+ typename Turns,
+ typename TurnPolicy,
+ typename InterruptPolicy
+>
+struct get_turns
+ <
+ ring_tag, box_tag,
+ Ring, Box,
+ ReverseRing, ReverseBox,
+ Turns,
+ TurnPolicy,
+ InterruptPolicy
+ > : detail::get_turns::get_turns_cs
+ <
+ Ring, Box, ReverseRing, ReverseBox,
+ Turns, TurnPolicy, InterruptPolicy
+ >
+
+{};
+
+
+template
+<
+ typename GeometryTag1, typename GeometryTag2,
+ typename Geometry1, typename Geometry2,
+ bool Reverse1, bool Reverse2,
+ typename Turns,
+ typename TurnPolicy,
+ typename InterruptPolicy
+>
+struct get_turns_reversed
+{
+ static inline void apply(
+ int source_id1, Geometry1 const& g1,
+ int source_id2, Geometry2 const& g2,
+ Turns& turns, InterruptPolicy& interrupt_policy)
+ {
+ get_turns
+ <
+ GeometryTag2, GeometryTag1,
+ Geometry2, Geometry1,
+ Reverse2, Reverse1,
+ Turns, TurnPolicy,
+ InterruptPolicy
+ >::apply(source_id2, g2, source_id1, g1, turns, interrupt_policy);
+ }
+};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+
+/*!
+\brief \brief_calc2{turn points}
+\ingroup overlay
+\tparam Geometry1 \tparam_geometry
+\tparam Geometry2 \tparam_geometry
+\tparam Turns type of turn-container (e.g. vector of "intersection/turn point"'s)
+\param geometry1 \param_geometry
+\param geometry2 \param_geometry
+\param turns container which will contain turn points
+\param interrupt_policy policy determining if process is stopped
+ when intersection is found
+ */
+template
+<
+ bool Reverse1, bool Reverse2,
+ typename AssignPolicy,
+ typename Geometry1,
+ typename Geometry2,
+ typename Turns,
+ typename InterruptPolicy
+>
+inline void get_turns(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Turns& turns,
+ InterruptPolicy& interrupt_policy)
+{
+ concept::check_concepts_and_equal_dimensions<Geometry1 const, Geometry2 const>();
+
+ typedef typename strategy_intersection
+ <
+ typename cs_tag<Geometry1>::type,
+ Geometry1,
+ Geometry2,
+ typename boost::range_value<Turns>::type
+ >::segment_intersection_strategy_type segment_intersection_strategy_type;
+
+ typedef detail::overlay::get_turn_info
+ <
+ typename point_type<Geometry1>::type,
+ typename point_type<Geometry2>::type,
+ typename boost::range_value<Turns>::type,
+ AssignPolicy
+ > TurnPolicy;
+
+ boost::mpl::if_c
+ <
+ reverse_dispatch<Geometry1, Geometry2>::type::value,
+ dispatch::get_turns_reversed
+ <
+ typename tag<Geometry1>::type,
+ typename tag<Geometry2>::type,
+ Geometry1, Geometry2,
+ Reverse1, Reverse2,
+ Turns, TurnPolicy,
+ InterruptPolicy
+ >,
+ dispatch::get_turns
+ <
+ typename tag<Geometry1>::type,
+ typename tag<Geometry2>::type,
+ Geometry1, Geometry2,
+ Reverse1, Reverse2,
+ Turns, TurnPolicy,
+ InterruptPolicy
+ >
+ >::type::apply(
+ 0, geometry1,
+ 1, geometry2,
+ turns, interrupt_policy);
+}
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURNS_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp b/boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp
new file mode 100644
index 0000000000..1e878ca525
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp
@@ -0,0 +1,672 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_HANDLE_TANGENCIES_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_HANDLE_TANGENCIES_HPP
+
+#include <algorithm>
+
+#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
+#include <boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp>
+#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+
+#include <boost/geometry/geometries/segment.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+
+template
+<
+ typename TurnPoints,
+ typename Indexed,
+ typename Geometry1, typename Geometry2,
+ bool Reverse1, bool Reverse2,
+ typename Strategy
+>
+struct sort_in_cluster
+{
+ inline sort_in_cluster(TurnPoints const& turn_points
+ , Geometry1 const& geometry1
+ , Geometry2 const& geometry2
+ , Strategy const& strategy)
+ : m_turn_points(turn_points)
+ , m_geometry1(geometry1)
+ , m_geometry2(geometry2)
+ , m_strategy(strategy)
+ {}
+
+private :
+
+ TurnPoints const& m_turn_points;
+ Geometry1 const& m_geometry1;
+ Geometry2 const& m_geometry2;
+ Strategy const& m_strategy;
+
+ typedef typename Indexed::type turn_operation_type;
+ typedef typename geometry::point_type<Geometry1>::type point_type;
+ typedef model::referring_segment<point_type const> segment_type;
+
+ // Determine how p/r and p/s are located.
+ template <typename P>
+ static inline void overlap_info(P const& pi, P const& pj,
+ P const& ri, P const& rj,
+ P const& si, P const& sj,
+ bool& pr_overlap, bool& ps_overlap, bool& rs_overlap)
+ {
+ // Determine how p/r and p/s are located.
+ // One of them is coming from opposite direction.
+
+ typedef strategy::intersection::relate_cartesian_segments
+ <
+ policies::relate::segments_intersection_points
+ <
+ segment_type,
+ segment_type,
+ segment_intersection_points<point_type>
+ >
+ > policy;
+
+ segment_type p(pi, pj);
+ segment_type r(ri, rj);
+ segment_type s(si, sj);
+
+ // Get the intersection point (or two points)
+ segment_intersection_points<point_type> pr = policy::apply(p, r);
+ segment_intersection_points<point_type> ps = policy::apply(p, s);
+ segment_intersection_points<point_type> rs = policy::apply(r, s);
+
+ // Check on overlap
+ pr_overlap = pr.count == 2;
+ ps_overlap = ps.count == 2;
+ rs_overlap = rs.count == 2;
+ }
+
+
+#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
+ inline void debug_consider(int order, Indexed const& left,
+ Indexed const& right, std::string const& header,
+ bool skip = true,
+ std::string const& extra = "", bool ret = false
+ ) const
+ {
+ if (skip) return;
+
+ point_type pi, pj, ri, rj, si, sj;
+ geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
+ left.subject.seg_id,
+ pi, pj);
+ geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
+ left.subject.other_id,
+ ri, rj);
+ geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
+ right.subject.other_id,
+ si, sj);
+
+ bool prc = false, psc = false, rsc = false;
+ overlap_info(pi, pj, ri, rj, si, sj, prc, psc, rsc);
+
+ int const side_ri_p = m_strategy.apply(pi, pj, ri);
+ int const side_rj_p = m_strategy.apply(pi, pj, rj);
+ int const side_si_p = m_strategy.apply(pi, pj, si);
+ int const side_sj_p = m_strategy.apply(pi, pj, sj);
+ int const side_si_r = m_strategy.apply(ri, rj, si);
+ int const side_sj_r = m_strategy.apply(ri, rj, sj);
+
+ std::cout << "Case: " << header << " for " << left.index << " / " << right.index << std::endl;
+#ifdef BOOST_GEOMETRY_DEBUG_ENRICH_MORE
+ std::cout << " Segment p:" << geometry::wkt(pi) << " .. " << geometry::wkt(pj) << std::endl;
+ std::cout << " Segment r:" << geometry::wkt(ri) << " .. " << geometry::wkt(rj) << std::endl;
+ std::cout << " Segment s:" << geometry::wkt(si) << " .. " << geometry::wkt(sj) << std::endl;
+
+ std::cout << " r//p: " << side_ri_p << " / " << side_rj_p << std::endl;
+ std::cout << " s//p: " << side_si_p << " / " << side_sj_p << std::endl;
+ std::cout << " s//r: " << side_si_r << " / " << side_sj_r << std::endl;
+#endif
+
+ std::cout << header
+ //<< " order: " << order
+ << " ops: " << operation_char(left.subject.operation)
+ << "/" << operation_char(right.subject.operation)
+ << " ri//p: " << side_ri_p
+ << " si//p: " << side_si_p
+ << " si//r: " << side_si_r
+ << " cnts: " << int(prc) << "," << int(psc) << "," << int(rsc)
+ //<< " idx: " << left.index << "/" << right.index
+ ;
+
+ if (! extra.empty())
+ {
+ std::cout << " " << extra << " " << (ret ? "true" : "false");
+ }
+ std::cout << std::endl;
+ }
+#else
+ inline void debug_consider(int, Indexed const& ,
+ Indexed const& , std::string const& ,
+ bool = true,
+ std::string const& = "", bool = false
+ ) const
+ {}
+#endif
+
+
+ // ux/ux
+ inline bool consider_ux_ux(Indexed const& left,
+ Indexed const& right
+ , std::string const& // header
+ ) const
+ {
+ bool ret = left.index < right.index;
+
+ // In combination of u/x, x/u: take first union, then blocked.
+ // Solves #88, #61, #56, #80
+ if (left.subject.operation == operation_union
+ && right.subject.operation == operation_blocked)
+ {
+ ret = true;
+ }
+ else if (left.subject.operation == operation_blocked
+ && right.subject.operation == operation_union)
+ {
+ ret = false;
+ }
+ else
+ {
+#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
+ std::cout << "ux/ux unhandled" << std::endl;
+#endif
+ }
+
+ //debug_consider(0, left, right, header, false, "-> return ", ret);
+
+ return ret;
+ }
+
+ inline bool consider_iu_ux(Indexed const& left,
+ Indexed const& right,
+ int order // 1: iu first, -1: ux first
+ , std::string const& // header
+ ) const
+ {
+ bool ret = false;
+
+ if (left.subject.operation == operation_union
+ && right.subject.operation == operation_union)
+ {
+ ret = order == 1;
+ }
+ else if (left.subject.operation == operation_union
+ && right.subject.operation == operation_blocked)
+ {
+ ret = true;
+ }
+ else if (right.subject.operation == operation_union
+ && left.subject.operation == operation_blocked)
+ {
+ ret = false;
+ }
+ else if (left.subject.operation == operation_union)
+ {
+ ret = true;
+ }
+ else if (right.subject.operation == operation_union)
+ {
+ ret = false;
+ }
+ else
+ {
+#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
+ // this still happens in the traverse.cpp test
+ std::cout << " iu/ux unhandled" << std::endl;
+#endif
+ ret = order == 1;
+ }
+
+ //debug_consider(0, left, right, header, false, "-> return", ret);
+ return ret;
+ }
+
+ inline bool consider_iu_ix(Indexed const& left,
+ Indexed const& right,
+ int order // 1: iu first, -1: ix first
+ , std::string const& // header
+ ) const
+ {
+ //debug_consider(order, left, right, header, false, "iu/ix");
+
+ return left.subject.operation == operation_intersection
+ && right.subject.operation == operation_intersection ? order == 1
+ : left.subject.operation == operation_intersection ? false
+ : right.subject.operation == operation_intersection ? true
+ : order == 1;
+ }
+
+
+ inline bool consider_iu_iu(Indexed const& left, Indexed const& right,
+ std::string const& header) const
+ {
+ //debug_consider(0, left, right, header);
+
+ // In general, order it like "union, intersection".
+ if (left.subject.operation == operation_intersection
+ && right.subject.operation == operation_union)
+ {
+ //debug_consider(0, left, right, header, false, "i,u", false);
+ return false;
+ }
+ else if (left.subject.operation == operation_union
+ && right.subject.operation == operation_intersection)
+ {
+ //debug_consider(0, left, right, header, false, "u,i", true);
+ return true;
+ }
+
+ point_type pi, pj, ri, rj, si, sj;
+ geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
+ left.subject.seg_id,
+ pi, pj);
+ geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
+ left.subject.other_id,
+ ri, rj);
+ geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
+ right.subject.other_id,
+ si, sj);
+
+ int const side_ri_p = m_strategy.apply(pi, pj, ri);
+ int const side_si_p = m_strategy.apply(pi, pj, si);
+ int const side_si_r = m_strategy.apply(ri, rj, si);
+
+ // Both located at same side (#58, pie_21_7_21_0_3)
+ if (side_ri_p * side_si_p == 1 && side_si_r != 0)
+ {
+ // Take the most left one
+ if (left.subject.operation == operation_union
+ && right.subject.operation == operation_union)
+ {
+ bool ret = side_si_r == 1;
+ //debug_consider(0, left, right, header, false, "same side", ret);
+ return ret;
+ }
+ }
+
+
+ // Coming from opposite sides (#59, #99)
+ if (side_ri_p * side_si_p == -1)
+ {
+ bool ret = false;
+
+ {
+ ret = side_ri_p == 1; // #100
+ debug_consider(0, left, right, header, false, "opp.", ret);
+ return ret;
+ }
+#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
+ std::cout << " iu/iu coming from opposite unhandled" << std::endl;
+#endif
+ }
+
+ // We need EXTRA information here: are p/r/s overlapping?
+ bool pr_ov = false, ps_ov = false, rs_ov = false;
+ overlap_info(pi, pj, ri, rj, si, sj, pr_ov, ps_ov, rs_ov);
+
+ // One coming from right (#83,#90)
+ // One coming from left (#90, #94, #95)
+ if (side_si_r != 0 && (side_ri_p != 0 || side_si_p != 0))
+ {
+ bool ret = false;
+
+ if (pr_ov || ps_ov)
+ {
+ int r = side_ri_p != 0 ? side_ri_p : side_si_p;
+ ret = r * side_si_r == 1;
+ }
+ else
+ {
+ ret = side_si_r == 1;
+ }
+
+ debug_consider(0, left, right, header, false, "left or right", ret);
+ return ret;
+ }
+
+ // All aligned (#92, #96)
+ if (side_ri_p == 0 && side_si_p == 0 && side_si_r == 0)
+ {
+ // One of them is coming from opposite direction.
+
+ // Take the one NOT overlapping
+ bool ret = false;
+ bool found = false;
+ if (pr_ov && ! ps_ov)
+ {
+ ret = true;
+ found = true;
+ }
+ else if (!pr_ov && ps_ov)
+ {
+ ret = false;
+ found = true;
+ }
+
+ debug_consider(0, left, right, header, false, "aligned", ret);
+ if (found)
+ {
+ return ret;
+ }
+ }
+
+#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
+ std::cout << " iu/iu unhandled" << std::endl;
+ debug_consider(0, left, right, header, false, "unhandled", left.index < right.index);
+#endif
+ return left.index < right.index;
+ }
+
+ inline bool consider_ii(Indexed const& left, Indexed const& right,
+ std::string const& header) const
+ {
+ debug_consider(0, left, right, header);
+
+ point_type pi, pj, ri, rj, si, sj;
+ geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
+ left.subject.seg_id,
+ pi, pj);
+ geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
+ left.subject.other_id,
+ ri, rj);
+ geometry::copy_segment_points<Reverse1, Reverse2>(m_geometry1, m_geometry2,
+ right.subject.other_id,
+ si, sj);
+
+ int const side_ri_p = m_strategy.apply(pi, pj, ri);
+ int const side_si_p = m_strategy.apply(pi, pj, si);
+
+ // Two other points are (mostly) lying both right of the considered segment
+ // Take the most left one
+ int const side_si_r = m_strategy.apply(ri, rj, si);
+ if (side_ri_p == -1
+ && side_si_p == -1
+ && side_si_r != 0)
+ {
+ bool const ret = side_si_r != 1;
+ return ret;
+ }
+ return left.index < right.index;
+ }
+
+
+public :
+ inline bool operator()(Indexed const& left, Indexed const& right) const
+ {
+ bool const default_order = left.index < right.index;
+
+ if ((m_turn_points[left.index].discarded || left.discarded)
+ && (m_turn_points[right.index].discarded || right.discarded))
+ {
+ return default_order;
+ }
+ else if (m_turn_points[left.index].discarded || left.discarded)
+ {
+ // Be careful to sort discarded first, then all others
+ return true;
+ }
+ else if (m_turn_points[right.index].discarded || right.discarded)
+ {
+ // See above so return false here such that right (discarded)
+ // is sorted before left (not discarded)
+ return false;
+ }
+ else if (m_turn_points[left.index].combination(operation_blocked, operation_union)
+ && m_turn_points[right.index].combination(operation_blocked, operation_union))
+ {
+ // ux/ux
+ return consider_ux_ux(left, right, "ux/ux");
+ }
+ else if (m_turn_points[left.index].both(operation_union)
+ && m_turn_points[right.index].both(operation_union))
+ {
+ // uu/uu, Order is arbitrary
+ // Note: uu/uu is discarded now before so this point will
+ // not be reached.
+ return default_order;
+ }
+ else if (m_turn_points[left.index].combination(operation_intersection, operation_union)
+ && m_turn_points[right.index].combination(operation_intersection, operation_union))
+ {
+ return consider_iu_iu(left, right, "iu/iu");
+ }
+ else if (m_turn_points[left.index].both(operation_intersection)
+ && m_turn_points[right.index].both(operation_intersection))
+ {
+ return consider_ii(left, right, "ii/ii");
+ }
+ else if (m_turn_points[left.index].combination(operation_union, operation_blocked)
+ && m_turn_points[right.index].combination(operation_intersection, operation_union))
+ {
+ return consider_iu_ux(left, right, -1, "ux/iu");
+ }
+ else if (m_turn_points[left.index].combination(operation_intersection, operation_union)
+ && m_turn_points[right.index].combination(operation_union, operation_blocked))
+ {
+ return consider_iu_ux(left, right, 1, "iu/ux");
+ }
+ else if (m_turn_points[left.index].combination(operation_intersection, operation_blocked)
+ && m_turn_points[right.index].combination(operation_intersection, operation_union))
+ {
+ return consider_iu_ix(left, right, 1, "ix/iu");
+ }
+ else if (m_turn_points[left.index].combination(operation_intersection, operation_union)
+ && m_turn_points[right.index].combination(operation_intersection, operation_blocked))
+ {
+ return consider_iu_ix(left, right, -1, "iu/ix");
+ }
+ else if (m_turn_points[left.index].method != method_equal
+ && m_turn_points[right.index].method == method_equal
+ )
+ {
+ // If one of them was EQUAL or CONTINUES, it should always come first
+ return false;
+ }
+ else if (m_turn_points[left.index].method == method_equal
+ && m_turn_points[right.index].method != method_equal
+ )
+ {
+ return true;
+ }
+
+ // Now we have no clue how to sort.
+
+#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
+ std::cout << " Consider: " << operation_char(m_turn_points[left.index].operations[0].operation)
+ << operation_char(m_turn_points[left.index].operations[1].operation)
+ << "/" << operation_char(m_turn_points[right.index].operations[0].operation)
+ << operation_char(m_turn_points[right.index].operations[1].operation)
+ << " " << " Take " << left.index << " < " << right.index
+ << std::cout;
+#endif
+
+ return default_order;
+ }
+};
+
+
+
+template
+<
+ typename IndexType,
+ typename Iterator,
+ typename TurnPoints,
+ typename Geometry1,
+ typename Geometry2,
+ typename Strategy
+>
+inline void inspect_cluster(Iterator begin_cluster, Iterator end_cluster,
+ TurnPoints& turn_points,
+ operation_type ,
+ Geometry1 const& , Geometry2 const& ,
+ Strategy const& )
+{
+ int count = 0;
+
+ // Make an analysis about all occuring cases here.
+ std::map<std::pair<operation_type, operation_type>, int> inspection;
+ for (Iterator it = begin_cluster; it != end_cluster; ++it)
+ {
+ operation_type first = turn_points[it->index].operations[0].operation;
+ operation_type second = turn_points[it->index].operations[1].operation;
+ if (first > second)
+ {
+ std::swap(first, second);
+ }
+ inspection[std::make_pair(first, second)]++;
+ count++;
+ }
+
+
+ bool keep_cc = false;
+
+ // Decide about which is going to be discarded here.
+ if (inspection[std::make_pair(operation_union, operation_union)] == 1
+ && inspection[std::make_pair(operation_continue, operation_continue)] == 1)
+ {
+ // In case of uu/cc, discard the uu, that indicates a tangency and
+ // inclusion would disturb the (e.g.) cc-cc-cc ordering
+ // NOTE: uu is now discarded anyhow.
+ keep_cc = true;
+ }
+ else if (count == 2
+ && inspection[std::make_pair(operation_intersection, operation_intersection)] == 1
+ && inspection[std::make_pair(operation_union, operation_intersection)] == 1)
+ {
+ // In case of ii/iu, discard the iu. The ii should always be visited,
+ // Because (in case of not discarding iu) correctly ordering of ii/iu appears impossible
+ for (Iterator it = begin_cluster; it != end_cluster; ++it)
+ {
+ if (turn_points[it->index].combination(operation_intersection, operation_union))
+ {
+ it->discarded = true;
+ }
+ }
+ }
+
+ // Discard any continue turn, unless it is the only thing left
+ // (necessary to avoid cc-only rings, all being discarded
+ // e.g. traversal case #75)
+ int nd_count= 0, cc_count = 0;
+ for (Iterator it = begin_cluster; it != end_cluster; ++it)
+ {
+ if (! it->discarded)
+ {
+ nd_count++;
+ if (turn_points[it->index].both(operation_continue))
+ {
+ cc_count++;
+ }
+ }
+ }
+
+ if (nd_count == cc_count)
+ {
+ keep_cc = true;
+ }
+
+ if (! keep_cc)
+ {
+ for (Iterator it = begin_cluster; it != end_cluster; ++it)
+ {
+ if (turn_points[it->index].both(operation_continue))
+ {
+ it->discarded = true;
+ }
+ }
+ }
+}
+
+
+template
+<
+ typename IndexType,
+ bool Reverse1, bool Reverse2,
+ typename Iterator,
+ typename TurnPoints,
+ typename Geometry1,
+ typename Geometry2,
+ typename Strategy
+>
+inline void handle_cluster(Iterator begin_cluster, Iterator end_cluster,
+ TurnPoints& turn_points,
+ operation_type for_operation,
+ Geometry1 const& geometry1, Geometry2 const& geometry2,
+ Strategy const& strategy)
+{
+ // First inspect and (possibly) discard rows
+ inspect_cluster<IndexType>(begin_cluster, end_cluster, turn_points,
+ for_operation, geometry1, geometry2, strategy);
+
+
+ // Then sort this range (discard rows will be ordered first and will be removed in enrich_assign)
+ std::sort(begin_cluster, end_cluster,
+ sort_in_cluster
+ <
+ TurnPoints,
+ IndexType,
+ Geometry1, Geometry2,
+ Reverse1, Reverse2,
+ Strategy
+ >(turn_points, geometry1, geometry2, strategy));
+
+
+#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
+ typedef typename IndexType::type operations_type;
+ operations_type const& op = turn_points[begin_cluster->index].operations[begin_cluster->operation_index];
+ std::cout << "Clustered points on equal distance " << op.enriched.distance << std::endl;
+ std::cout << "->Indexes ";
+
+ for (Iterator it = begin_cluster; it != end_cluster; ++it)
+ {
+ std::cout << " " << it->index;
+ }
+ std::cout << std::endl << "->Methods: ";
+ for (Iterator it = begin_cluster; it != end_cluster; ++it)
+ {
+ std::cout << " " << method_char(turn_points[it->index].method);
+ }
+ std::cout << std::endl << "->Operations: ";
+ for (Iterator it = begin_cluster; it != end_cluster; ++it)
+ {
+ std::cout << " " << operation_char(turn_points[it->index].operations[0].operation)
+ << operation_char(turn_points[it->index].operations[1].operation);
+ }
+ std::cout << std::endl << "->Discarded: ";
+ for (Iterator it = begin_cluster; it != end_cluster; ++it)
+ {
+ std::cout << " " << (it->discarded ? "true" : "false");
+ }
+ std::cout << std::endl;
+ //<< "\tOn segments: " << prev_op.seg_id << " / " << prev_op.other_id
+ //<< " and " << op.seg_id << " / " << op.other_id
+ //<< geometry::distance(turn_points[prev->index].point, turn_points[it->index].point)
+#endif
+
+}
+
+
+}} // namespace detail::overlay
+#endif //DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_HANDLE_TANGENCIES_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp b/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp
new file mode 100644
index 0000000000..8bca790d74
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp
@@ -0,0 +1,690 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_INTERSECTION_INSERT_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_INTERSECTION_INSERT_HPP
+
+
+#include <cstddef>
+
+#include <boost/mpl/if.hpp>
+#include <boost/mpl/assert.hpp>
+#include <boost/range/metafunctions.hpp>
+
+
+#include <boost/geometry/core/is_areal.hpp>
+#include <boost/geometry/core/point_order.hpp>
+#include <boost/geometry/core/reverse_dispatch.hpp>
+#include <boost/geometry/geometries/concepts/check.hpp>
+#include <boost/geometry/algorithms/convert.hpp>
+#include <boost/geometry/algorithms/detail/point_on_border.hpp>
+#include <boost/geometry/algorithms/detail/overlay/clip_linestring.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp>
+#include <boost/geometry/algorithms/detail/overlay/overlay.hpp>
+#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
+#include <boost/geometry/algorithms/detail/overlay/follow.hpp>
+#include <boost/geometry/views/segment_view.hpp>
+
+#if defined(BOOST_GEOMETRY_DEBUG_FOLLOW)
+#include <boost/foreach.hpp>
+#endif
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace intersection
+{
+
+template
+<
+ typename Segment1, typename Segment2,
+ typename OutputIterator, typename PointOut,
+ typename Strategy
+>
+struct intersection_segment_segment_point
+{
+ static inline OutputIterator apply(Segment1 const& segment1,
+ Segment2 const& segment2, OutputIterator out,
+ Strategy const& )
+ {
+ typedef typename point_type<PointOut>::type point_type;
+
+ // Get the intersection point (or two points)
+ segment_intersection_points<point_type> is
+ = strategy::intersection::relate_cartesian_segments
+ <
+ policies::relate::segments_intersection_points
+ <
+ Segment1,
+ Segment2,
+ segment_intersection_points<point_type>
+ >
+ >::apply(segment1, segment2);
+
+ for (std::size_t i = 0; i < is.count; i++)
+ {
+ PointOut p;
+ geometry::convert(is.intersections[i], p);
+ *out++ = p;
+ }
+ return out;
+ }
+};
+
+template
+<
+ typename Linestring1, typename Linestring2,
+ typename OutputIterator, typename PointOut,
+ typename Strategy
+>
+struct intersection_linestring_linestring_point
+{
+ static inline OutputIterator apply(Linestring1 const& linestring1,
+ Linestring2 const& linestring2, OutputIterator out,
+ Strategy const& )
+ {
+ typedef typename point_type<PointOut>::type point_type;
+
+ typedef detail::overlay::turn_info<point_type> turn_info;
+ std::deque<turn_info> turns;
+
+ geometry::get_intersection_points(linestring1, linestring2, turns);
+
+ for (typename boost::range_iterator<std::deque<turn_info> const>::type
+ it = boost::begin(turns); it != boost::end(turns); ++it)
+ {
+ PointOut p;
+ geometry::convert(it->point, p);
+ *out++ = p;
+ }
+ return out;
+ }
+};
+
+/*!
+\brief Version of linestring with an areal feature (polygon or multipolygon)
+*/
+template
+<
+ typename LineString, typename Areal,
+ bool ReverseAreal,
+ typename OutputIterator, typename LineStringOut,
+ overlay_type OverlayType,
+ typename Strategy
+>
+struct intersection_of_linestring_with_areal
+{
+ typedef detail::overlay::follow
+ <
+ LineStringOut,
+ LineString,
+ Areal,
+ OverlayType
+ > follower;
+
+#if defined(BOOST_GEOMETRY_DEBUG_FOLLOW)
+ template <typename Turn, typename Operation>
+ static inline void debug_follow(Turn const& turn, Operation op,
+ int index)
+ {
+ std::cout << index
+ << " at " << op.seg_id
+ << " meth: " << method_char(turn.method)
+ << " op: " << operation_char(op.operation)
+ << " vis: " << visited_char(op.visited)
+ << " of: " << operation_char(turn.operations[0].operation)
+ << operation_char(turn.operations[1].operation)
+ << " " << geometry::wkt(turn.point)
+ << std::endl;
+ }
+#endif
+
+ static inline OutputIterator apply(LineString const& linestring, Areal const& areal,
+ OutputIterator out,
+ Strategy const& )
+ {
+ if (boost::size(linestring) == 0)
+ {
+ return out;
+ }
+
+ typedef typename point_type<LineStringOut>::type point_type;
+
+ typedef detail::overlay::traversal_turn_info<point_type> turn_info;
+ std::deque<turn_info> turns;
+
+ detail::get_turns::no_interrupt_policy policy;
+ geometry::get_turns
+ <
+ false,
+ (OverlayType == overlay_intersection ? ReverseAreal : !ReverseAreal),
+ detail::overlay::calculate_distance_policy
+ >(linestring, areal, turns, policy);
+
+ if (turns.empty())
+ {
+ // No intersection points, it is either completely
+ // inside (interior + borders)
+ // or completely outside
+
+ // Use border point (on a segment) to check this
+ // (because turn points might skip some cases)
+ point_type border_point;
+ if (! geometry::point_on_border(border_point, linestring, true))
+ {
+ return out;
+ }
+
+
+ if (follower::included(border_point, areal))
+ {
+ LineStringOut copy;
+ geometry::convert(linestring, copy);
+ *out++ = copy;
+ }
+ return out;
+ }
+
+#if defined(BOOST_GEOMETRY_DEBUG_FOLLOW)
+ int index = 0;
+ BOOST_FOREACH(turn_info const& turn, turns)
+ {
+ debug_follow(turn, turn.operations[0], index++);
+ }
+#endif
+
+ return follower::apply
+ (
+ linestring, areal,
+ geometry::detail::overlay::operation_intersection,
+ turns, out
+ );
+ }
+};
+
+
+}} // namespace detail::intersection
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+template
+<
+ // tag dispatching:
+ typename TagIn1, typename TagIn2, typename TagOut,
+ // orientation
+ // metafunction finetuning helpers:
+ bool Areal1, bool Areal2, bool ArealOut,
+ // real types
+ typename Geometry1, typename Geometry2,
+ bool Reverse1, bool Reverse2, bool ReverseOut,
+ typename OutputIterator,
+ typename GeometryOut,
+ overlay_type OverlayType,
+ typename Strategy
+>
+struct intersection_insert
+{
+ BOOST_MPL_ASSERT_MSG
+ (
+ false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPES_OR_ORIENTATIONS
+ , (types<Geometry1, Geometry2, GeometryOut>)
+ );
+};
+
+
+template
+<
+ typename TagIn1, typename TagIn2, typename TagOut,
+ typename Geometry1, typename Geometry2,
+ bool Reverse1, bool Reverse2, bool ReverseOut,
+ typename OutputIterator,
+ typename GeometryOut,
+ overlay_type OverlayType,
+ typename Strategy
+>
+struct intersection_insert
+ <
+ TagIn1, TagIn2, TagOut,
+ true, true, true,
+ Geometry1, Geometry2,
+ Reverse1, Reverse2, ReverseOut,
+ OutputIterator, GeometryOut,
+ OverlayType,
+ Strategy
+ > : detail::overlay::overlay
+ <Geometry1, Geometry2, Reverse1, Reverse2, ReverseOut, OutputIterator, GeometryOut, OverlayType, Strategy>
+{};
+
+
+// Any areal type with box:
+template
+<
+ typename TagIn, typename TagOut,
+ typename Geometry, typename Box,
+ bool Reverse1, bool Reverse2, bool ReverseOut,
+ typename OutputIterator,
+ typename GeometryOut,
+ overlay_type OverlayType,
+ typename Strategy
+>
+struct intersection_insert
+ <
+ TagIn, box_tag, TagOut,
+ true, true, true,
+ Geometry, Box,
+ Reverse1, Reverse2, ReverseOut,
+ OutputIterator, GeometryOut,
+ OverlayType,
+ Strategy
+ > : detail::overlay::overlay
+ <Geometry, Box, Reverse1, Reverse2, ReverseOut, OutputIterator, GeometryOut, OverlayType, Strategy>
+{};
+
+
+template
+<
+ typename Segment1, typename Segment2,
+ bool Reverse1, bool Reverse2, bool ReverseOut,
+ typename OutputIterator, typename GeometryOut,
+ overlay_type OverlayType,
+ typename Strategy
+>
+struct intersection_insert
+ <
+ segment_tag, segment_tag, point_tag,
+ false, false, false,
+ Segment1, Segment2,
+ Reverse1, Reverse2, ReverseOut,
+ OutputIterator, GeometryOut,
+ OverlayType, Strategy
+ > : detail::intersection::intersection_segment_segment_point
+ <
+ Segment1, Segment2,
+ OutputIterator, GeometryOut,
+ Strategy
+ >
+{};
+
+
+template
+<
+ typename Linestring1, typename Linestring2,
+ bool Reverse1, bool Reverse2, bool ReverseOut,
+ typename OutputIterator, typename GeometryOut,
+ overlay_type OverlayType,
+ typename Strategy
+>
+struct intersection_insert
+ <
+ linestring_tag, linestring_tag, point_tag,
+ false, false, false,
+ Linestring1, Linestring2,
+ Reverse1, Reverse2, ReverseOut,
+ OutputIterator, GeometryOut,
+ OverlayType, Strategy
+ > : detail::intersection::intersection_linestring_linestring_point
+ <
+ Linestring1, Linestring2,
+ OutputIterator, GeometryOut,
+ Strategy
+ >
+{};
+
+
+template
+<
+ typename Linestring, typename Box,
+ bool Reverse1, bool Reverse2, bool ReverseOut,
+ typename OutputIterator, typename GeometryOut,
+ overlay_type OverlayType,
+ typename Strategy
+>
+struct intersection_insert
+ <
+ linestring_tag, box_tag, linestring_tag,
+ false, true, false,
+ Linestring, Box,
+ Reverse1, Reverse2, ReverseOut,
+ OutputIterator, GeometryOut,
+ OverlayType,
+ Strategy
+ >
+{
+ static inline OutputIterator apply(Linestring const& linestring,
+ Box const& box, OutputIterator out, Strategy const& )
+ {
+ typedef typename point_type<GeometryOut>::type point_type;
+ strategy::intersection::liang_barsky<Box, point_type> lb_strategy;
+ return detail::intersection::clip_range_with_box
+ <GeometryOut>(box, linestring, out, lb_strategy);
+ }
+};
+
+
+template
+<
+ typename Linestring, typename Polygon,
+ bool ReverseLinestring, bool ReversePolygon, bool ReverseOut,
+ typename OutputIterator, typename GeometryOut,
+ overlay_type OverlayType,
+ typename Strategy
+>
+struct intersection_insert
+ <
+ linestring_tag, polygon_tag, linestring_tag,
+ false, true, false,
+ Linestring, Polygon,
+ ReverseLinestring, ReversePolygon, ReverseOut,
+ OutputIterator, GeometryOut,
+ OverlayType,
+ Strategy
+ > : detail::intersection::intersection_of_linestring_with_areal
+ <
+ Linestring, Polygon,
+ ReversePolygon,
+ OutputIterator, GeometryOut,
+ OverlayType,
+ Strategy
+ >
+{};
+
+
+template
+<
+ typename Linestring, typename Ring,
+ bool ReverseLinestring, bool ReverseRing, bool ReverseOut,
+ typename OutputIterator, typename GeometryOut,
+ overlay_type OverlayType,
+ typename Strategy
+>
+struct intersection_insert
+ <
+ linestring_tag, ring_tag, linestring_tag,
+ false, true, false,
+ Linestring, Ring,
+ ReverseLinestring, ReverseRing, ReverseOut,
+ OutputIterator, GeometryOut,
+ OverlayType,
+ Strategy
+ > : detail::intersection::intersection_of_linestring_with_areal
+ <
+ Linestring, Ring,
+ ReverseRing,
+ OutputIterator, GeometryOut,
+ OverlayType,
+ Strategy
+ >
+{};
+
+template
+<
+ typename Segment, typename Box,
+ bool Reverse1, bool Reverse2, bool ReverseOut,
+ typename OutputIterator, typename GeometryOut,
+ overlay_type OverlayType,
+ typename Strategy
+>
+struct intersection_insert
+ <
+ segment_tag, box_tag, linestring_tag,
+ false, true, false,
+ Segment, Box,
+ Reverse1, Reverse2, ReverseOut,
+ OutputIterator, GeometryOut,
+ OverlayType,
+ Strategy
+ >
+{
+ static inline OutputIterator apply(Segment const& segment,
+ Box const& box, OutputIterator out, Strategy const& )
+ {
+ geometry::segment_view<Segment> range(segment);
+
+ typedef typename point_type<GeometryOut>::type point_type;
+ strategy::intersection::liang_barsky<Box, point_type> lb_strategy;
+ return detail::intersection::clip_range_with_box
+ <GeometryOut>(box, range, out, lb_strategy);
+ }
+};
+
+template
+<
+ typename Tag1, typename Tag2,
+ bool Areal1, bool Areal2,
+ typename Geometry1, typename Geometry2,
+ bool Reverse1, bool Reverse2, bool ReverseOut,
+ typename OutputIterator, typename PointOut,
+ overlay_type OverlayType,
+ typename Strategy
+>
+struct intersection_insert
+ <
+ Tag1, Tag2, point_tag,
+ Areal1, Areal2, false,
+ Geometry1, Geometry2,
+ Reverse1, Reverse2, ReverseOut,
+ OutputIterator, PointOut,
+ OverlayType,
+ Strategy
+ >
+{
+ static inline OutputIterator apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2, OutputIterator out, Strategy const& )
+ {
+
+ typedef detail::overlay::turn_info<PointOut> turn_info;
+ std::vector<turn_info> turns;
+
+ detail::get_turns::no_interrupt_policy policy;
+ geometry::get_turns
+ <
+ false, false, detail::overlay::assign_null_policy
+ >(geometry1, geometry2, turns, policy);
+ for (typename std::vector<turn_info>::const_iterator it
+ = turns.begin(); it != turns.end(); ++it)
+ {
+ *out++ = it->point;
+ }
+
+ return out;
+ }
+};
+
+
+template
+<
+ typename GeometryTag1, typename GeometryTag2, typename GeometryTag3,
+ bool Areal1, bool Areal2, bool ArealOut,
+ typename Geometry1, typename Geometry2,
+ bool Reverse1, bool Reverse2, bool ReverseOut,
+ typename OutputIterator, typename GeometryOut,
+ overlay_type OverlayType,
+ typename Strategy
+>
+struct intersection_insert_reversed
+{
+ static inline OutputIterator apply(Geometry1 const& g1,
+ Geometry2 const& g2, OutputIterator out,
+ Strategy const& strategy)
+ {
+ return intersection_insert
+ <
+ GeometryTag2, GeometryTag1, GeometryTag3,
+ Areal2, Areal1, ArealOut,
+ Geometry2, Geometry1,
+ Reverse2, Reverse1, ReverseOut,
+ OutputIterator, GeometryOut,
+ OverlayType,
+ Strategy
+ >::apply(g2, g1, out, strategy);
+ }
+};
+
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace intersection
+{
+
+
+template
+<
+ typename GeometryOut,
+ bool ReverseSecond,
+ overlay_type OverlayType,
+ typename Geometry1, typename Geometry2,
+ typename OutputIterator,
+ typename Strategy
+>
+inline OutputIterator insert(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ OutputIterator out,
+ Strategy const& strategy)
+{
+ return boost::mpl::if_c
+ <
+ geometry::reverse_dispatch<Geometry1, Geometry2>::type::value,
+ geometry::dispatch::intersection_insert_reversed
+ <
+ typename geometry::tag<Geometry1>::type,
+ typename geometry::tag<Geometry2>::type,
+ typename geometry::tag<GeometryOut>::type,
+ geometry::is_areal<Geometry1>::value,
+ geometry::is_areal<Geometry2>::value,
+ geometry::is_areal<GeometryOut>::value,
+ Geometry1, Geometry2,
+ overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
+ overlay::do_reverse<geometry::point_order<Geometry2>::value, ReverseSecond>::value,
+ overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value,
+ OutputIterator, GeometryOut,
+ OverlayType,
+ Strategy
+ >,
+ geometry::dispatch::intersection_insert
+ <
+ typename geometry::tag<Geometry1>::type,
+ typename geometry::tag<Geometry2>::type,
+ typename geometry::tag<GeometryOut>::type,
+ geometry::is_areal<Geometry1>::value,
+ geometry::is_areal<Geometry2>::value,
+ geometry::is_areal<GeometryOut>::value,
+ Geometry1, Geometry2,
+ geometry::detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
+ geometry::detail::overlay::do_reverse<geometry::point_order<Geometry2>::value, ReverseSecond>::value,
+ geometry::detail::overlay::do_reverse<geometry::point_order<GeometryOut>::value>::value,
+ OutputIterator, GeometryOut,
+ OverlayType,
+ Strategy
+ >
+ >::type::apply(geometry1, geometry2, out, strategy);
+}
+
+
+/*!
+\brief \brief_calc2{intersection} \brief_strategy
+\ingroup intersection
+\details \details_calc2{intersection_insert, spatial set theoretic intersection}
+ \brief_strategy. \details_insert{intersection}
+\tparam GeometryOut \tparam_geometry{\p_l_or_c}
+\tparam Geometry1 \tparam_geometry
+\tparam Geometry2 \tparam_geometry
+\tparam OutputIterator \tparam_out{\p_l_or_c}
+\tparam Strategy \tparam_strategy_overlay
+\param geometry1 \param_geometry
+\param geometry2 \param_geometry
+\param out \param_out{intersection}
+\param strategy \param_strategy{intersection}
+\return \return_out
+
+\qbk{distinguish,with strategy}
+\qbk{[include reference/algorithms/intersection.qbk]}
+*/
+template
+<
+ typename GeometryOut,
+ typename Geometry1,
+ typename Geometry2,
+ typename OutputIterator,
+ typename Strategy
+>
+inline OutputIterator intersection_insert(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ OutputIterator out,
+ Strategy const& strategy)
+{
+ concept::check<Geometry1 const>();
+ concept::check<Geometry2 const>();
+
+ return detail::intersection::insert
+ <
+ GeometryOut, false, overlay_intersection
+ >(geometry1, geometry2, out, strategy);
+}
+
+
+/*!
+\brief \brief_calc2{intersection}
+\ingroup intersection
+\details \details_calc2{intersection_insert, spatial set theoretic intersection}.
+ \details_insert{intersection}
+\tparam GeometryOut \tparam_geometry{\p_l_or_c}
+\tparam Geometry1 \tparam_geometry
+\tparam Geometry2 \tparam_geometry
+\tparam OutputIterator \tparam_out{\p_l_or_c}
+\param geometry1 \param_geometry
+\param geometry2 \param_geometry
+\param out \param_out{intersection}
+\return \return_out
+
+\qbk{[include reference/algorithms/intersection.qbk]}
+*/
+template
+<
+ typename GeometryOut,
+ typename Geometry1,
+ typename Geometry2,
+ typename OutputIterator
+>
+inline OutputIterator intersection_insert(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ OutputIterator out)
+{
+ concept::check<Geometry1 const>();
+ concept::check<Geometry2 const>();
+
+ typedef strategy_intersection
+ <
+ typename cs_tag<GeometryOut>::type,
+ Geometry1,
+ Geometry2,
+ typename geometry::point_type<GeometryOut>::type
+ > strategy;
+
+ return intersection_insert<GeometryOut>(geometry1, geometry2, out,
+ strategy());
+}
+
+}} // namespace detail::intersection
+#endif // DOXYGEN_NO_DETAIL
+
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_INTERSECTION_INSERT_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/overlay.hpp b/boost/geometry/algorithms/detail/overlay/overlay.hpp
new file mode 100644
index 0000000000..ab5b6d123d
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/overlay.hpp
@@ -0,0 +1,301 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_OVERLAY_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_OVERLAY_HPP
+
+
+#include <deque>
+#include <map>
+
+#include <boost/range.hpp>
+#include <boost/mpl/assert.hpp>
+
+
+#include <boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp>
+#include <boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp>
+#include <boost/geometry/algorithms/detail/overlay/enrichment_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
+#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
+#include <boost/geometry/algorithms/detail/overlay/traverse.hpp>
+#include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+
+
+#include <boost/geometry/algorithms/num_points.hpp>
+#include <boost/geometry/algorithms/reverse.hpp>
+
+#include <boost/geometry/algorithms/detail/overlay/add_rings.hpp>
+#include <boost/geometry/algorithms/detail/overlay/assign_parents.hpp>
+#include <boost/geometry/algorithms/detail/overlay/ring_properties.hpp>
+#include <boost/geometry/algorithms/detail/overlay/select_rings.hpp>
+
+
+#ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE
+# include <boost/geometry/io/dsv/write.hpp>
+#endif
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+// Skip for assemble process
+template <typename TurnInfo>
+inline bool skip(TurnInfo const& turn_info)
+{
+ return (turn_info.discarded || turn_info.both(operation_union))
+ && ! turn_info.any_blocked()
+ && ! turn_info.both(operation_intersection)
+ ;
+}
+
+
+template <typename TurnPoints, typename Map>
+inline void map_turns(Map& map, TurnPoints const& turn_points)
+{
+ typedef typename boost::range_value<TurnPoints>::type turn_point_type;
+ typedef typename turn_point_type::container_type container_type;
+
+ int index = 0;
+ for (typename boost::range_iterator<TurnPoints const>::type
+ it = boost::begin(turn_points);
+ it != boost::end(turn_points);
+ ++it, ++index)
+ {
+ if (! skip(*it))
+ {
+ int op_index = 0;
+ for (typename boost::range_iterator<container_type const>::type
+ op_it = boost::begin(it->operations);
+ op_it != boost::end(it->operations);
+ ++op_it, ++op_index)
+ {
+ ring_identifier ring_id
+ (
+ op_it->seg_id.source_index,
+ op_it->seg_id.multi_index,
+ op_it->seg_id.ring_index
+ );
+ map[ring_id]++;
+ }
+ }
+ }
+}
+
+
+template
+<
+ typename GeometryOut, overlay_type Direction, bool ReverseOut,
+ typename Geometry1, typename Geometry2,
+ typename OutputIterator
+>
+inline OutputIterator return_if_one_input_is_empty(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ OutputIterator out)
+{
+ typedef std::deque
+ <
+ typename geometry::ring_type<GeometryOut>::type
+ > ring_container_type;
+
+ typedef ring_properties<typename geometry::point_type<Geometry1>::type> properties;
+
+ // Union: return either of them
+ // Intersection: return nothing
+ // Difference: return first of them
+ if (Direction == overlay_intersection
+ || (Direction == overlay_difference
+ && geometry::num_points(geometry1) == 0))
+ {
+ return out;
+ }
+
+ std::map<ring_identifier, int> empty;
+ std::map<ring_identifier, properties> all_of_one_of_them;
+
+ select_rings<Direction>(geometry1, geometry2, empty, all_of_one_of_them, false);
+ ring_container_type rings;
+ assign_parents(geometry1, geometry2, rings, all_of_one_of_them);
+ return add_rings<GeometryOut>(all_of_one_of_them, geometry1, geometry2, rings, out);
+}
+
+
+template
+<
+ typename Geometry1, typename Geometry2,
+ bool Reverse1, bool Reverse2, bool ReverseOut,
+ typename OutputIterator, typename GeometryOut,
+ overlay_type Direction,
+ typename Strategy
+>
+struct overlay
+{
+ static inline OutputIterator apply(
+ Geometry1 const& geometry1, Geometry2 const& geometry2,
+ OutputIterator out,
+ Strategy const& )
+ {
+ if (geometry::num_points(geometry1) == 0
+ && geometry::num_points(geometry2) == 0)
+ {
+ return out;
+ }
+
+ if (geometry::num_points(geometry1) == 0
+ || geometry::num_points(geometry2) == 0)
+ {
+ return return_if_one_input_is_empty
+ <
+ GeometryOut, Direction, ReverseOut
+ >(geometry1, geometry2, out);
+ }
+
+ typedef typename geometry::point_type<GeometryOut>::type point_type;
+ typedef detail::overlay::traversal_turn_info<point_type> turn_info;
+ typedef std::deque<turn_info> container_type;
+
+ typedef std::deque
+ <
+ typename geometry::ring_type<GeometryOut>::type
+ > ring_container_type;
+
+ container_type turn_points;
+
+#ifdef BOOST_GEOMETRY_TIME_OVERLAY
+ boost::timer timer;
+#endif
+
+#ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE
+std::cout << "get turns" << std::endl;
+#endif
+ detail::get_turns::no_interrupt_policy policy;
+ geometry::get_turns
+ <
+ Reverse1, Reverse2,
+ detail::overlay::calculate_distance_policy
+ >(geometry1, geometry2, turn_points, policy);
+
+#ifdef BOOST_GEOMETRY_TIME_OVERLAY
+ std::cout << "get_turns: " << timer.elapsed() << std::endl;
+#endif
+
+#ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE
+std::cout << "enrich" << std::endl;
+#endif
+ typename Strategy::side_strategy_type side_strategy;
+ geometry::enrich_intersection_points<Reverse1, Reverse2>(turn_points,
+ Direction == overlay_union
+ ? geometry::detail::overlay::operation_union
+ : geometry::detail::overlay::operation_intersection,
+ geometry1, geometry2,
+ side_strategy);
+
+#ifdef BOOST_GEOMETRY_TIME_OVERLAY
+ std::cout << "enrich_intersection_points: " << timer.elapsed() << std::endl;
+#endif
+
+
+#ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE
+std::cout << "traverse" << std::endl;
+#endif
+ // Traverse through intersection/turn points and create rings of them.
+ // Note that these rings are always in clockwise order, even in CCW polygons,
+ // and are marked as "to be reversed" below
+ ring_container_type rings;
+ traverse<Reverse1, Reverse2, Geometry1, Geometry2>::apply
+ (
+ geometry1, geometry2,
+ Direction == overlay_union
+ ? geometry::detail::overlay::operation_union
+ : geometry::detail::overlay::operation_intersection,
+ turn_points, rings
+ );
+
+#ifdef BOOST_GEOMETRY_TIME_OVERLAY
+ std::cout << "traverse: " << timer.elapsed() << std::endl;
+#endif
+
+
+ std::map<ring_identifier, int> map;
+ map_turns(map, turn_points);
+
+#ifdef BOOST_GEOMETRY_TIME_OVERLAY
+ std::cout << "map_turns: " << timer.elapsed() << std::endl;
+#endif
+
+ typedef ring_properties<typename geometry::point_type<Geometry1>::type> properties;
+
+ std::map<ring_identifier, properties> selected;
+ select_rings<Direction>(geometry1, geometry2, map, selected, ! turn_points.empty());
+
+#ifdef BOOST_GEOMETRY_TIME_OVERLAY
+ std::cout << "select_rings: " << timer.elapsed() << std::endl;
+#endif
+
+
+ // Add rings created during traversal
+ {
+ ring_identifier id(2, 0, -1);
+ for (typename boost::range_iterator<ring_container_type>::type
+ it = boost::begin(rings);
+ it != boost::end(rings);
+ ++it)
+ {
+ selected[id] = properties(*it, true);
+ selected[id].reversed = ReverseOut;
+ id.multi_index++;
+ }
+ }
+
+#ifdef BOOST_GEOMETRY_TIME_OVERLAY
+ std::cout << "add traversal rings: " << timer.elapsed() << std::endl;
+#endif
+
+
+ assign_parents(geometry1, geometry2, rings, selected);
+
+#ifdef BOOST_GEOMETRY_TIME_OVERLAY
+ std::cout << "assign_parents: " << timer.elapsed() << std::endl;
+#endif
+
+ return add_rings<GeometryOut>(selected, geometry1, geometry2, rings, out);
+ }
+};
+
+
+// Metafunction helper for intersection and union
+template <order_selector Selector, bool Reverse = false>
+struct do_reverse {};
+
+template <>
+struct do_reverse<clockwise, false> : boost::false_type {};
+
+template <>
+struct do_reverse<clockwise, true> : boost::true_type {};
+
+template <>
+struct do_reverse<counterclockwise, false> : boost::true_type {};
+
+template <>
+struct do_reverse<counterclockwise, true> : boost::false_type {};
+
+
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_OVERLAY_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/overlay_type.hpp b/boost/geometry/algorithms/detail/overlay/overlay_type.hpp
new file mode 100644
index 0000000000..af62131f0e
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/overlay_type.hpp
@@ -0,0 +1,29 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_OVERLAY_TYPE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_OVERLAY_TYPE_HPP
+
+
+
+namespace boost { namespace geometry
+{
+
+enum overlay_type
+{
+ overlay_union,
+ overlay_intersection,
+ overlay_difference,
+ overlay_dissolve
+};
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_OVERLAY_TYPE_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/ring_properties.hpp b/boost/geometry/algorithms/detail/overlay/ring_properties.hpp
new file mode 100644
index 0000000000..a6088694da
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/ring_properties.hpp
@@ -0,0 +1,78 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_RING_PROPERTIES_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_RING_PROPERTIES_HPP
+
+
+#include <boost/geometry/algorithms/area.hpp>
+#include <boost/geometry/algorithms/within.hpp>
+#include <boost/geometry/algorithms/detail/point_on_border.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+template <typename Point>
+struct ring_properties
+{
+ typedef Point point_type;
+ typedef typename default_area_result<Point>::type area_type;
+
+ // Filled by "select_rings"
+ Point point;
+ area_type area;
+
+ // Filled by "update_selection_map"
+ int within_code;
+ bool reversed;
+
+ // Filled/used by "assign_rings"
+ bool discarded;
+ ring_identifier parent;
+ area_type parent_area;
+ std::vector<ring_identifier> children;
+
+ inline ring_properties()
+ : area(area_type())
+ , within_code(-1)
+ , reversed(false)
+ , discarded(false)
+ , parent_area(-1)
+ {}
+
+ template <typename RingOrBox>
+ inline ring_properties(RingOrBox const& ring_or_box, bool midpoint)
+ : within_code(-1)
+ , reversed(false)
+ , discarded(false)
+ , parent_area(-1)
+ {
+ this->area = geometry::area(ring_or_box);
+ geometry::point_on_border(this->point, ring_or_box, midpoint);
+ }
+
+ inline area_type get_area() const
+ {
+ return reversed ? -area : area;
+ }
+};
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_RING_PROPERTIES_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/segment_identifier.hpp b/boost/geometry/algorithms/detail/overlay/segment_identifier.hpp
new file mode 100644
index 0000000000..007113ffba
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/segment_identifier.hpp
@@ -0,0 +1,91 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SEGMENT_IDENTIFIER_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SEGMENT_IDENTIFIER_HPP
+
+
+#if defined(BOOST_GEOMETRY_DEBUG_OVERLAY)
+# define BOOST_GEOMETRY_DEBUG_SEGMENT_IDENTIFIER
+#endif
+
+
+#include <vector>
+
+
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/coordinate_dimension.hpp>
+
+
+
+namespace boost { namespace geometry
+{
+
+
+// Internal struct to uniquely identify a segment
+// on a linestring,ring
+// or polygon (needs ring_index)
+// or multi-geometry (needs multi_index)
+struct segment_identifier
+{
+ inline segment_identifier()
+ : source_index(-1)
+ , multi_index(-1)
+ , ring_index(-1)
+ , segment_index(-1)
+ {}
+
+ inline segment_identifier(int src, int mul, int rin, int seg)
+ : source_index(src)
+ , multi_index(mul)
+ , ring_index(rin)
+ , segment_index(seg)
+ {}
+
+ inline bool operator<(segment_identifier const& other) const
+ {
+ return source_index != other.source_index ? source_index < other.source_index
+ : multi_index !=other.multi_index ? multi_index < other.multi_index
+ : ring_index != other.ring_index ? ring_index < other.ring_index
+ : segment_index < other.segment_index
+ ;
+ }
+
+ inline bool operator==(segment_identifier const& other) const
+ {
+ return source_index == other.source_index
+ && segment_index == other.segment_index
+ && ring_index == other.ring_index
+ && multi_index == other.multi_index
+ ;
+ }
+
+#if defined(BOOST_GEOMETRY_DEBUG_SEGMENT_IDENTIFIER)
+ friend std::ostream& operator<<(std::ostream &os, segment_identifier const& seg_id)
+ {
+ std::cout
+ << "s:" << seg_id.source_index
+ << ", v:" << seg_id.segment_index // ~vertex
+ ;
+ if (seg_id.ring_index >= 0) std::cout << ", r:" << seg_id.ring_index;
+ if (seg_id.multi_index >= 0) std::cout << ", m:" << seg_id.multi_index;
+ return os;
+ }
+#endif
+
+ int source_index;
+ int multi_index;
+ int ring_index;
+ int segment_index;
+};
+
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SEGMENT_IDENTIFIER_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/select_rings.hpp b/boost/geometry/algorithms/detail/overlay/select_rings.hpp
new file mode 100644
index 0000000000..f664b19514
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/select_rings.hpp
@@ -0,0 +1,295 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SELECT_RINGS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SELECT_RINGS_HPP
+
+#include <map>
+
+
+#include <boost/geometry/algorithms/area.hpp>
+#include <boost/geometry/algorithms/within.hpp>
+#include <boost/geometry/algorithms/detail/point_on_border.hpp>
+#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
+#include <boost/geometry/algorithms/detail/overlay/ring_properties.hpp>
+#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+
+namespace dispatch
+{
+
+ template <typename Tag, typename Geometry>
+ struct select_rings
+ {};
+
+ template <typename Box>
+ struct select_rings<box_tag, Box>
+ {
+ template <typename Geometry, typename Map>
+ static inline void apply(Box const& box, Geometry const& ,
+ ring_identifier const& id, Map& map, bool midpoint)
+ {
+ map[id] = typename Map::mapped_type(box, midpoint);
+ }
+
+ template <typename Map>
+ static inline void apply(Box const& box,
+ ring_identifier const& id, Map& map, bool midpoint)
+ {
+ map[id] = typename Map::mapped_type(box, midpoint);
+ }
+ };
+
+ template <typename Ring>
+ struct select_rings<ring_tag, Ring>
+ {
+ template <typename Geometry, typename Map>
+ static inline void apply(Ring const& ring, Geometry const& ,
+ ring_identifier const& id, Map& map, bool midpoint)
+ {
+ if (boost::size(ring) > 0)
+ {
+ map[id] = typename Map::mapped_type(ring, midpoint);
+ }
+ }
+
+ template <typename Map>
+ static inline void apply(Ring const& ring,
+ ring_identifier const& id, Map& map, bool midpoint)
+ {
+ if (boost::size(ring) > 0)
+ {
+ map[id] = typename Map::mapped_type(ring, midpoint);
+ }
+ }
+ };
+
+
+ template <typename Polygon>
+ struct select_rings<polygon_tag, Polygon>
+ {
+ template <typename Geometry, typename Map>
+ static inline void apply(Polygon const& polygon, Geometry const& geometry,
+ ring_identifier id, Map& map, bool midpoint)
+ {
+ typedef typename geometry::ring_type<Polygon>::type ring_type;
+ typedef select_rings<ring_tag, ring_type> per_ring;
+
+ per_ring::apply(exterior_ring(polygon), geometry, id, map, midpoint);
+
+ typename interior_return_type<Polygon const>::type rings
+ = interior_rings(polygon);
+ for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
+ {
+ id.ring_index++;
+ per_ring::apply(*it, geometry, id, map, midpoint);
+ }
+ }
+
+ template <typename Map>
+ static inline void apply(Polygon const& polygon,
+ ring_identifier id, Map& map, bool midpoint)
+ {
+ typedef typename geometry::ring_type<Polygon>::type ring_type;
+ typedef select_rings<ring_tag, ring_type> per_ring;
+
+ per_ring::apply(exterior_ring(polygon), id, map, midpoint);
+
+ typename interior_return_type<Polygon const>::type rings
+ = interior_rings(polygon);
+ for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
+ {
+ id.ring_index++;
+ per_ring::apply(*it, id, map, midpoint);
+ }
+ }
+ };
+}
+
+
+template<overlay_type OverlayType>
+struct decide
+{};
+
+template<>
+struct decide<overlay_union>
+{
+ template <typename Code>
+ static bool include(ring_identifier const& , Code const& code)
+ {
+ return code.within_code * -1 == 1;
+ }
+
+ template <typename Code>
+ static bool reversed(ring_identifier const& , Code const& )
+ {
+ return false;
+ }
+};
+
+template<>
+struct decide<overlay_difference>
+{
+ template <typename Code>
+ static bool include(ring_identifier const& id, Code const& code)
+ {
+ bool is_first = id.source_index == 0;
+ return code.within_code * -1 * (is_first ? 1 : -1) == 1;
+ }
+
+ template <typename Code>
+ static bool reversed(ring_identifier const& id, Code const& code)
+ {
+ return include(id, code) && id.source_index == 1;
+ }
+};
+
+template<>
+struct decide<overlay_intersection>
+{
+ template <typename Code>
+ static bool include(ring_identifier const& , Code const& code)
+ {
+ return code.within_code * 1 == 1;
+ }
+
+ template <typename Code>
+ static bool reversed(ring_identifier const& , Code const& )
+ {
+ return false;
+ }
+};
+
+
+template
+<
+ overlay_type OverlayType,
+ typename Geometry1, typename Geometry2,
+ typename IntersectionMap, typename SelectionMap
+>
+inline void update_selection_map(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ IntersectionMap const& intersection_map,
+ SelectionMap const& map_with_all, SelectionMap& selection_map)
+{
+ selection_map.clear();
+
+ for (typename SelectionMap::const_iterator it = boost::begin(map_with_all);
+ it != boost::end(map_with_all);
+ ++it)
+ {
+ /*
+ int union_code = it->second.within_code * -1;
+ bool is_first = it->first.source_index == 0;
+ std::cout << it->first << " " << it->second.area
+ << ": " << it->second.within_code
+ << " union: " << union_code
+ << " intersection: " << (it->second.within_code * 1)
+ << " G1-G2: " << (union_code * (is_first ? 1 : -1))
+ << " G2-G1: " << (union_code * (is_first ? -1 : 1))
+ << " -> " << (decide<OverlayType>::include(it->first, it->second) ? "INC" : "")
+ << decide<OverlayType>::reverse(it->first, it->second)
+ << std::endl;
+ */
+
+ bool found = intersection_map.find(it->first) != intersection_map.end();
+ if (! found)
+ {
+ ring_identifier const id = it->first;
+ typename SelectionMap::mapped_type properties = it->second; // Copy by value
+
+ // Calculate the "within code" (previously this was done earlier but is
+ // must efficienter here - it can be even more efficient doing it all at once,
+ // using partition, TODO)
+ // So though this is less elegant than before, it avoids many unused point-in-poly calculations
+ switch(id.source_index)
+ {
+ case 0 :
+ properties.within_code
+ = geometry::within(properties.point, geometry2) ? 1 : -1;
+ break;
+ case 1 :
+ properties.within_code
+ = geometry::within(properties.point, geometry1) ? 1 : -1;
+ break;
+ }
+
+ if (decide<OverlayType>::include(id, properties))
+ {
+ properties.reversed = decide<OverlayType>::reversed(id, properties);
+ selection_map[id] = properties;
+ }
+ }
+ }
+}
+
+
+/*!
+\brief The function select_rings select rings based on the overlay-type (union,intersection)
+*/
+template
+<
+ overlay_type OverlayType,
+ typename Geometry1, typename Geometry2,
+ typename IntersectionMap, typename SelectionMap
+>
+inline void select_rings(Geometry1 const& geometry1, Geometry2 const& geometry2,
+ IntersectionMap const& intersection_map,
+ SelectionMap& selection_map, bool midpoint)
+{
+ typedef typename geometry::tag<Geometry1>::type tag1;
+ typedef typename geometry::tag<Geometry2>::type tag2;
+
+ SelectionMap map_with_all;
+ dispatch::select_rings<tag1, Geometry1>::apply(geometry1, geometry2,
+ ring_identifier(0, -1, -1), map_with_all, midpoint);
+ dispatch::select_rings<tag2, Geometry2>::apply(geometry2, geometry1,
+ ring_identifier(1, -1, -1), map_with_all, midpoint);
+
+ update_selection_map<OverlayType>(geometry1, geometry2, intersection_map,
+ map_with_all, selection_map);
+}
+
+template
+<
+ overlay_type OverlayType,
+ typename Geometry,
+ typename IntersectionMap, typename SelectionMap
+>
+inline void select_rings(Geometry const& geometry,
+ IntersectionMap const& intersection_map,
+ SelectionMap& selection_map, bool midpoint)
+{
+ typedef typename geometry::tag<Geometry>::type tag;
+
+ SelectionMap map_with_all;
+ dispatch::select_rings<tag, Geometry>::apply(geometry,
+ ring_identifier(0, -1, -1), map_with_all, midpoint);
+
+ update_selection_map<OverlayType>(geometry, geometry, intersection_map,
+ map_with_all, selection_map);
+}
+
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SELECT_RINGS_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp b/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp
new file mode 100644
index 0000000000..9c4c99394e
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp
@@ -0,0 +1,308 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SELF_TURN_POINTS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SELF_TURN_POINTS_HPP
+
+#include <cstddef>
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/coordinate_dimension.hpp>
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+
+#include <boost/geometry/algorithms/detail/disjoint.hpp>
+#include <boost/geometry/algorithms/detail/partition.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
+
+#include <boost/geometry/geometries/box.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace self_get_turn_points
+{
+
+struct no_interrupt_policy
+{
+ static bool const enabled = false;
+ static bool const has_intersections = false;
+
+
+ template <typename Range>
+ static inline bool apply(Range const&)
+ {
+ return false;
+ }
+};
+
+
+
+
+class self_ip_exception : public geometry::exception {};
+
+template
+<
+ typename Geometry,
+ typename Turns,
+ typename TurnPolicy,
+ typename InterruptPolicy
+>
+struct self_section_visitor
+{
+ Geometry const& m_geometry;
+ Turns& m_turns;
+ InterruptPolicy& m_interrupt_policy;
+
+ inline self_section_visitor(Geometry const& g,
+ Turns& turns, InterruptPolicy& ip)
+ : m_geometry(g)
+ , m_turns(turns)
+ , m_interrupt_policy(ip)
+ {}
+
+ template <typename Section>
+ inline bool apply(Section const& sec1, Section const& sec2)
+ {
+ if (! detail::disjoint::disjoint_box_box(sec1.bounding_box, sec2.bounding_box)
+ && ! sec1.duplicate
+ && ! sec2.duplicate)
+ {
+ detail::get_turns::get_turns_in_sections
+ <
+ Geometry, Geometry,
+ false, false,
+ Section, Section,
+ Turns, TurnPolicy,
+ InterruptPolicy
+ >::apply(
+ 0, m_geometry, sec1,
+ 0, m_geometry, sec2,
+ false,
+ m_turns, m_interrupt_policy);
+ }
+ if (m_interrupt_policy.has_intersections)
+ {
+ // TODO: we should give partition an interrupt policy.
+ // Now we throw, and catch below, to stop the partition loop.
+ throw self_ip_exception();
+ }
+ return true;
+ }
+
+};
+
+
+
+template
+<
+ typename Geometry,
+ typename Turns,
+ typename TurnPolicy,
+ typename InterruptPolicy
+>
+struct get_turns
+{
+ static inline bool apply(
+ Geometry const& geometry,
+ Turns& turns,
+ InterruptPolicy& interrupt_policy)
+ {
+ typedef model::box
+ <
+ typename geometry::point_type<Geometry>::type
+ > box_type;
+ typedef typename geometry::sections
+ <
+ box_type, 1
+ > sections_type;
+
+ sections_type sec;
+ geometry::sectionalize<false>(geometry, sec);
+
+ self_section_visitor
+ <
+ Geometry,
+ Turns, TurnPolicy, InterruptPolicy
+ > visitor(geometry, turns, interrupt_policy);
+
+ try
+ {
+ geometry::partition
+ <
+ box_type,
+ detail::get_turns::get_section_box,
+ detail::get_turns::ovelaps_section_box
+ >::apply(sec, visitor);
+ }
+ catch(self_ip_exception const& )
+ {
+ return false;
+ }
+
+ return true;
+ }
+};
+
+
+}} // namespace detail::self_get_turn_points
+#endif // DOXYGEN_NO_DETAIL
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+template
+<
+ typename GeometryTag,
+ typename Geometry,
+ typename Turns,
+ typename TurnPolicy,
+ typename InterruptPolicy
+>
+struct self_get_turn_points
+{
+};
+
+
+template
+<
+ typename Ring,
+ typename Turns,
+ typename TurnPolicy,
+ typename InterruptPolicy
+>
+struct self_get_turn_points
+ <
+ ring_tag, Ring,
+ Turns,
+ TurnPolicy,
+ InterruptPolicy
+ >
+ : detail::self_get_turn_points::get_turns
+ <
+ Ring,
+ Turns,
+ TurnPolicy,
+ InterruptPolicy
+ >
+{};
+
+
+template
+<
+ typename Box,
+ typename Turns,
+ typename TurnPolicy,
+ typename InterruptPolicy
+>
+struct self_get_turn_points
+ <
+ box_tag, Box,
+ Turns,
+ TurnPolicy,
+ InterruptPolicy
+ >
+{
+ static inline bool apply(
+ Box const& ,
+ Turns& ,
+ InterruptPolicy& )
+ {
+ return true;
+ }
+};
+
+
+template
+<
+ typename Polygon,
+ typename Turns,
+ typename TurnPolicy,
+ typename InterruptPolicy
+>
+struct self_get_turn_points
+ <
+ polygon_tag, Polygon,
+ Turns,
+ TurnPolicy,
+ InterruptPolicy
+ >
+ : detail::self_get_turn_points::get_turns
+ <
+ Polygon,
+ Turns,
+ TurnPolicy,
+ InterruptPolicy
+ >
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+/*!
+ \brief Calculate self intersections of a geometry
+ \ingroup overlay
+ \tparam Geometry geometry type
+ \tparam Turns type of intersection container
+ (e.g. vector of "intersection/turn point"'s)
+ \param geometry geometry
+ \param turns container which will contain intersection points
+ \param interrupt_policy policy determining if process is stopped
+ when intersection is found
+ */
+template
+<
+ typename AssignPolicy,
+ typename Geometry,
+ typename Turns,
+ typename InterruptPolicy
+>
+inline void self_turns(Geometry const& geometry,
+ Turns& turns, InterruptPolicy& interrupt_policy)
+{
+ concept::check<Geometry const>();
+
+ typedef typename strategy_intersection
+ <
+ typename cs_tag<Geometry>::type,
+ Geometry,
+ Geometry,
+ typename boost::range_value<Turns>::type
+ >::segment_intersection_strategy_type strategy_type;
+
+ typedef detail::overlay::get_turn_info
+ <
+ typename point_type<Geometry>::type,
+ typename point_type<Geometry>::type,
+ typename boost::range_value<Turns>::type,
+ detail::overlay::assign_null_policy
+ > TurnPolicy;
+
+ dispatch::self_get_turn_points
+ <
+ typename tag<Geometry>::type,
+ Geometry,
+ Turns,
+ TurnPolicy,
+ InterruptPolicy
+ >::apply(geometry, turns, interrupt_policy);
+}
+
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SELF_TURN_POINTS_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/stream_info.hpp b/boost/geometry/algorithms/detail/overlay/stream_info.hpp
new file mode 100644
index 0000000000..eebe381944
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/stream_info.hpp
@@ -0,0 +1,75 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_STREAM_INFO_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_STREAM_INFO_HPP
+
+
+#include <string>
+
+#include <boost/array.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+
+ static inline std::string dir(int d)
+ {
+ return d == 0 ? "-" : (d == 1 ? "L" : d == -1 ? "R" : "#");
+ }
+ static inline std::string how_str(int h)
+ {
+ return h == 0 ? "-" : (h == 1 ? "A" : "D");
+ }
+
+ template <typename P>
+ std::ostream& operator<<(std::ostream &os, turn_info<P> const& info)
+ {
+ typename geometry::coordinate_type<P>::type d = info.distance;
+ os << "\t"
+ << " src " << info.seg_id.source_index
+ << " seg " << info.seg_id.segment_index
+ << " (// " << info.other_id.source_index
+ << "." << info.other_id.segment_index << ")"
+ << " how " << info.how
+ << "[" << how_str(info.arrival)
+ << " " << dir(info.direction)
+ << (info.opposite ? " o" : "")
+ << "]"
+ << " sd "
+ << dir(info.sides.get<0,0>())
+ << dir(info.sides.get<0,1>())
+ << dir(info.sides.get<1,0>())
+ << dir(info.sides.get<1,1>())
+ << " nxt seg " << info.travels_to_vertex_index
+ << " , ip " << info.travels_to_ip_index
+ << " , or " << info.next_ip_index
+ << " dst " << double(d)
+ << info.visit_state;
+ if (info.flagged)
+ {
+ os << " FLAGGED";
+ }
+ return os;
+ }
+
+
+
+}} // namespace detail::overlay
+#endif //DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_STREAM_INFO_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/traversal_info.hpp b/boost/geometry/algorithms/detail/overlay/traversal_info.hpp
new file mode 100644
index 0000000000..810a27af04
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/traversal_info.hpp
@@ -0,0 +1,47 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_INFO_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_INFO_HPP
+
+
+#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/enrichment_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/visit_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+
+template <typename P>
+struct traversal_turn_operation : public turn_operation
+{
+ enrichment_info<P> enriched;
+ visit_info visited;
+};
+
+template <typename P>
+struct traversal_turn_info : public turn_info<P, traversal_turn_operation<P> >
+{};
+
+
+
+}} // namespace detail::overlay
+#endif //DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_INFO_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/traverse.hpp b/boost/geometry/algorithms/detail/overlay/traverse.hpp
new file mode 100644
index 0000000000..12daafa0cf
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/traverse.hpp
@@ -0,0 +1,395 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSE_HPP
+
+#include <cstddef>
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp>
+#include <boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp>
+#include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp>
+#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/coordinate_dimension.hpp>
+#include <boost/geometry/geometries/concepts/check.hpp>
+
+#if defined(BOOST_GEOMETRY_DEBUG_INTERSECTION) \
+ || defined(BOOST_GEOMETRY_OVERLAY_REPORT_WKT) \
+ || defined(BOOST_GEOMETRY_DEBUG_TRAVERSE)
+# include <string>
+# include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
+# include <boost/geometry/io/wkt/wkt.hpp>
+#endif
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+template <typename Turn, typename Operation>
+#ifdef BOOST_GEOMETRY_DEBUG_TRAVERSE
+inline void debug_traverse(Turn const& turn, Operation op,
+ std::string const& header)
+{
+ std::cout << header
+ << " at " << op.seg_id
+ << " meth: " << method_char(turn.method)
+ << " op: " << operation_char(op.operation)
+ << " vis: " << visited_char(op.visited)
+ << " of: " << operation_char(turn.operations[0].operation)
+ << operation_char(turn.operations[1].operation)
+ << " " << geometry::wkt(turn.point)
+ << std::endl;
+
+ if (boost::contains(header, "Finished"))
+ {
+ std::cout << std::endl;
+ }
+}
+#else
+inline void debug_traverse(Turn const& , Operation, std::string const& )
+{
+}
+#endif
+
+
+template <typename Info, typename Turn>
+inline void set_visited_for_continue(Info& info, Turn const& turn)
+{
+ // On "continue", set "visited" for ALL directions
+ if (turn.operation == detail::overlay::operation_continue)
+ {
+ for (typename boost::range_iterator
+ <
+ typename Info::container_type
+ >::type it = boost::begin(info.operations);
+ it != boost::end(info.operations);
+ ++it)
+ {
+ if (it->visited.none())
+ {
+ it->visited.set_visited();
+ }
+ }
+ }
+}
+
+
+template
+<
+ bool Reverse1, bool Reverse2,
+ typename GeometryOut,
+ typename G1,
+ typename G2,
+ typename Turns,
+ typename IntersectionInfo
+>
+inline bool assign_next_ip(G1 const& g1, G2 const& g2,
+ Turns& turns,
+ typename boost::range_iterator<Turns>::type& ip,
+ GeometryOut& current_output,
+ IntersectionInfo& info,
+ segment_identifier& seg_id)
+{
+ info.visited.set_visited();
+ set_visited_for_continue(*ip, info);
+
+ // If there is no next IP on this segment
+ if (info.enriched.next_ip_index < 0)
+ {
+ if (info.enriched.travels_to_vertex_index < 0
+ || info.enriched.travels_to_ip_index < 0)
+ {
+ return false;
+ }
+
+ BOOST_ASSERT(info.enriched.travels_to_vertex_index >= 0);
+ BOOST_ASSERT(info.enriched.travels_to_ip_index >= 0);
+
+ if (info.seg_id.source_index == 0)
+ {
+ geometry::copy_segments<Reverse1>(g1, info.seg_id,
+ info.enriched.travels_to_vertex_index,
+ current_output);
+ }
+ else
+ {
+ geometry::copy_segments<Reverse2>(g2, info.seg_id,
+ info.enriched.travels_to_vertex_index,
+ current_output);
+ }
+ seg_id = info.seg_id;
+ ip = boost::begin(turns) + info.enriched.travels_to_ip_index;
+ }
+ else
+ {
+ ip = boost::begin(turns) + info.enriched.next_ip_index;
+ seg_id = info.seg_id;
+ }
+
+ detail::overlay::append_no_duplicates(current_output, ip->point);
+ return true;
+}
+
+
+inline bool select_source(operation_type operation, int source1, int source2)
+{
+ return (operation == operation_intersection && source1 != source2)
+ || (operation == operation_union && source1 == source2)
+ ;
+}
+
+
+template
+<
+ typename Turn,
+ typename Iterator
+>
+inline bool select_next_ip(operation_type operation,
+ Turn& turn,
+ segment_identifier const& seg_id,
+ Iterator& selected)
+{
+ if (turn.discarded)
+ {
+ return false;
+ }
+ bool has_tp = false;
+ selected = boost::end(turn.operations);
+ for (Iterator it = boost::begin(turn.operations);
+ it != boost::end(turn.operations);
+ ++it)
+ {
+ if (it->visited.started())
+ {
+ selected = it;
+ //std::cout << " RETURN";
+ return true;
+ }
+
+ // In some cases there are two alternatives.
+ // For "ii", take the other one (alternate)
+ // UNLESS the other one is already visited
+ // For "uu", take the same one (see above);
+ // For "cc", take either one, but if there is a starting one,
+ // take that one.
+ if ( (it->operation == operation_continue
+ && (! has_tp || it->visited.started()
+ )
+ )
+ || (it->operation == operation
+ && ! it->visited.finished()
+ && (! has_tp
+ || select_source(operation,
+ it->seg_id.source_index, seg_id.source_index)
+ )
+ )
+ )
+ {
+ selected = it;
+ debug_traverse(turn, *it, " Candidate");
+ has_tp = true;
+ }
+ }
+
+ if (has_tp)
+ {
+ debug_traverse(turn, *selected, " Accepted");
+ }
+
+
+ return has_tp;
+}
+
+
+
+/*!
+ \brief Traverses through intersection points / geometries
+ \ingroup overlay
+ */
+template
+<
+ bool Reverse1, bool Reverse2,
+ typename Geometry1,
+ typename Geometry2,
+ typename Backtrack = backtrack_check_self_intersections<Geometry1, Geometry2>
+>
+class traverse
+{
+public :
+ template <typename Turns, typename Rings>
+ static inline void apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ detail::overlay::operation_type operation,
+ Turns& turns, Rings& rings)
+ {
+ typedef typename boost::range_iterator<Turns>::type turn_iterator;
+ typedef typename boost::range_value<Turns>::type turn_type;
+ typedef typename boost::range_iterator
+ <
+ typename turn_type::container_type
+ >::type turn_operation_iterator_type;
+
+ std::size_t size_at_start = boost::size(rings);
+
+ typename Backtrack::state_type state;
+ do
+ {
+ state.reset();
+
+ // Iterate through all unvisited points
+ for (turn_iterator it = boost::begin(turns);
+ state.good() && it != boost::end(turns);
+ ++it)
+ {
+ // Skip discarded ones
+ if (! (it->is_discarded() || it->blocked()))
+ {
+ for (turn_operation_iterator_type iit = boost::begin(it->operations);
+ state.good() && iit != boost::end(it->operations);
+ ++iit)
+ {
+ if (iit->visited.none()
+ && ! iit->visited.rejected()
+ && (iit->operation == operation
+ || iit->operation == detail::overlay::operation_continue)
+ )
+ {
+ set_visited_for_continue(*it, *iit);
+
+ typename boost::range_value<Rings>::type current_output;
+ detail::overlay::append_no_duplicates(current_output,
+ it->point, true);
+
+ turn_iterator current = it;
+ turn_operation_iterator_type current_iit = iit;
+ segment_identifier current_seg_id;
+
+ if (! detail::overlay::assign_next_ip<Reverse1, Reverse2>(
+ geometry1, geometry2,
+ turns,
+ current, current_output,
+ *iit, current_seg_id))
+ {
+ Backtrack::apply(
+ size_at_start,
+ rings, current_output, turns, *current_iit,
+ "No next IP",
+ geometry1, geometry2, state);
+ }
+
+ if (! detail::overlay::select_next_ip(
+ operation,
+ *current,
+ current_seg_id,
+ current_iit))
+ {
+ Backtrack::apply(
+ size_at_start,
+ rings, current_output, turns, *iit,
+ "Dead end at start",
+ geometry1, geometry2, state);
+ }
+ else
+ {
+
+ iit->visited.set_started();
+ detail::overlay::debug_traverse(*it, *iit, "-> Started");
+ detail::overlay::debug_traverse(*current, *current_iit, "Selected ");
+
+
+ unsigned int i = 0;
+
+ while (current_iit != iit && state.good())
+ {
+ if (current_iit->visited.visited())
+ {
+ // It visits a visited node again, without passing the start node.
+ // This makes it suspicious for endless loops
+ Backtrack::apply(
+ size_at_start,
+ rings, current_output, turns, *iit,
+ "Visit again",
+ geometry1, geometry2, state);
+ }
+ else
+ {
+
+
+ // We assume clockwise polygons only, non self-intersecting, closed.
+ // However, the input might be different, and checking validity
+ // is up to the library user.
+
+ // Therefore we make here some sanity checks. If the input
+ // violates the assumptions, the output polygon will not be correct
+ // but the routine will stop and output the current polygon, and
+ // will continue with the next one.
+
+ // Below three reasons to stop.
+ detail::overlay::assign_next_ip<Reverse1, Reverse2>(
+ geometry1, geometry2,
+ turns, current, current_output,
+ *current_iit, current_seg_id);
+
+ if (! detail::overlay::select_next_ip(
+ operation,
+ *current,
+ current_seg_id,
+ current_iit))
+ {
+ // Should not occur in valid (non-self-intersecting) polygons
+ // Should not occur in self-intersecting polygons without spikes
+ // Might occur in polygons with spikes
+ Backtrack::apply(
+ size_at_start,
+ rings, current_output, turns, *iit,
+ "Dead end",
+ geometry1, geometry2, state);
+ }
+ detail::overlay::debug_traverse(*current, *current_iit, "Selected ");
+
+ if (i++ > 2 + 2 * turns.size())
+ {
+ // Sanity check: there may be never more loops
+ // than turn points.
+ // Turn points marked as "ii" can be visited twice.
+ Backtrack::apply(
+ size_at_start,
+ rings, current_output, turns, *iit,
+ "Endless loop",
+ geometry1, geometry2, state);
+ }
+ }
+ }
+
+ if (state.good())
+ {
+ iit->visited.set_finished();
+ detail::overlay::debug_traverse(*current, *iit, "->Finished");
+ rings.push_back(current_output);
+ }
+ }
+ }
+ }
+ }
+ }
+ } while (! state.good());
+ }
+};
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSE_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/turn_info.hpp b/boost/geometry/algorithms/detail/overlay/turn_info.hpp
new file mode 100644
index 0000000000..aa6b428f19
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/turn_info.hpp
@@ -0,0 +1,142 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TURN_INFO_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TURN_INFO_HPP
+
+
+#include <boost/array.hpp>
+
+#include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+
+enum operation_type
+{
+ operation_none,
+ operation_union,
+ operation_intersection,
+ operation_blocked,
+ operation_continue
+};
+
+
+enum method_type
+{
+ method_none,
+ method_disjoint,
+ method_crosses,
+ method_touch,
+ method_touch_interior,
+ method_collinear,
+ method_equal,
+ method_error
+};
+
+
+/*!
+ \brief Turn operation: operation
+ \details Information necessary for traversal phase (a phase
+ of the overlay process). The information is gathered during the
+ get_turns (segment intersection) phase.
+ The class is to be included in the turn_info class, either direct
+ or a derived or similar class with more (e.g. enrichment) information.
+ */
+struct turn_operation
+{
+ operation_type operation;
+ segment_identifier seg_id;
+ segment_identifier other_id;
+
+ inline turn_operation()
+ : operation(operation_none)
+ {}
+};
+
+
+/*!
+ \brief Turn information: intersection point, method, and turn information
+ \details Information necessary for traversal phase (a phase
+ of the overlay process). The information is gathered during the
+ get_turns (segment intersection) phase.
+ \tparam Point point type of intersection point
+ \tparam Operation gives classes opportunity to add additional info
+ \tparam Container gives classes opportunity to define how operations are stored
+ */
+template
+<
+ typename Point,
+ typename Operation = turn_operation,
+ typename Container = boost::array<Operation, 2>
+>
+struct turn_info
+{
+ typedef Point point_type;
+ typedef Operation turn_operation_type;
+ typedef Container container_type;
+
+ Point point;
+ method_type method;
+ bool discarded;
+
+
+ Container operations;
+
+ inline turn_info()
+ : method(method_none)
+ , discarded(false)
+ {}
+
+ inline bool both(operation_type type) const
+ {
+ return has12(type, type);
+ }
+
+ inline bool combination(operation_type type1, operation_type type2) const
+ {
+ return has12(type1, type2) || has12(type2, type1);
+ }
+
+
+ inline bool is_discarded() const { return discarded; }
+ inline bool blocked() const
+ {
+ return both(operation_blocked);
+ }
+ inline bool any_blocked() const
+ {
+ return this->operations[0].operation == operation_blocked
+ || this->operations[1].operation == operation_blocked;
+ }
+
+
+private :
+ inline bool has12(operation_type type1, operation_type type2) const
+ {
+ return this->operations[0].operation == type1
+ && this->operations[1].operation == type2
+ ;
+ }
+
+};
+
+
+}} // namespace detail::overlay
+#endif //DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TURN_INFO_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/visit_info.hpp b/boost/geometry/algorithms/detail/overlay/visit_info.hpp
new file mode 100644
index 0000000000..6be63f42b4
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/visit_info.hpp
@@ -0,0 +1,136 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_VISIT_INFO_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_VISIT_INFO_HPP
+
+
+#ifdef BOOST_GEOMETRY_USE_MSM
+# include <boost/geometry/algorithms/detail/overlay/msm_state.hpp>
+#endif
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+
+#if ! defined(BOOST_GEOMETRY_USE_MSM)
+
+class visit_info
+{
+private :
+ static const int NONE = 0;
+ static const int STARTED = 1;
+ static const int VISITED = 2;
+ static const int FINISHED = 3;
+ static const int REJECTED = 4;
+
+ int m_visit_code;
+ bool m_rejected;
+
+public:
+ inline visit_info()
+ : m_visit_code(0)
+ , m_rejected(false)
+ {}
+
+ inline void set_visited() { m_visit_code = VISITED; }
+ inline void set_started() { m_visit_code = STARTED; }
+ inline void set_finished() { m_visit_code = FINISHED; }
+ inline void set_rejected()
+ {
+ m_visit_code = REJECTED;
+ m_rejected = true;
+ }
+
+ inline bool none() const { return m_visit_code == NONE; }
+ inline bool visited() const { return m_visit_code == VISITED; }
+ inline bool started() const { return m_visit_code == STARTED; }
+ inline bool finished() const { return m_visit_code == FINISHED; }
+ inline bool rejected() const { return m_rejected; }
+
+ inline void clear()
+ {
+ if (! rejected())
+ {
+ m_visit_code = NONE;
+ }
+ }
+
+
+
+#ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION
+ friend std::ostream& operator<<(std::ostream &os, visit_info const& v)
+ {
+ if (v.m_visit_code != 0)
+ {
+ os << " VIS: " << int(v.m_visit_code);
+ }
+ return os;
+ }
+#endif
+
+};
+
+
+#else
+
+
+class visit_info
+{
+
+private :
+
+#ifndef USE_MSM_MINI
+ mutable
+#endif
+ traverse_state state;
+
+public :
+ inline visit_info()
+ {
+ state.start();
+ }
+
+ inline void set_none() { state.process_event(none()); } // Not Yet Implemented!
+ inline void set_visited() { state.process_event(visit()); }
+ inline void set_started() { state.process_event(starting()); }
+ inline void set_finished() { state.process_event(finish()); }
+
+#ifdef USE_MSM_MINI
+ inline bool none() const { return state.flag_none(); }
+ inline bool visited() const { return state.flag_visited(); }
+ inline bool started() const { return state.flag_started(); }
+#else
+ inline bool none() const { return state.is_flag_active<is_init>(); }
+ inline bool visited() const { return state.is_flag_active<is_visited>(); }
+ inline bool started() const { return state.is_flag_active<is_started>(); }
+#endif
+
+#ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION
+ friend std::ostream& operator<<(std::ostream &os, visit_info const& v)
+ {
+ return os;
+ }
+#endif
+};
+#endif
+
+
+}} // namespace detail::overlay
+#endif //DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_VISIT_INFO_HPP
diff --git a/boost/geometry/algorithms/detail/partition.hpp b/boost/geometry/algorithms/detail/partition.hpp
new file mode 100644
index 0000000000..7a7de2cdd3
--- /dev/null
+++ b/boost/geometry/algorithms/detail/partition.hpp
@@ -0,0 +1,425 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2011-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_PARTITION_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_PARTITION_HPP
+
+#include <vector>
+#include <boost/range/algorithm/copy.hpp>
+#include <boost/geometry/algorithms/assign.hpp>
+#include <boost/geometry/core/coordinate_type.hpp>
+
+namespace boost { namespace geometry
+{
+
+namespace detail { namespace partition
+{
+
+typedef std::vector<std::size_t> index_vector_type;
+
+template <int Dimension, typename Box>
+inline void divide_box(Box const& box, Box& lower_box, Box& upper_box)
+{
+ typedef typename coordinate_type<Box>::type ctype;
+
+ // Divide input box into two parts, e.g. left/right
+ ctype two = 2;
+ ctype mid = (geometry::get<min_corner, Dimension>(box)
+ + geometry::get<max_corner, Dimension>(box)) / two;
+
+ lower_box = box;
+ upper_box = box;
+ geometry::set<max_corner, Dimension>(lower_box, mid);
+ geometry::set<min_corner, Dimension>(upper_box, mid);
+}
+
+// Divide collection into three subsets: lower, upper and oversized
+// (not-fitting)
+// (lower == left or bottom, upper == right or top)
+template <typename OverlapsPolicy, typename InputCollection, typename Box>
+static inline void divide_into_subsets(Box const& lower_box,
+ Box const& upper_box,
+ InputCollection const& collection,
+ index_vector_type const& input,
+ index_vector_type& lower,
+ index_vector_type& upper,
+ index_vector_type& exceeding)
+{
+ typedef boost::range_iterator
+ <
+ index_vector_type const
+ >::type index_iterator_type;
+
+ for(index_iterator_type it = boost::begin(input);
+ it != boost::end(input);
+ ++it)
+ {
+ bool const lower_overlapping = OverlapsPolicy::apply(lower_box,
+ collection[*it]);
+ bool const upper_overlapping = OverlapsPolicy::apply(upper_box,
+ collection[*it]);
+
+ if (lower_overlapping && upper_overlapping)
+ {
+ exceeding.push_back(*it);
+ }
+ else if (lower_overlapping)
+ {
+ lower.push_back(*it);
+ }
+ else if (upper_overlapping)
+ {
+ upper.push_back(*it);
+ }
+ else
+ {
+ // Is nowhere! Should not occur!
+ BOOST_ASSERT(true);
+ }
+ }
+}
+
+// Match collection with itself
+template <typename InputCollection, typename Policy>
+static inline void handle_one(InputCollection const& collection,
+ index_vector_type const& input,
+ Policy& policy)
+{
+ typedef boost::range_iterator<index_vector_type const>::type
+ index_iterator_type;
+ // Quadratic behaviour at lowest level (lowest quad, or all exceeding)
+ for(index_iterator_type it1 = boost::begin(input);
+ it1 != boost::end(input);
+ ++it1)
+ {
+ index_iterator_type it2 = it1;
+ for(++it2; it2 != boost::end(input); ++it2)
+ {
+ policy.apply(collection[*it1], collection[*it2]);
+ }
+ }
+}
+
+// Match collection 1 with collection 2
+template <typename InputCollection, typename Policy>
+static inline void handle_two(
+ InputCollection const& collection1, index_vector_type const& input1,
+ InputCollection const& collection2, index_vector_type const& input2,
+ Policy& policy)
+{
+ typedef boost::range_iterator
+ <
+ index_vector_type const
+ >::type index_iterator_type;
+
+ for(index_iterator_type it1 = boost::begin(input1);
+ it1 != boost::end(input1);
+ ++it1)
+ {
+ for(index_iterator_type it2 = boost::begin(input2);
+ it2 != boost::end(input2);
+ ++it2)
+ {
+ policy.apply(collection1[*it1], collection2[*it2]);
+ }
+ }
+}
+
+template
+<
+ int Dimension,
+ typename Box,
+ typename OverlapsPolicy,
+ typename VisitBoxPolicy
+>
+class partition_one_collection
+{
+ typedef std::vector<std::size_t> index_vector_type;
+ typedef typename coordinate_type<Box>::type ctype;
+ typedef partition_one_collection
+ <
+ 1 - Dimension,
+ Box,
+ OverlapsPolicy,
+ VisitBoxPolicy
+ > sub_divide;
+
+ template <typename InputCollection, typename Policy>
+ static inline void next_level(Box const& box,
+ InputCollection const& collection,
+ index_vector_type const& input,
+ int level, int min_elements,
+ Policy& policy, VisitBoxPolicy& box_policy)
+ {
+ if (boost::size(input) > 0)
+ {
+ if (boost::size(input) > min_elements && level < 100)
+ {
+ sub_divide::apply(box, collection, input, level + 1,
+ min_elements, policy, box_policy);
+ }
+ else
+ {
+ handle_one(collection, input, policy);
+ }
+ }
+ }
+
+public :
+ template <typename InputCollection, typename Policy>
+ static inline void apply(Box const& box,
+ InputCollection const& collection,
+ index_vector_type const& input,
+ int level,
+ int min_elements,
+ Policy& policy, VisitBoxPolicy& box_policy)
+ {
+ box_policy.apply(box, level);
+
+ Box lower_box, upper_box;
+ divide_box<Dimension>(box, lower_box, upper_box);
+
+ index_vector_type lower, upper, exceeding;
+ divide_into_subsets<OverlapsPolicy>(lower_box, upper_box, collection,
+ input, lower, upper, exceeding);
+
+ if (boost::size(exceeding) > 0)
+ {
+ // All what is not fitting a partition should be combined
+ // with each other, and with all which is fitting.
+ handle_one(collection, exceeding, policy);
+ handle_two(collection, exceeding, collection, lower, policy);
+ handle_two(collection, exceeding, collection, upper, policy);
+ }
+
+ // Recursively call operation both parts
+ next_level(lower_box, collection, lower, level, min_elements,
+ policy, box_policy);
+ next_level(upper_box, collection, upper, level, min_elements,
+ policy, box_policy);
+ }
+};
+
+template
+<
+ int Dimension,
+ typename Box,
+ typename OverlapsPolicy,
+ typename VisitBoxPolicy
+>
+class partition_two_collections
+{
+ typedef std::vector<std::size_t> index_vector_type;
+ typedef typename coordinate_type<Box>::type ctype;
+ typedef partition_two_collections
+ <
+ 1 - Dimension,
+ Box,
+ OverlapsPolicy,
+ VisitBoxPolicy
+ > sub_divide;
+
+ template <typename InputCollection, typename Policy>
+ static inline void next_level(Box const& box,
+ InputCollection const& collection1,
+ index_vector_type const& input1,
+ InputCollection const& collection2,
+ index_vector_type const& input2,
+ int level, int min_elements,
+ Policy& policy, VisitBoxPolicy& box_policy)
+ {
+ if (boost::size(input1) > 0 && boost::size(input2) > 0)
+ {
+ if (boost::size(input1) > min_elements
+ && boost::size(input2) > min_elements
+ && level < 100)
+ {
+ sub_divide::apply(box, collection1, input1, collection2,
+ input2, level + 1, min_elements,
+ policy, box_policy);
+ }
+ else
+ {
+ box_policy.apply(box, level + 1);
+ handle_two(collection1, input1, collection2, input2, policy);
+ }
+ }
+ }
+
+public :
+ template <typename InputCollection, typename Policy>
+ static inline void apply(Box const& box,
+ InputCollection const& collection1, index_vector_type const& input1,
+ InputCollection const& collection2, index_vector_type const& input2,
+ int level,
+ int min_elements,
+ Policy& policy, VisitBoxPolicy& box_policy)
+ {
+ box_policy.apply(box, level);
+
+ Box lower_box, upper_box;
+ divide_box<Dimension>(box, lower_box, upper_box);
+
+ index_vector_type lower1, upper1, exceeding1;
+ index_vector_type lower2, upper2, exceeding2;
+ divide_into_subsets<OverlapsPolicy>(lower_box, upper_box, collection1,
+ input1, lower1, upper1, exceeding1);
+ divide_into_subsets<OverlapsPolicy>(lower_box, upper_box, collection2,
+ input2, lower2, upper2, exceeding2);
+
+ if (boost::size(exceeding1) > 0)
+ {
+ // All exceeding from 1 with 2:
+ handle_two(collection1, exceeding1, collection2, exceeding2,
+ policy);
+
+ // All exceeding from 1 with lower and upper of 2:
+ handle_two(collection1, exceeding1, collection2, lower2, policy);
+ handle_two(collection1, exceeding1, collection2, upper2, policy);
+ }
+ if (boost::size(exceeding2) > 0)
+ {
+ // All exceeding from 2 with lower and upper of 1:
+ handle_two(collection1, lower1, collection2, exceeding2, policy);
+ handle_two(collection1, upper1, collection2, exceeding2, policy);
+ }
+
+ next_level(lower_box, collection1, lower1, collection2, lower2, level,
+ min_elements, policy, box_policy);
+ next_level(upper_box, collection1, upper1, collection2, upper2, level,
+ min_elements, policy, box_policy);
+ }
+};
+
+}} // namespace detail::partition
+
+struct visit_no_policy
+{
+ template <typename Box>
+ static inline void apply(Box const&, int )
+ {}
+};
+
+template
+<
+ typename Box,
+ typename ExpandPolicy,
+ typename OverlapsPolicy,
+ typename VisitBoxPolicy = visit_no_policy
+>
+class partition
+{
+ typedef std::vector<std::size_t> index_vector_type;
+
+ template <typename InputCollection>
+ static inline void expand_to_collection(InputCollection const& collection,
+ Box& total, index_vector_type& index_vector)
+ {
+ std::size_t index = 0;
+ for(typename boost::range_iterator<InputCollection const>::type it
+ = boost::begin(collection);
+ it != boost::end(collection);
+ ++it, ++index)
+ {
+ ExpandPolicy::apply(total, *it);
+ index_vector.push_back(index);
+ }
+ }
+
+public :
+ template <typename InputCollection, typename VisitPolicy>
+ static inline void apply(InputCollection const& collection,
+ VisitPolicy& visitor,
+ int min_elements = 16,
+ VisitBoxPolicy box_visitor = visit_no_policy()
+ )
+ {
+ if (boost::size(collection) > min_elements)
+ {
+ index_vector_type index_vector;
+ Box total;
+ assign_inverse(total);
+ expand_to_collection(collection, total, index_vector);
+
+ detail::partition::partition_one_collection
+ <
+ 0, Box,
+ OverlapsPolicy,
+ VisitBoxPolicy
+ >::apply(total, collection, index_vector, 0, min_elements,
+ visitor, box_visitor);
+ }
+ else
+ {
+ typedef typename boost::range_iterator
+ <
+ InputCollection const
+ >::type iterator_type;
+ for(iterator_type it1 = boost::begin(collection);
+ it1 != boost::end(collection);
+ ++it1)
+ {
+ iterator_type it2 = it1;
+ for(++it2; it2 != boost::end(collection); ++it2)
+ {
+ visitor.apply(*it1, *it2);
+ }
+ }
+ }
+ }
+
+ template <typename InputCollection, typename VisitPolicy>
+ static inline void apply(InputCollection const& collection1,
+ InputCollection const& collection2,
+ VisitPolicy& visitor,
+ int min_elements = 16,
+ VisitBoxPolicy box_visitor = visit_no_policy()
+ )
+ {
+ if (boost::size(collection1) > min_elements
+ && boost::size(collection2) > min_elements)
+ {
+ index_vector_type index_vector1, index_vector2;
+ Box total;
+ assign_inverse(total);
+ expand_to_collection(collection1, total, index_vector1);
+ expand_to_collection(collection2, total, index_vector2);
+
+ detail::partition::partition_two_collections
+ <
+ 0, Box, OverlapsPolicy, VisitBoxPolicy
+ >::apply(total,
+ collection1, index_vector1,
+ collection2, index_vector2,
+ 0, min_elements, visitor, box_visitor);
+ }
+ else
+ {
+ typedef typename boost::range_iterator
+ <
+ InputCollection const
+ >::type iterator_type;
+ for(iterator_type it1 = boost::begin(collection1);
+ it1 != boost::end(collection1);
+ ++it1)
+ {
+ for(iterator_type it2 = boost::begin(collection2);
+ it2 != boost::end(collection2);
+ ++it2)
+ {
+ visitor.apply(*it1, *it2);
+ }
+ }
+ }
+ }
+
+};
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_PARTITION_HPP
diff --git a/boost/geometry/algorithms/detail/point_on_border.hpp b/boost/geometry/algorithms/detail/point_on_border.hpp
new file mode 100644
index 0000000000..33177924aa
--- /dev/null
+++ b/boost/geometry/algorithms/detail/point_on_border.hpp
@@ -0,0 +1,243 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.Dimension. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_POINT_ON_BORDER_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_POINT_ON_BORDER_HPP
+
+
+#include <cstddef>
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/ring_type.hpp>
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+
+#include <boost/geometry/algorithms/assign.hpp>
+#include <boost/geometry/algorithms/detail/disjoint.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace point_on_border
+{
+
+
+template<typename Point>
+struct get_point
+{
+ static inline bool apply(Point& destination, Point const& source, bool)
+ {
+ destination = source;
+ return true;
+ }
+};
+
+template<typename Point, std::size_t Dimension, std::size_t DimensionCount>
+struct midpoint_helper
+{
+ static inline bool apply(Point& p, Point const& p1, Point const& p2)
+ {
+ typename coordinate_type<Point>::type const two = 2;
+ set<Dimension>(p,
+ (get<Dimension>(p1) + get<Dimension>(p2)) / two);
+ return midpoint_helper<Point, Dimension + 1, DimensionCount>::apply(p, p1, p2);
+ }
+};
+
+
+template <typename Point, std::size_t DimensionCount>
+struct midpoint_helper<Point, DimensionCount, DimensionCount>
+{
+ static inline bool apply(Point& , Point const& , Point const& )
+ {
+ return true;
+ }
+};
+
+
+template<typename Point, typename Range>
+struct point_on_range
+{
+ static inline bool apply(Point& point, Range const& range, bool midpoint)
+ {
+ const std::size_t n = boost::size(range);
+ if (midpoint && n > 1)
+ {
+ typedef typename boost::range_iterator
+ <
+ Range const
+ >::type iterator;
+
+ iterator it = boost::begin(range);
+ iterator prev = it++;
+ while (it != boost::end(range)
+ && detail::equals::equals_point_point(*it, *prev))
+ {
+ prev = it++;
+ }
+ if (it != boost::end(range))
+ {
+ return midpoint_helper
+ <
+ Point,
+ 0, dimension<Point>::value
+ >::apply(point, *prev, *it);
+ }
+ }
+
+ if (n > 0)
+ {
+ point = *boost::begin(range);
+ return true;
+ }
+ return false;
+ }
+};
+
+
+template<typename Point, typename Polygon>
+struct point_on_polygon
+{
+ static inline bool apply(Point& point, Polygon const& polygon, bool midpoint)
+ {
+ return point_on_range
+ <
+ Point,
+ typename ring_type<Polygon>::type
+ >::apply(point, exterior_ring(polygon), midpoint);
+ }
+};
+
+
+template<typename Point, typename Box>
+struct point_on_box
+{
+ static inline bool apply(Point& point, Box const& box, bool midpoint)
+ {
+ if (midpoint)
+ {
+ Point p1, p2;
+ detail::assign::assign_box_2d_corner<min_corner, min_corner>(box, p1);
+ detail::assign::assign_box_2d_corner<max_corner, min_corner>(box, p2);
+ midpoint_helper
+ <
+ Point,
+ 0, dimension<Point>::value
+ >::apply(point, p1, p2);
+ }
+ else
+ {
+ detail::assign::assign_box_2d_corner<min_corner, min_corner>(box, point);
+ }
+
+ return true;
+ }
+};
+
+
+}} // namespace detail::point_on_border
+#endif // DOXYGEN_NO_DETAIL
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template
+<
+ typename GeometryTag,
+ typename Point,
+ typename Geometry
+
+>
+struct point_on_border
+{};
+
+
+template<typename Point>
+struct point_on_border<point_tag, Point, Point>
+ : detail::point_on_border::get_point<Point>
+{};
+
+
+template<typename Point, typename Linestring>
+struct point_on_border<linestring_tag, Point, Linestring>
+ : detail::point_on_border::point_on_range<Point, Linestring>
+{};
+
+
+template<typename Point, typename Ring>
+struct point_on_border<ring_tag, Point, Ring>
+ : detail::point_on_border::point_on_range<Point, Ring>
+{};
+
+
+template<typename Point, typename Polygon>
+struct point_on_border<polygon_tag, Point, Polygon>
+ : detail::point_on_border::point_on_polygon<Point, Polygon>
+{};
+
+
+template<typename Point, typename Box>
+struct point_on_border<box_tag, Point, Box>
+ : detail::point_on_border::point_on_box<Point, Box>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+/*!
+\brief Take point on a border
+\ingroup overlay
+\tparam Geometry geometry type. This also defines the type of the output point
+\param point to assign
+\param geometry geometry to take point from
+\param midpoint boolean flag, true if the point should not be a vertex, but some point
+ in between of two vertices
+\return TRUE if successful, else false.
+ It is only false if polygon/line have no points
+\note for a polygon, it is always a point on the exterior ring
+\note for take_midpoint, it is not taken from two consecutive duplicate vertices,
+ (unless there are no other).
+ */
+template <typename Point, typename Geometry>
+inline bool point_on_border(Point& point,
+ Geometry const& geometry,
+ bool midpoint = false)
+{
+ concept::check<Point>();
+ concept::check<Geometry const>();
+
+ typedef typename point_type<Geometry>::type point_type;
+
+ return dispatch::point_on_border
+ <
+ typename tag<Geometry>::type,
+ Point,
+ Geometry
+ >::apply(point, geometry, midpoint);
+}
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_POINT_ON_BORDER_HPP
diff --git a/boost/geometry/algorithms/detail/ring_identifier.hpp b/boost/geometry/algorithms/detail/ring_identifier.hpp
new file mode 100644
index 0000000000..9209ee0304
--- /dev/null
+++ b/boost/geometry/algorithms/detail/ring_identifier.hpp
@@ -0,0 +1,70 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RING_IDENTIFIER_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RING_IDENTIFIER_HPP
+
+
+namespace boost { namespace geometry
+{
+
+
+// Ring Identifier. It is currently: source,multi,ring
+struct ring_identifier
+{
+
+ inline ring_identifier()
+ : source_index(-1)
+ , multi_index(-1)
+ , ring_index(-1)
+ {}
+
+ inline ring_identifier(int src, int mul, int rin)
+ : source_index(src)
+ , multi_index(mul)
+ , ring_index(rin)
+ {}
+
+ inline bool operator<(ring_identifier const& other) const
+ {
+ return source_index != other.source_index ? source_index < other.source_index
+ : multi_index !=other.multi_index ? multi_index < other.multi_index
+ : ring_index < other.ring_index
+ ;
+ }
+
+ inline bool operator==(ring_identifier const& other) const
+ {
+ return source_index == other.source_index
+ && ring_index == other.ring_index
+ && multi_index == other.multi_index
+ ;
+ }
+
+#if defined(BOOST_GEOMETRY_DEBUG_IDENTIFIER)
+ friend std::ostream& operator<<(std::ostream &os, ring_identifier const& ring_id)
+ {
+ os << "(s:" << ring_id.source_index;
+ if (ring_id.ring_index >= 0) os << ", r:" << ring_id.ring_index;
+ if (ring_id.multi_index >= 0) os << ", m:" << ring_id.multi_index;
+ os << ")";
+ return os;
+ }
+#endif
+
+
+ int source_index;
+ int multi_index;
+ int ring_index;
+};
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RING_IDENTIFIER_HPP
diff --git a/boost/geometry/algorithms/detail/sections/range_by_section.hpp b/boost/geometry/algorithms/detail/sections/range_by_section.hpp
new file mode 100644
index 0000000000..ad62f232bd
--- /dev/null
+++ b/boost/geometry/algorithms/detail/sections/range_by_section.hpp
@@ -0,0 +1,131 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_RANGE_BY_SECTION_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_RANGE_BY_SECTION_HPP
+
+
+#include <boost/mpl/assert.hpp>
+#include <boost/range.hpp>
+
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/closure.hpp>
+#include <boost/geometry/core/exterior_ring.hpp>
+#include <boost/geometry/core/interior_rings.hpp>
+
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace section
+{
+
+
+template <typename Range, typename Section>
+struct full_section_range
+{
+ static inline Range const& apply(Range const& range, Section const& )
+ {
+ return range;
+ }
+};
+
+
+template <typename Polygon, typename Section>
+struct full_section_polygon
+{
+ static inline typename ring_return_type<Polygon const>::type apply(Polygon const& polygon, Section const& section)
+ {
+ return section.ring_id.ring_index < 0
+ ? geometry::exterior_ring(polygon)
+ : geometry::interior_rings(polygon)[section.ring_id.ring_index];
+ }
+};
+
+
+}} // namespace detail::section
+#endif
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template
+<
+ typename Tag,
+ typename Geometry,
+ typename Section
+>
+struct range_by_section
+{
+ BOOST_MPL_ASSERT_MSG
+ (
+ false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
+ , (types<Geometry>)
+ );
+};
+
+
+template <typename LineString, typename Section>
+struct range_by_section<linestring_tag, LineString, Section>
+ : detail::section::full_section_range<LineString, Section>
+{};
+
+
+template <typename Ring, typename Section>
+struct range_by_section<ring_tag, Ring, Section>
+ : detail::section::full_section_range<Ring, Section>
+{};
+
+
+template <typename Polygon, typename Section>
+struct range_by_section<polygon_tag, Polygon, Section>
+ : detail::section::full_section_polygon<Polygon, Section>
+{};
+
+
+} // namespace dispatch
+#endif
+
+
+/*!
+ \brief Get full ring (exterior, one of interiors, one from multi)
+ indicated by the specified section
+ \ingroup sectionalize
+ \tparam Geometry type
+ \tparam Section type of section to get from
+ \param geometry geometry to take section of
+ \param section structure with section
+ */
+template <typename Geometry, typename Section>
+inline typename ring_return_type<Geometry const>::type
+ range_by_section(Geometry const& geometry, Section const& section)
+{
+ concept::check<Geometry const>();
+
+ return dispatch::range_by_section
+ <
+ typename tag<Geometry>::type,
+ Geometry,
+ Section
+ >::apply(geometry, section);
+}
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_RANGE_BY_SECTION_HPP
diff --git a/boost/geometry/algorithms/detail/sections/sectionalize.hpp b/boost/geometry/algorithms/detail/sections/sectionalize.hpp
new file mode 100644
index 0000000000..36bcbdd6e7
--- /dev/null
+++ b/boost/geometry/algorithms/detail/sections/sectionalize.hpp
@@ -0,0 +1,648 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP
+
+#include <cstddef>
+#include <vector>
+
+#include <boost/mpl/assert.hpp>
+#include <boost/range.hpp>
+#include <boost/typeof/typeof.hpp>
+
+#include <boost/geometry/algorithms/assign.hpp>
+#include <boost/geometry/algorithms/expand.hpp>
+
+#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
+
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/closure.hpp>
+#include <boost/geometry/core/exterior_ring.hpp>
+#include <boost/geometry/core/point_order.hpp>
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+#include <boost/geometry/util/math.hpp>
+#include <boost/geometry/views/closeable_view.hpp>
+#include <boost/geometry/views/reversible_view.hpp>
+#include <boost/geometry/geometries/segment.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+/*!
+ \brief Structure containing section information
+ \details Section information consists of a bounding box, direction
+ information (if it is increasing or decreasing, per dimension),
+ index information (begin-end, ring, multi) and the number of
+ segments in this section
+
+ \tparam Box box-type
+ \tparam DimensionCount number of dimensions for this section
+ \ingroup sectionalize
+ */
+template <typename Box, std::size_t DimensionCount>
+struct section
+{
+ typedef Box box_type;
+
+ int id; // might be obsolete now, BSG 14-03-2011 TODO decide about this
+
+ int directions[DimensionCount];
+ ring_identifier ring_id;
+ Box bounding_box;
+
+ int begin_index;
+ int end_index;
+ std::size_t count;
+ std::size_t range_count;
+ bool duplicate;
+ int non_duplicate_index;
+
+ inline section()
+ : id(-1)
+ , begin_index(-1)
+ , end_index(-1)
+ , count(0)
+ , range_count(0)
+ , duplicate(false)
+ , non_duplicate_index(-1)
+ {
+ assign_inverse(bounding_box);
+ for (register std::size_t i = 0; i < DimensionCount; i++)
+ {
+ directions[i] = 0;
+ }
+ }
+};
+
+
+/*!
+ \brief Structure containing a collection of sections
+ \note Derived from a vector, proves to be faster than of deque
+ \note vector might be templated in the future
+ \ingroup sectionalize
+ */
+template <typename Box, std::size_t DimensionCount>
+struct sections : std::vector<section<Box, DimensionCount> >
+{
+ typedef Box box_type;
+ static std::size_t const value = DimensionCount;
+};
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace sectionalize
+{
+
+template <typename Segment, std::size_t Dimension, std::size_t DimensionCount>
+struct get_direction_loop
+{
+ typedef typename coordinate_type<Segment>::type coordinate_type;
+
+ static inline void apply(Segment const& seg,
+ int directions[DimensionCount])
+ {
+ coordinate_type const diff =
+ geometry::get<1, Dimension>(seg) - geometry::get<0, Dimension>(seg);
+
+ coordinate_type zero = coordinate_type();
+ directions[Dimension] = diff > zero ? 1 : diff < zero ? -1 : 0;
+
+ get_direction_loop
+ <
+ Segment, Dimension + 1, DimensionCount
+ >::apply(seg, directions);
+ }
+};
+
+template <typename Segment, std::size_t DimensionCount>
+struct get_direction_loop<Segment, DimensionCount, DimensionCount>
+{
+ static inline void apply(Segment const&, int [DimensionCount])
+ {}
+};
+
+template <typename T, std::size_t Dimension, std::size_t DimensionCount>
+struct copy_loop
+{
+ static inline void apply(T const source[DimensionCount],
+ T target[DimensionCount])
+ {
+ target[Dimension] = source[Dimension];
+ copy_loop<T, Dimension + 1, DimensionCount>::apply(source, target);
+ }
+};
+
+template <typename T, std::size_t DimensionCount>
+struct copy_loop<T, DimensionCount, DimensionCount>
+{
+ static inline void apply(T const [DimensionCount], T [DimensionCount])
+ {}
+};
+
+template <typename T, std::size_t Dimension, std::size_t DimensionCount>
+struct compare_loop
+{
+ static inline bool apply(T const source[DimensionCount],
+ T const target[DimensionCount])
+ {
+ bool const not_equal = target[Dimension] != source[Dimension];
+
+ return not_equal
+ ? false
+ : compare_loop
+ <
+ T, Dimension + 1, DimensionCount
+ >::apply(source, target);
+ }
+};
+
+template <typename T, std::size_t DimensionCount>
+struct compare_loop<T, DimensionCount, DimensionCount>
+{
+ static inline bool apply(T const [DimensionCount],
+ T const [DimensionCount])
+ {
+
+ return true;
+ }
+};
+
+
+template <typename Segment, std::size_t Dimension, std::size_t DimensionCount>
+struct check_duplicate_loop
+{
+ typedef typename coordinate_type<Segment>::type coordinate_type;
+
+ static inline bool apply(Segment const& seg)
+ {
+ if (! geometry::math::equals
+ (
+ geometry::get<0, Dimension>(seg),
+ geometry::get<1, Dimension>(seg)
+ )
+ )
+ {
+ return false;
+ }
+
+ return check_duplicate_loop
+ <
+ Segment, Dimension + 1, DimensionCount
+ >::apply(seg);
+ }
+};
+
+template <typename Segment, std::size_t DimensionCount>
+struct check_duplicate_loop<Segment, DimensionCount, DimensionCount>
+{
+ static inline bool apply(Segment const&)
+ {
+ return true;
+ }
+};
+
+template <typename T, std::size_t Dimension, std::size_t DimensionCount>
+struct assign_loop
+{
+ static inline void apply(T dims[DimensionCount], int const value)
+ {
+ dims[Dimension] = value;
+ assign_loop<T, Dimension + 1, DimensionCount>::apply(dims, value);
+ }
+};
+
+template <typename T, std::size_t DimensionCount>
+struct assign_loop<T, DimensionCount, DimensionCount>
+{
+ static inline void apply(T [DimensionCount], int const)
+ {
+ }
+};
+
+/// @brief Helper class to create sections of a part of a range, on the fly
+template
+<
+ typename Range, // Can be closeable_view
+ typename Point,
+ typename Sections,
+ std::size_t DimensionCount,
+ std::size_t MaxCount
+>
+struct sectionalize_part
+{
+ typedef model::referring_segment<Point const> segment_type;
+ typedef typename boost::range_value<Sections>::type section_type;
+
+ typedef typename boost::range_iterator<Range const>::type iterator_type;
+
+ static inline void apply(Sections& sections, section_type& section,
+ int& index, int& ndi,
+ Range const& range,
+ ring_identifier ring_id)
+ {
+ if (boost::size(range) <= index)
+ {
+ return;
+ }
+
+ if (index == 0)
+ {
+ ndi = 0;
+ }
+
+ iterator_type it = boost::begin(range);
+ it += index;
+
+ for(iterator_type previous = it++;
+ it != boost::end(range);
+ ++previous, ++it, index++)
+ {
+ segment_type segment(*previous, *it);
+
+ int direction_classes[DimensionCount] = {0};
+ get_direction_loop
+ <
+ segment_type, 0, DimensionCount
+ >::apply(segment, direction_classes);
+
+ // if "dir" == 0 for all point-dimensions, it is duplicate.
+ // Those sections might be omitted, if wished, lateron
+ bool duplicate = false;
+
+ if (direction_classes[0] == 0)
+ {
+ // Recheck because ALL dimensions should be checked,
+ // not only first one.
+ // (DimensionCount might be < dimension<P>::value)
+ if (check_duplicate_loop
+ <
+ segment_type, 0, geometry::dimension<Point>::type::value
+ >::apply(segment)
+ )
+ {
+ duplicate = true;
+
+ // Change direction-info to force new section
+ // Note that wo consecutive duplicate segments will generate
+ // only one duplicate-section.
+ // Actual value is not important as long as it is not -1,0,1
+ assign_loop
+ <
+ int, 0, DimensionCount
+ >::apply(direction_classes, -99);
+ }
+ }
+
+ if (section.count > 0
+ && (!compare_loop
+ <
+ int, 0, DimensionCount
+ >::apply(direction_classes, section.directions)
+ || section.count > MaxCount
+ )
+ )
+ {
+ sections.push_back(section);
+ section = section_type();
+ }
+
+ if (section.count == 0)
+ {
+ section.begin_index = index;
+ section.ring_id = ring_id;
+ section.duplicate = duplicate;
+ section.non_duplicate_index = ndi;
+ section.range_count = boost::size(range);
+
+ copy_loop
+ <
+ int, 0, DimensionCount
+ >::apply(direction_classes, section.directions);
+ geometry::expand(section.bounding_box, *previous);
+ }
+
+ geometry::expand(section.bounding_box, *it);
+ section.end_index = index + 1;
+ section.count++;
+ if (! duplicate)
+ {
+ ndi++;
+ }
+ }
+ }
+};
+
+
+template
+<
+ typename Range, closure_selector Closure, bool Reverse,
+ typename Point,
+ typename Sections,
+ std::size_t DimensionCount,
+ std::size_t MaxCount
+>
+struct sectionalize_range
+{
+ typedef typename closeable_view<Range const, Closure>::type cview_type;
+ typedef typename reversible_view
+ <
+ cview_type const,
+ Reverse ? iterate_reverse : iterate_forward
+ >::type view_type;
+
+ static inline void apply(Range const& range, Sections& sections,
+ ring_identifier ring_id)
+ {
+ typedef model::referring_segment<Point const> segment_type;
+
+ cview_type cview(range);
+ view_type view(cview);
+
+ std::size_t const n = boost::size(view);
+ if (n == 0)
+ {
+ // Zero points, no section
+ return;
+ }
+
+ if (n == 1)
+ {
+ // Line with one point ==> no sections
+ return;
+ }
+
+ int index = 0;
+ int ndi = 0; // non duplicate index
+
+ typedef typename boost::range_value<Sections>::type section_type;
+ section_type section;
+
+ sectionalize_part
+ <
+ view_type, Point, Sections,
+ DimensionCount, MaxCount
+ >::apply(sections, section, index, ndi,
+ view, ring_id);
+
+ // Add last section if applicable
+ if (section.count > 0)
+ {
+ sections.push_back(section);
+ }
+ }
+};
+
+template
+<
+ typename Polygon,
+ bool Reverse,
+ typename Sections,
+ std::size_t DimensionCount,
+ std::size_t MaxCount
+>
+struct sectionalize_polygon
+{
+ static inline void apply(Polygon const& poly, Sections& sections,
+ ring_identifier ring_id)
+ {
+ typedef typename point_type<Polygon>::type point_type;
+ typedef typename ring_type<Polygon>::type ring_type;
+ typedef sectionalize_range
+ <
+ ring_type, closure<Polygon>::value, Reverse,
+ point_type, Sections, DimensionCount, MaxCount
+ > sectionalizer_type;
+
+ ring_id.ring_index = -1;
+ sectionalizer_type::apply(exterior_ring(poly), sections, ring_id);//-1, multi_index);
+
+ ring_id.ring_index++;
+ typename interior_return_type<Polygon const>::type rings
+ = interior_rings(poly);
+ for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings);
+ ++it, ++ring_id.ring_index)
+ {
+ sectionalizer_type::apply(*it, sections, ring_id);
+ }
+ }
+};
+
+template
+<
+ typename Box,
+ typename Sections,
+ std::size_t DimensionCount,
+ std::size_t MaxCount
+>
+struct sectionalize_box
+{
+ static inline void apply(Box const& box, Sections& sections, ring_identifier const& ring_id)
+ {
+ typedef typename point_type<Box>::type point_type;
+
+ assert_dimension<Box, 2>();
+
+ // Add all four sides of the 2D-box as separate section.
+ // Easiest is to convert it to a polygon.
+ // However, we don't have the polygon type
+ // (or polygon would be a helper-type).
+ // Therefore we mimic a linestring/std::vector of 5 points
+
+ // TODO: might be replaced by assign_box_corners_oriented
+ // or just "convert"
+ point_type ll, lr, ul, ur;
+ geometry::detail::assign_box_corners(box, ll, lr, ul, ur);
+
+ std::vector<point_type> points;
+ points.push_back(ll);
+ points.push_back(ul);
+ points.push_back(ur);
+ points.push_back(lr);
+ points.push_back(ll);
+
+ sectionalize_range
+ <
+ std::vector<point_type>, closed, false,
+ point_type,
+ Sections,
+ DimensionCount,
+ MaxCount
+ >::apply(points, sections, ring_id);
+ }
+};
+
+template <typename Sections>
+inline void set_section_unique_ids(Sections& sections)
+{
+ // Set ID's.
+ int index = 0;
+ for (typename boost::range_iterator<Sections>::type it = boost::begin(sections);
+ it != boost::end(sections);
+ ++it)
+ {
+ it->id = index++;
+ }
+}
+
+
+}} // namespace detail::sectionalize
+#endif // DOXYGEN_NO_DETAIL
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+template
+<
+ typename Tag,
+ typename Geometry,
+ bool Reverse,
+ typename Sections,
+ std::size_t DimensionCount,
+ std::size_t MaxCount
+>
+struct sectionalize
+{
+ BOOST_MPL_ASSERT_MSG
+ (
+ false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
+ , (types<Geometry>)
+ );
+};
+
+template
+<
+ typename Box,
+ bool Reverse,
+ typename Sections,
+ std::size_t DimensionCount,
+ std::size_t MaxCount
+>
+struct sectionalize<box_tag, Box, Reverse, Sections, DimensionCount, MaxCount>
+ : detail::sectionalize::sectionalize_box
+ <
+ Box,
+ Sections,
+ DimensionCount,
+ MaxCount
+ >
+{};
+
+template
+<
+ typename LineString,
+ typename Sections,
+ std::size_t DimensionCount,
+ std::size_t MaxCount
+>
+struct sectionalize
+ <
+ linestring_tag,
+ LineString,
+ false,
+ Sections,
+ DimensionCount,
+ MaxCount
+ >
+ : detail::sectionalize::sectionalize_range
+ <
+ LineString, closed, false,
+ typename point_type<LineString>::type,
+ Sections,
+ DimensionCount,
+ MaxCount
+ >
+{};
+
+template
+<
+ typename Ring,
+ bool Reverse,
+ typename Sections,
+ std::size_t DimensionCount,
+ std::size_t MaxCount
+>
+struct sectionalize<ring_tag, Ring, Reverse, Sections, DimensionCount, MaxCount>
+ : detail::sectionalize::sectionalize_range
+ <
+ Ring, geometry::closure<Ring>::value, Reverse,
+ typename point_type<Ring>::type,
+ Sections,
+ DimensionCount,
+ MaxCount
+ >
+{};
+
+template
+<
+ typename Polygon,
+ bool Reverse,
+ typename Sections,
+ std::size_t DimensionCount,
+ std::size_t MaxCount
+>
+struct sectionalize<polygon_tag, Polygon, Reverse, Sections, DimensionCount, MaxCount>
+ : detail::sectionalize::sectionalize_polygon
+ <
+ Polygon, Reverse, Sections, DimensionCount, MaxCount
+ >
+{};
+
+} // namespace dispatch
+#endif
+
+
+/*!
+ \brief Split a geometry into monotonic sections
+ \ingroup sectionalize
+ \tparam Geometry type of geometry to check
+ \tparam Sections type of sections to create
+ \param geometry geometry to create sections from
+ \param sections structure with sections
+ \param source_index index to assign to the ring_identifiers
+ */
+template<bool Reverse, typename Geometry, typename Sections>
+inline void sectionalize(Geometry const& geometry, Sections& sections, int source_index = 0)
+{
+ concept::check<Geometry const>();
+
+ // TODO: review use of this constant (see below) as causing problems with GCC 4.6 --mloskot
+ // A maximum of 10 segments per section seems to give the fastest results
+ //static std::size_t const max_segments_per_section = 10;
+ typedef dispatch::sectionalize
+ <
+ typename tag<Geometry>::type,
+ Geometry,
+ Reverse,
+ Sections,
+ Sections::value,
+ 10 // TODO: max_segments_per_section
+ > sectionalizer_type;
+
+ sections.clear();
+ ring_identifier ring_id;
+ ring_id.source_index = source_index;
+ sectionalizer_type::apply(geometry, sections, ring_id);
+ detail::sectionalize::set_section_unique_ids(sections);
+}
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP
diff --git a/boost/geometry/algorithms/detail/throw_on_empty_input.hpp b/boost/geometry/algorithms/detail/throw_on_empty_input.hpp
new file mode 100644
index 0000000000..62328a0d87
--- /dev/null
+++ b/boost/geometry/algorithms/detail/throw_on_empty_input.hpp
@@ -0,0 +1,53 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_THROW_ON_EMPTY_INPUT_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_THROW_ON_EMPTY_INPUT_HPP
+
+#include <boost/geometry/core/exception.hpp>
+#include <boost/geometry/algorithms/num_points.hpp>
+
+// BSG 2012-02-06: we use this currently only for distance.
+// For other scalar results area,length,perimeter it is commented on purpose.
+// Reason is that for distance there is no other choice. distance of two
+// empty geometries (or one empty) should NOT return any value.
+// But for area it is no problem to be 0.
+// Suppose: area(intersection(a,b)). We (probably) don't want a throw there...
+
+// So decided that at least for Boost 1.49 this is commented for
+// scalar results, except distance.
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail
+{
+
+template <typename Geometry>
+inline void throw_on_empty_input(Geometry const& geometry)
+{
+#if ! defined(BOOST_GEOMETRY_EMPTY_INPUT_NO_THROW)
+ if (geometry::num_points(geometry) == 0)
+ {
+ throw empty_input_exception();
+ }
+#endif
+}
+
+} // namespace detail
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_THROW_ON_EMPTY_INPUT_HPP
+