summaryrefslogtreecommitdiff
path: root/boost/geometry/algorithms
diff options
context:
space:
mode:
Diffstat (limited to 'boost/geometry/algorithms')
-rw-r--r--boost/geometry/algorithms/correct.hpp95
-rw-r--r--boost/geometry/algorithms/covered_by.hpp439
-rw-r--r--boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp221
-rw-r--r--boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp45
-rw-r--r--boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp38
-rw-r--r--boost/geometry/algorithms/detail/buffer/turn_in_original_visitor.hpp10
-rw-r--r--boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp27
-rw-r--r--boost/geometry/algorithms/detail/covered_by/implementation.hpp280
-rw-r--r--boost/geometry/algorithms/detail/covered_by/interface.hpp261
-rw-r--r--boost/geometry/algorithms/detail/direction_code.hpp221
-rw-r--r--boost/geometry/algorithms/detail/disjoint/box_box.hpp13
-rw-r--r--boost/geometry/algorithms/detail/disjoint/implementation.hpp4
-rw-r--r--boost/geometry/algorithms/detail/disjoint/multipoint_geometry.hpp249
-rw-r--r--boost/geometry/algorithms/detail/disjoint/segment_box.hpp167
-rw-r--r--boost/geometry/algorithms/detail/envelope/segment.hpp125
-rw-r--r--boost/geometry/algorithms/detail/equals/implementation.hpp397
-rw-r--r--boost/geometry/algorithms/detail/equals/interface.hpp317
-rw-r--r--boost/geometry/algorithms/detail/extreme_points.hpp93
-rw-r--r--boost/geometry/algorithms/detail/get_left_turns.hpp40
-rw-r--r--boost/geometry/algorithms/detail/has_self_intersections.hpp2
-rw-r--r--boost/geometry/algorithms/detail/intersects/implementation.hpp88
-rw-r--r--boost/geometry/algorithms/detail/intersects/interface.hpp115
-rw-r--r--boost/geometry/algorithms/detail/is_simple/linear.hpp48
-rw-r--r--boost/geometry/algorithms/detail/is_valid/has_spikes.hpp15
-rw-r--r--boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp2
-rw-r--r--boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp13
-rw-r--r--boost/geometry/algorithms/detail/is_valid/linear.hpp36
-rw-r--r--boost/geometry/algorithms/detail/is_valid/multipolygon.hpp75
-rw-r--r--boost/geometry/algorithms/detail/is_valid/polygon.hpp155
-rw-r--r--boost/geometry/algorithms/detail/is_valid/ring.hpp7
-rw-r--r--boost/geometry/algorithms/detail/multi_modify.hpp16
-rw-r--r--boost/geometry/algorithms/detail/occupation_info.hpp19
-rw-r--r--boost/geometry/algorithms/detail/overlaps/implementation.hpp156
-rw-r--r--boost/geometry/algorithms/detail/overlaps/interface.hpp124
-rw-r--r--boost/geometry/algorithms/detail/overlay/aggregate_operations.hpp166
-rw-r--r--boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp13
-rw-r--r--boost/geometry/algorithms/detail/overlay/assign_parents.hpp136
-rw-r--r--boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp1
-rw-r--r--boost/geometry/algorithms/detail/overlay/copy_segments.hpp34
-rw-r--r--boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp172
-rw-r--r--boost/geometry/algorithms/detail/overlay/enrichment_info.hpp13
-rw-r--r--boost/geometry/algorithms/detail/overlay/follow.hpp121
-rw-r--r--boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp41
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_relative_order.hpp32
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_turn_info.hpp14
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp2
-rw-r--r--boost/geometry/algorithms/detail/overlay/get_turns.hpp34
-rw-r--r--boost/geometry/algorithms/detail/overlay/handle_colocations.hpp148
-rw-r--r--boost/geometry/algorithms/detail/overlay/handle_self_turns.hpp143
-rw-r--r--boost/geometry/algorithms/detail/overlay/intersection_insert.hpp46
-rw-r--r--boost/geometry/algorithms/detail/overlay/is_self_turn.hpp68
-rw-r--r--boost/geometry/algorithms/detail/overlay/less_by_segment_ratio.hpp24
-rw-r--r--boost/geometry/algorithms/detail/overlay/linear_linear.hpp10
-rw-r--r--boost/geometry/algorithms/detail/overlay/overlay.hpp134
-rw-r--r--boost/geometry/algorithms/detail/overlay/pointlike_linear.hpp69
-rw-r--r--boost/geometry/algorithms/detail/overlay/range_in_geometry.hpp178
-rw-r--r--boost/geometry/algorithms/detail/overlay/ring_properties.hpp19
-rw-r--r--boost/geometry/algorithms/detail/overlay/select_rings.hpp114
-rw-r--r--boost/geometry/algorithms/detail/overlay/self_turn_points.hpp151
-rw-r--r--boost/geometry/algorithms/detail/overlay/sort_by_side.hpp160
-rw-r--r--boost/geometry/algorithms/detail/overlay/traversal.hpp434
-rw-r--r--boost/geometry/algorithms/detail/overlay/traversal_intersection_patterns.hpp306
-rw-r--r--boost/geometry/algorithms/detail/overlay/traversal_ring_creator.hpp42
-rw-r--r--boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp408
-rw-r--r--boost/geometry/algorithms/detail/overlay/turn_info.hpp11
-rw-r--r--boost/geometry/algorithms/detail/partition.hpp294
-rw-r--r--boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp76
-rw-r--r--boost/geometry/algorithms/detail/point_on_border.hpp193
-rw-r--r--boost/geometry/algorithms/detail/relate/implementation.hpp11
-rw-r--r--boost/geometry/algorithms/detail/relate/multi_point_geometry.hpp568
-rw-r--r--boost/geometry/algorithms/detail/relate/point_geometry.hpp38
-rw-r--r--boost/geometry/algorithms/detail/relate/point_point.hpp54
-rw-r--r--boost/geometry/algorithms/detail/relate/topology_check.hpp244
-rw-r--r--boost/geometry/algorithms/detail/sections/section_functions.hpp96
-rw-r--r--boost/geometry/algorithms/detail/sections/sectionalize.hpp194
-rw-r--r--boost/geometry/algorithms/detail/touches/implementation.hpp459
-rw-r--r--boost/geometry/algorithms/detail/touches/interface.hpp321
-rw-r--r--boost/geometry/algorithms/detail/within/implementation.hpp306
-rw-r--r--boost/geometry/algorithms/detail/within/interface.hpp304
-rw-r--r--boost/geometry/algorithms/detail/within/multi_point.hpp268
-rw-r--r--boost/geometry/algorithms/equals.hpp645
-rw-r--r--boost/geometry/algorithms/intersects.hpp116
-rw-r--r--boost/geometry/algorithms/is_convex.hpp92
-rw-r--r--boost/geometry/algorithms/overlaps.hpp210
-rw-r--r--boost/geometry/algorithms/point_on_surface.hpp56
-rw-r--r--boost/geometry/algorithms/remove_spikes.hpp112
-rw-r--r--boost/geometry/algorithms/touches.hpp683
-rw-r--r--boost/geometry/algorithms/within.hpp500
88 files changed, 8800 insertions, 4197 deletions
diff --git a/boost/geometry/algorithms/correct.hpp b/boost/geometry/algorithms/correct.hpp
index 5d3b6939af..a572d921d5 100644
--- a/boost/geometry/algorithms/correct.hpp
+++ b/boost/geometry/algorithms/correct.hpp
@@ -5,6 +5,10 @@
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
+// This file was modified by Oracle on 2017.
+// Modifications copyright (c) 2017 Oracle and/or its affiliates.
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -61,7 +65,8 @@ namespace detail { namespace correct
template <typename Geometry>
struct correct_nop
{
- static inline void apply(Geometry& )
+ template <typename Strategy>
+ static inline void apply(Geometry& , Strategy const& )
{}
};
@@ -104,8 +109,8 @@ struct correct_box_loop<Box, DimensionCount, DimensionCount>
template <typename Box>
struct correct_box
{
-
- static inline void apply(Box& box)
+ template <typename Strategy>
+ static inline void apply(Box& box, Strategy const& )
{
// Currently only for Cartesian coordinates
// (or spherical without crossing dateline)
@@ -119,18 +124,12 @@ struct correct_box
// Close a ring, if not closed
-template <typename Ring, typename Predicate>
+template <typename Ring, template <typename> class Predicate>
struct correct_ring
{
typedef typename point_type<Ring>::type point_type;
typedef typename coordinate_type<Ring>::type coordinate_type;
- typedef typename strategy::area::services::default_strategy
- <
- typename cs_tag<point_type>::type,
- point_type
- >::type strategy_type;
-
typedef detail::area::ring_area
<
order_as_direction<geometry::point_order<Ring>::value>::value,
@@ -138,7 +137,8 @@ struct correct_ring
> ring_area_type;
- static inline void apply(Ring& r)
+ template <typename Strategy>
+ static inline void apply(Ring& r, Strategy const& strategy)
{
// Check close-ness
if (boost::size(r) > 2)
@@ -158,10 +158,10 @@ struct correct_ring
}
}
// Check area
- Predicate predicate;
- typedef typename default_area_result<Ring>::type area_result_type;
- area_result_type const zero = area_result_type();
- if (predicate(ring_area_type::apply(r, strategy_type()), zero))
+ typedef typename Strategy::return_type area_result_type;
+ Predicate<area_result_type> predicate;
+ area_result_type const zero = 0;
+ if (predicate(ring_area_type::apply(r, strategy), zero))
{
std::reverse(boost::begin(r), boost::end(r));
}
@@ -174,15 +174,15 @@ template <typename Polygon>
struct correct_polygon
{
typedef typename ring_type<Polygon>::type ring_type;
- typedef typename default_area_result<Polygon>::type area_result_type;
-
- static inline void apply(Polygon& poly)
+
+ template <typename Strategy>
+ static inline void apply(Polygon& poly, Strategy const& strategy)
{
correct_ring
<
ring_type,
- std::less<area_result_type>
- >::apply(exterior_ring(poly));
+ std::less
+ >::apply(exterior_ring(poly), strategy);
typename interior_return_type<Polygon>::type
rings = interior_rings(poly);
@@ -192,8 +192,8 @@ struct correct_polygon
correct_ring
<
ring_type,
- std::greater<area_result_type>
- >::apply(*it);
+ std::greater
+ >::apply(*it, strategy);
}
}
};
@@ -237,7 +237,7 @@ struct correct<Ring, ring_tag>
: detail::correct::correct_ring
<
Ring,
- std::less<typename default_area_result<Ring>::type>
+ std::less
>
{};
@@ -281,29 +281,36 @@ namespace resolve_variant {
template <typename Geometry>
struct correct
{
- static inline void apply(Geometry& geometry)
+ template <typename Strategy>
+ static inline void apply(Geometry& geometry, Strategy const& strategy)
{
concepts::check<Geometry const>();
- dispatch::correct<Geometry>::apply(geometry);
+ dispatch::correct<Geometry>::apply(geometry, strategy);
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct correct<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
{
+ template <typename Strategy>
struct visitor: boost::static_visitor<void>
{
+ Strategy const& m_strategy;
+
+ visitor(Strategy const& strategy): m_strategy(strategy) {}
+
template <typename Geometry>
void operator()(Geometry& geometry) const
{
- correct<Geometry>::apply(geometry);
+ correct<Geometry>::apply(geometry, m_strategy);
}
};
+ template <typename Strategy>
static inline void
- apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry)
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry, Strategy const& strategy)
{
- boost::apply_visitor(visitor(), geometry);
+ boost::apply_visitor(visitor<Strategy>(strategy), geometry);
}
};
@@ -325,7 +332,37 @@ struct correct<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
template <typename Geometry>
inline void correct(Geometry& geometry)
{
- resolve_variant::correct<Geometry>::apply(geometry);
+ typedef typename point_type<Geometry>::type point_type;
+
+ typedef typename strategy::area::services::default_strategy
+ <
+ typename cs_tag<point_type>::type,
+ point_type
+ >::type strategy_type;
+
+ resolve_variant::correct<Geometry>::apply(geometry, strategy_type());
+}
+
+/*!
+\brief Corrects a geometry
+\details Corrects a geometry: all rings which are wrongly oriented with respect
+ to their expected orientation are reversed. To all rings which do not have a
+ closing point and are typed as they should have one, the first point is
+ appended. Also boxes can be corrected.
+\ingroup correct
+\tparam Geometry \tparam_geometry
+\tparam Strategy \tparam_strategy{Area}
+\param geometry \param_geometry which will be corrected if necessary
+\param strategy \param_strategy{area}
+
+\qbk{distinguish,with strategy}
+
+\qbk{[include reference/algorithms/correct.qbk]}
+*/
+template <typename Geometry, typename Strategy>
+inline void correct(Geometry& geometry, Strategy const& strategy)
+{
+ resolve_variant::correct<Geometry>::apply(geometry, strategy);
}
#if defined(_MSC_VER)
diff --git a/boost/geometry/algorithms/covered_by.hpp b/boost/geometry/algorithms/covered_by.hpp
index f9d9dcc486..d68429673a 100644
--- a/boost/geometry/algorithms/covered_by.hpp
+++ b/boost/geometry/algorithms/covered_by.hpp
@@ -20,443 +20,8 @@
#define BOOST_GEOMETRY_ALGORITHMS_COVERED_BY_HPP
-#include <cstddef>
+#include <boost/geometry/algorithms/detail/covered_by/interface.hpp>
+#include <boost/geometry/algorithms/detail/covered_by/implementation.hpp>
-#include <boost/variant/apply_visitor.hpp>
-#include <boost/variant/static_visitor.hpp>
-#include <boost/variant/variant_fwd.hpp>
-
-#include <boost/geometry/algorithms/not_implemented.hpp>
-#include <boost/geometry/algorithms/within.hpp>
-
-#include <boost/geometry/strategies/cartesian/point_in_box.hpp>
-#include <boost/geometry/strategies/cartesian/box_in_box.hpp>
-#include <boost/geometry/strategies/default_strategy.hpp>
-
-namespace boost { namespace geometry
-{
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace covered_by {
-
-struct use_point_in_geometry
-{
- template <typename Geometry1, typename Geometry2, typename Strategy>
- static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
- {
- return detail::within::point_in_geometry(geometry1, geometry2, strategy) >= 0;
- }
-};
-
-struct use_relate
-{
- template <typename Geometry1, typename Geometry2, typename Strategy>
- static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
- {
- typedef typename detail::de9im::static_mask_covered_by_type
- <
- Geometry1, Geometry2
- >::type covered_by_mask;
- return geometry::relate(geometry1, geometry2, covered_by_mask(), strategy);
- }
-};
-
-}} // namespace detail::covered_by
-#endif // DOXYGEN_NO_DETAIL
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-template
-<
- typename Geometry1,
- typename Geometry2,
- typename Tag1 = typename tag<Geometry1>::type,
- typename Tag2 = typename tag<Geometry2>::type
->
-struct covered_by
- : not_implemented<Tag1, Tag2>
-{};
-
-
-template <typename Point, typename Box>
-struct covered_by<Point, Box, point_tag, box_tag>
-{
- template <typename Strategy>
- static inline bool apply(Point const& point, Box const& box, Strategy const& strategy)
- {
- ::boost::ignore_unused_variable_warning(strategy);
- return strategy.apply(point, box);
- }
-};
-
-template <typename Box1, typename Box2>
-struct covered_by<Box1, Box2, box_tag, box_tag>
-{
- template <typename Strategy>
- static inline bool apply(Box1 const& box1, Box2 const& box2, Strategy const& strategy)
- {
- assert_dimension_equal<Box1, Box2>();
- ::boost::ignore_unused_variable_warning(strategy);
- return strategy.apply(box1, box2);
- }
-};
-
-
-// P/P
-
-template <typename Point1, typename Point2>
-struct covered_by<Point1, Point2, point_tag, point_tag>
- : public detail::covered_by::use_point_in_geometry
-{};
-
-template <typename Point, typename MultiPoint>
-struct covered_by<Point, MultiPoint, point_tag, multi_point_tag>
- : public detail::covered_by::use_point_in_geometry
-{};
-
-// P/L
-
-template <typename Point, typename Segment>
-struct covered_by<Point, Segment, point_tag, segment_tag>
- : public detail::covered_by::use_point_in_geometry
-{};
-
-template <typename Point, typename Linestring>
-struct covered_by<Point, Linestring, point_tag, linestring_tag>
- : public detail::covered_by::use_point_in_geometry
-{};
-
-template <typename Point, typename MultiLinestring>
-struct covered_by<Point, MultiLinestring, point_tag, multi_linestring_tag>
- : public detail::covered_by::use_point_in_geometry
-{};
-
-// P/A
-
-template <typename Point, typename Ring>
-struct covered_by<Point, Ring, point_tag, ring_tag>
- : public detail::covered_by::use_point_in_geometry
-{};
-
-template <typename Point, typename Polygon>
-struct covered_by<Point, Polygon, point_tag, polygon_tag>
- : public detail::covered_by::use_point_in_geometry
-{};
-
-template <typename Point, typename MultiPolygon>
-struct covered_by<Point, MultiPolygon, point_tag, multi_polygon_tag>
- : public detail::covered_by::use_point_in_geometry
-{};
-
-// L/L
-
-template <typename Linestring1, typename Linestring2>
-struct covered_by<Linestring1, Linestring2, linestring_tag, linestring_tag>
- : public detail::covered_by::use_relate
-{};
-
-template <typename Linestring, typename MultiLinestring>
-struct covered_by<Linestring, MultiLinestring, linestring_tag, multi_linestring_tag>
- : public detail::covered_by::use_relate
-{};
-
-template <typename MultiLinestring, typename Linestring>
-struct covered_by<MultiLinestring, Linestring, multi_linestring_tag, linestring_tag>
- : public detail::covered_by::use_relate
-{};
-
-template <typename MultiLinestring1, typename MultiLinestring2>
-struct covered_by<MultiLinestring1, MultiLinestring2, multi_linestring_tag, multi_linestring_tag>
- : public detail::covered_by::use_relate
-{};
-
-// L/A
-
-template <typename Linestring, typename Ring>
-struct covered_by<Linestring, Ring, linestring_tag, ring_tag>
- : public detail::covered_by::use_relate
-{};
-
-template <typename MultiLinestring, typename Ring>
-struct covered_by<MultiLinestring, Ring, multi_linestring_tag, ring_tag>
- : public detail::covered_by::use_relate
-{};
-
-template <typename Linestring, typename Polygon>
-struct covered_by<Linestring, Polygon, linestring_tag, polygon_tag>
- : public detail::covered_by::use_relate
-{};
-
-template <typename MultiLinestring, typename Polygon>
-struct covered_by<MultiLinestring, Polygon, multi_linestring_tag, polygon_tag>
- : public detail::covered_by::use_relate
-{};
-
-template <typename Linestring, typename MultiPolygon>
-struct covered_by<Linestring, MultiPolygon, linestring_tag, multi_polygon_tag>
- : public detail::covered_by::use_relate
-{};
-
-template <typename MultiLinestring, typename MultiPolygon>
-struct covered_by<MultiLinestring, MultiPolygon, multi_linestring_tag, multi_polygon_tag>
- : public detail::covered_by::use_relate
-{};
-
-// A/A
-
-template <typename Ring1, typename Ring2>
-struct covered_by<Ring1, Ring2, ring_tag, ring_tag>
- : public detail::covered_by::use_relate
-{};
-
-template <typename Ring, typename Polygon>
-struct covered_by<Ring, Polygon, ring_tag, polygon_tag>
- : public detail::covered_by::use_relate
-{};
-
-template <typename Polygon, typename Ring>
-struct covered_by<Polygon, Ring, polygon_tag, ring_tag>
- : public detail::covered_by::use_relate
-{};
-
-template <typename Polygon1, typename Polygon2>
-struct covered_by<Polygon1, Polygon2, polygon_tag, polygon_tag>
- : public detail::covered_by::use_relate
-{};
-
-template <typename Ring, typename MultiPolygon>
-struct covered_by<Ring, MultiPolygon, ring_tag, multi_polygon_tag>
- : public detail::covered_by::use_relate
-{};
-
-template <typename MultiPolygon, typename Ring>
-struct covered_by<MultiPolygon, Ring, multi_polygon_tag, ring_tag>
- : public detail::covered_by::use_relate
-{};
-
-template <typename Polygon, typename MultiPolygon>
-struct covered_by<Polygon, MultiPolygon, polygon_tag, multi_polygon_tag>
- : public detail::covered_by::use_relate
-{};
-
-template <typename MultiPolygon, typename Polygon>
-struct covered_by<MultiPolygon, Polygon, multi_polygon_tag, polygon_tag>
- : public detail::covered_by::use_relate
-{};
-
-template <typename MultiPolygon1, typename MultiPolygon2>
-struct covered_by<MultiPolygon1, MultiPolygon2, multi_polygon_tag, multi_polygon_tag>
- : public detail::covered_by::use_relate
-{};
-
-} // namespace dispatch
-#endif // DOXYGEN_NO_DISPATCH
-
-
-namespace resolve_strategy {
-
-struct covered_by
-{
- template <typename Geometry1, typename Geometry2, typename Strategy>
- static inline bool apply(Geometry1 const& geometry1,
- Geometry2 const& geometry2,
- Strategy const& strategy)
- {
- concepts::within::check
- <
- typename tag<Geometry1>::type,
- typename tag<Geometry2>::type,
- typename tag_cast<typename tag<Geometry2>::type, areal_tag>::type,
- Strategy
- >();
- concepts::check<Geometry1 const>();
- concepts::check<Geometry2 const>();
- assert_dimension_equal<Geometry1, Geometry2>();
-
- return dispatch::covered_by<Geometry1, Geometry2>::apply(geometry1,
- geometry2,
- strategy);
- }
-
- template <typename Geometry1, typename Geometry2>
- static inline bool apply(Geometry1 const& geometry1,
- Geometry2 const& geometry2,
- default_strategy)
- {
- typedef typename strategy::covered_by::services::default_strategy
- <
- Geometry1,
- Geometry2
- >::type strategy_type;
-
- return covered_by::apply(geometry1, geometry2, strategy_type());
- }
-};
-
-} // namespace resolve_strategy
-
-
-namespace resolve_variant {
-
-template <typename Geometry1, typename Geometry2>
-struct covered_by
-{
- template <typename Strategy>
- static inline bool apply(Geometry1 const& geometry1,
- Geometry2 const& geometry2,
- Strategy const& strategy)
- {
- return resolve_strategy::covered_by
- ::apply(geometry1, geometry2, strategy);
- }
-};
-
-template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
-struct covered_by<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
-{
- template <typename Strategy>
- struct visitor: boost::static_visitor<bool>
- {
- Geometry2 const& m_geometry2;
- Strategy const& m_strategy;
-
- visitor(Geometry2 const& geometry2, Strategy const& strategy)
- : m_geometry2(geometry2), m_strategy(strategy) {}
-
- template <typename Geometry1>
- bool operator()(Geometry1 const& geometry1) const
- {
- return covered_by<Geometry1, Geometry2>
- ::apply(geometry1, m_geometry2, m_strategy);
- }
- };
-
- template <typename Strategy>
- static inline bool
- apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
- Geometry2 const& geometry2,
- Strategy const& strategy)
- {
- return boost::apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1);
- }
-};
-
-template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
-struct covered_by<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
-{
- template <typename Strategy>
- struct visitor: boost::static_visitor<bool>
- {
- Geometry1 const& m_geometry1;
- Strategy const& m_strategy;
-
- visitor(Geometry1 const& geometry1, Strategy const& strategy)
- : m_geometry1(geometry1), m_strategy(strategy) {}
-
- template <typename Geometry2>
- bool operator()(Geometry2 const& geometry2) const
- {
- return covered_by<Geometry1, Geometry2>
- ::apply(m_geometry1, geometry2, m_strategy);
- }
- };
-
- template <typename Strategy>
- static inline bool
- apply(Geometry1 const& geometry1,
- boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2,
- Strategy const& strategy)
- {
- return boost::apply_visitor(visitor<Strategy>(geometry1, strategy), geometry2);
- }
-};
-
-template <
- BOOST_VARIANT_ENUM_PARAMS(typename T1),
- BOOST_VARIANT_ENUM_PARAMS(typename T2)
->
-struct covered_by<
- boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>,
- boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>
->
-{
- template <typename Strategy>
- struct visitor: boost::static_visitor<bool>
- {
- Strategy const& m_strategy;
-
- visitor(Strategy const& strategy): m_strategy(strategy) {}
-
- template <typename Geometry1, typename Geometry2>
- bool operator()(Geometry1 const& geometry1,
- Geometry2 const& geometry2) const
- {
- return covered_by<Geometry1, Geometry2>
- ::apply(geometry1, geometry2, m_strategy);
- }
- };
-
- template <typename Strategy>
- static inline bool
- apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1,
- boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2,
- Strategy const& strategy)
- {
- return boost::apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2);
- }
-};
-
-} // namespace resolve_variant
-
-
-/*!
-\brief \brief_check12{is inside or on border}
-\ingroup covered_by
-\details \details_check12{covered_by, is inside or on border}.
-\tparam Geometry1 \tparam_geometry
-\tparam Geometry2 \tparam_geometry
-\param geometry1 \param_geometry which might be inside or on the border of the second geometry
-\param geometry2 \param_geometry which might cover the first geometry
-\return true if geometry1 is inside of or on the border of geometry2,
- else false
-\note The default strategy is used for covered_by detection
-
-\qbk{[include reference/algorithms/covered_by.qbk]}
-
- */
-template<typename Geometry1, typename Geometry2>
-inline bool covered_by(Geometry1 const& geometry1, Geometry2 const& geometry2)
-{
- return resolve_variant::covered_by<Geometry1, Geometry2>
- ::apply(geometry1, geometry2, default_strategy());
-}
-
-/*!
-\brief \brief_check12{is inside or on border} \brief_strategy
-\ingroup covered_by
-\details \details_check12{covered_by, is inside or on border}, \brief_strategy. \details_strategy_reasons
-\tparam Geometry1 \tparam_geometry
-\tparam Geometry2 \tparam_geometry
-\param geometry1 \param_geometry which might be inside or on the border of the second geometry
-\param geometry2 \param_geometry which might cover the first geometry
-\param strategy strategy to be used
-\return true if geometry1 is inside of or on the border of geometry2,
- else false
-
-\qbk{distinguish,with strategy}
-\qbk{[include reference/algorithms/covered_by.qbk]}
-
-*/
-template<typename Geometry1, typename Geometry2, typename Strategy>
-inline bool covered_by(Geometry1 const& geometry1, Geometry2 const& geometry2,
- Strategy const& strategy)
-{
- return resolve_variant::covered_by<Geometry1, Geometry2>
- ::apply(geometry1, geometry2, strategy);
-}
-
-}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_COVERED_BY_HPP
diff --git a/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp b/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp
index 029053dda3..a149f1dd46 100644
--- a/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp
+++ b/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp
@@ -122,7 +122,8 @@ struct buffer_range
typename DistanceStrategy,
typename JoinStrategy,
typename EndStrategy,
- typename RobustPolicy
+ typename RobustPolicy,
+ typename Strategy
>
static inline
void add_join(Collection& collection,
@@ -133,18 +134,19 @@ struct buffer_range
Point const& input,
output_point_type const& perp1,
output_point_type const& perp2,
- strategy::buffer::buffer_side_selector side,
+ geometry::strategy::buffer::buffer_side_selector side,
DistanceStrategy const& distance,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
- RobustPolicy const& )
+ RobustPolicy const& ,
+ Strategy const& strategy) // side strategy
{
output_point_type intersection_point;
geometry::assign_zero(intersection_point);
- strategy::buffer::join_selector join
- = get_join_type(penultimate_input, previous_input, input);
- if (join == strategy::buffer::join_convex)
+ geometry::strategy::buffer::join_selector join
+ = get_join_type(penultimate_input, previous_input, input, strategy);
+ if (join == geometry::strategy::buffer::join_convex)
{
// Calculate the intersection-point formed by the two sides.
// It might be that the two sides are not convex, but continue
@@ -157,23 +159,23 @@ struct buffer_range
switch(join)
{
- case strategy::buffer::join_continue :
+ case geometry::strategy::buffer::join_continue :
// No join, we get two consecutive sides
break;
- case strategy::buffer::join_concave :
+ case geometry::strategy::buffer::join_concave :
{
std::vector<output_point_type> range_out;
range_out.push_back(prev_perp2);
range_out.push_back(previous_input);
- collection.add_piece(strategy::buffer::buffered_concave, previous_input, range_out);
+ collection.add_piece(geometry::strategy::buffer::buffered_concave, previous_input, range_out);
range_out.clear();
range_out.push_back(previous_input);
range_out.push_back(perp1);
- collection.add_piece(strategy::buffer::buffered_concave, previous_input, range_out);
+ collection.add_piece(geometry::strategy::buffer::buffered_concave, previous_input, range_out);
}
break;
- case strategy::buffer::join_spike :
+ case geometry::strategy::buffer::join_spike :
{
// For linestrings, only add spike at one side to avoid
// duplicates
@@ -183,7 +185,7 @@ struct buffer_range
collection.set_current_ring_concave();
}
break;
- case strategy::buffer::join_convex :
+ case geometry::strategy::buffer::join_convex :
{
// The corner is convex, we create a join
// TODO (future) - avoid a separate vector, add the piece directly
@@ -193,7 +195,7 @@ struct buffer_range
distance.apply(previous_input, input, side),
range_out))
{
- collection.add_piece(strategy::buffer::buffered_join,
+ collection.add_piece(geometry::strategy::buffer::buffered_join,
previous_input, range_out);
}
}
@@ -201,27 +203,24 @@ struct buffer_range
}
}
- static inline strategy::buffer::join_selector get_join_type(
+ template <typename Strategy>
+ static inline geometry::strategy::buffer::join_selector get_join_type(
output_point_type const& p0,
output_point_type const& p1,
- output_point_type const& p2)
+ output_point_type const& p2,
+ Strategy const& strategy) // side strategy
{
- typedef typename strategy::side::services::default_strategy
- <
- typename cs_tag<output_point_type>::type
- >::type side_strategy;
-
- int const side = side_strategy::apply(p0, p1, p2);
- return side == -1 ? strategy::buffer::join_convex
- : side == 1 ? strategy::buffer::join_concave
+ int const side = strategy.apply(p0, p1, p2);
+ return side == -1 ? geometry::strategy::buffer::join_convex
+ : side == 1 ? geometry::strategy::buffer::join_concave
: parallel_continue
(
get<0>(p2) - get<0>(p1),
get<1>(p2) - get<1>(p1),
get<0>(p1) - get<0>(p0),
get<1>(p1) - get<1>(p0)
- ) ? strategy::buffer::join_continue
- : strategy::buffer::join_spike;
+ ) ? geometry::strategy::buffer::join_continue
+ : geometry::strategy::buffer::join_spike;
}
template
@@ -232,16 +231,18 @@ struct buffer_range
typename SideStrategy,
typename JoinStrategy,
typename EndStrategy,
- typename RobustPolicy
+ typename RobustPolicy,
+ typename Strategy
>
- static inline strategy::buffer::result_code iterate(Collection& collection,
+ static inline geometry::strategy::buffer::result_code iterate(Collection& collection,
Iterator begin, Iterator end,
- strategy::buffer::buffer_side_selector side,
+ geometry::strategy::buffer::buffer_side_selector side,
DistanceStrategy const& distance_strategy,
SideStrategy const& side_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
RobustPolicy const& robust_policy,
+ Strategy const& strategy, // side strategy
output_point_type& first_p1,
output_point_type& first_p2,
output_point_type& last_p1,
@@ -273,7 +274,7 @@ struct buffer_range
* pup: penultimate_point
*/
- strategy::buffer::result_code result = strategy::buffer::result_no_output;
+ geometry::strategy::buffer::result_code result = geometry::strategy::buffer::result_no_output;
bool first = true;
Iterator it = begin;
@@ -284,25 +285,25 @@ struct buffer_range
for (Iterator prev = it++; it != end; ++it)
{
generated_side.clear();
- strategy::buffer::result_code error_code
+ geometry::strategy::buffer::result_code error_code
= side_strategy.apply(*prev, *it, side,
distance_strategy, generated_side);
- if (error_code == strategy::buffer::result_no_output)
+ if (error_code == geometry::strategy::buffer::result_no_output)
{
// Because input is simplified, this is improbable,
// but it can happen for degenerate geometries
// Further handling of this side is skipped
continue;
}
- else if (error_code == strategy::buffer::result_error_numerical)
+ else if (error_code == geometry::strategy::buffer::result_error_numerical)
{
return error_code;
}
BOOST_GEOMETRY_ASSERT(! generated_side.empty());
- result = strategy::buffer::result_normal;
+ result = geometry::strategy::buffer::result_normal;
if (! first)
{
@@ -312,7 +313,7 @@ struct buffer_range
*it, generated_side.front(), generated_side.back(),
side,
distance_strategy, join_strategy, end_strategy,
- robust_policy);
+ robust_policy, strategy);
}
collection.add_side_piece(*prev, *it, generated_side, first);
@@ -350,7 +351,8 @@ struct buffer_multi
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
- typename RobustPolicy
+ typename RobustPolicy,
+ typename Strategy
>
static inline void apply(Multi const& multi,
Collection& collection,
@@ -359,7 +361,8 @@ struct buffer_multi
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
PointStrategy const& point_strategy,
- RobustPolicy const& robust_policy)
+ RobustPolicy const& robust_policy,
+ Strategy const& strategy) // side strategy
{
for (typename boost::range_iterator<Multi const>::type
it = boost::begin(multi);
@@ -369,7 +372,7 @@ struct buffer_multi
Policy::apply(*it, collection,
distance_strategy, side_strategy,
join_strategy, end_strategy, point_strategy,
- robust_policy);
+ robust_policy, strategy);
}
}
};
@@ -396,9 +399,9 @@ inline void buffer_point(Point const& point, Collection& collection,
collection.start_new_ring();
std::vector<OutputPointType> range_out;
point_strategy.apply(point, distance_strategy, range_out);
- collection.add_piece(strategy::buffer::buffered_point, range_out, false);
+ collection.add_piece(geometry::strategy::buffer::buffered_point, range_out, false);
collection.set_piece_center(point);
- collection.finish_ring(strategy::buffer::result_normal);
+ collection.finish_ring(geometry::strategy::buffer::result_normal);
}
@@ -436,7 +439,8 @@ struct buffer_inserter<point_tag, Point, RingOutput>
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
- typename RobustPolicy
+ typename RobustPolicy,
+ typename Strategy
>
static inline void apply(Point const& point, Collection& collection,
DistanceStrategy const& distance_strategy,
@@ -444,7 +448,8 @@ struct buffer_inserter<point_tag, Point, RingOutput>
JoinStrategy const& ,
EndStrategy const& ,
PointStrategy const& point_strategy,
- RobustPolicy const& )
+ RobustPolicy const& ,
+ Strategy const& ) // side strategy
{
detail::buffer::buffer_point
<
@@ -472,29 +477,32 @@ struct buffer_inserter_ring
typename SideStrategy,
typename JoinStrategy,
typename EndStrategy,
- typename RobustPolicy
+ typename RobustPolicy,
+ typename Strategy
>
- static inline strategy::buffer::result_code iterate(Collection& collection,
+ static inline geometry::strategy::buffer::result_code iterate(Collection& collection,
Iterator begin, Iterator end,
- strategy::buffer::buffer_side_selector side,
+ geometry::strategy::buffer::buffer_side_selector side,
DistanceStrategy const& distance_strategy,
SideStrategy const& side_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
- RobustPolicy const& robust_policy)
+ RobustPolicy const& robust_policy,
+ Strategy const& strategy) // side strategy
{
output_point_type first_p1, first_p2, last_p1, last_p2;
typedef detail::buffer::buffer_range<RingOutput> buffer_range;
- strategy::buffer::result_code result
+ geometry::strategy::buffer::result_code result
= buffer_range::iterate(collection, begin, end,
side,
- distance_strategy, side_strategy, join_strategy, end_strategy, robust_policy,
+ distance_strategy, side_strategy, join_strategy, end_strategy,
+ robust_policy, strategy,
first_p1, first_p2, last_p1, last_p2);
// Generate closing join
- if (result == strategy::buffer::result_normal)
+ if (result == geometry::strategy::buffer::result_normal)
{
buffer_range::add_join(collection,
*(end - 2),
@@ -502,7 +510,7 @@ struct buffer_inserter_ring
*(begin + 1), first_p1, first_p2,
side,
distance_strategy, join_strategy, end_strategy,
- robust_policy);
+ robust_policy, strategy);
}
// Buffer is closed automatically by last closing corner
@@ -517,21 +525,23 @@ struct buffer_inserter_ring
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
- typename RobustPolicy
+ typename RobustPolicy,
+ typename Strategy
>
- static inline strategy::buffer::result_code apply(RingInput const& ring,
+ static inline geometry::strategy::buffer::result_code apply(RingInput const& ring,
Collection& collection,
DistanceStrategy const& distance,
SideStrategy const& side_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
PointStrategy const& point_strategy,
- RobustPolicy const& robust_policy)
+ RobustPolicy const& robust_policy,
+ Strategy const& strategy) // side strategy
{
RingInput simplified;
detail::buffer::simplify_input(ring, distance, simplified);
- strategy::buffer::result_code code = strategy::buffer::result_no_output;
+ geometry::strategy::buffer::result_code code = geometry::strategy::buffer::result_no_output;
std::size_t n = boost::size(simplified);
std::size_t const min_points = core_detail::closure::minimum_ring_size
@@ -546,18 +556,20 @@ struct buffer_inserter_ring
{
// Walk backwards (rings will be reversed afterwards)
code = iterate(collection, boost::rbegin(view), boost::rend(view),
- strategy::buffer::buffer_side_right,
- distance, side_strategy, join_strategy, end_strategy, robust_policy);
+ geometry::strategy::buffer::buffer_side_right,
+ distance, side_strategy, join_strategy, end_strategy,
+ robust_policy, strategy);
}
else
{
code = iterate(collection, boost::begin(view), boost::end(view),
- strategy::buffer::buffer_side_left,
- distance, side_strategy, join_strategy, end_strategy, robust_policy);
+ geometry::strategy::buffer::buffer_side_left,
+ distance, side_strategy, join_strategy, end_strategy,
+ robust_policy, strategy);
}
}
- if (code == strategy::buffer::result_no_output && n >= 1)
+ if (code == geometry::strategy::buffer::result_no_output && n >= 1)
{
// Use point_strategy to buffer degenerated ring
detail::buffer::buffer_point<output_point_type>
@@ -586,23 +598,25 @@ struct buffer_inserter<ring_tag, RingInput, RingOutput>
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
- typename RobustPolicy
+ typename RobustPolicy,
+ typename Strategy
>
- static inline strategy::buffer::result_code apply(RingInput const& ring,
+ static inline geometry::strategy::buffer::result_code apply(RingInput const& ring,
Collection& collection,
DistanceStrategy const& distance,
SideStrategy const& side_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
PointStrategy const& point_strategy,
- RobustPolicy const& robust_policy)
+ RobustPolicy const& robust_policy,
+ Strategy const& strategy) // side strategy
{
collection.start_new_ring();
- strategy::buffer::result_code const code
+ geometry::strategy::buffer::result_code const code
= buffer_inserter_ring<RingInput, RingOutput>::apply(ring,
collection, distance,
side_strategy, join_strategy, end_strategy, point_strategy,
- robust_policy);
+ robust_policy, strategy);
collection.finish_ring(code);
return code;
}
@@ -627,16 +641,18 @@ struct buffer_inserter<linestring_tag, Linestring, Polygon>
typename SideStrategy,
typename JoinStrategy,
typename EndStrategy,
- typename RobustPolicy
+ typename RobustPolicy,
+ typename Strategy
>
- static inline strategy::buffer::result_code iterate(Collection& collection,
+ static inline geometry::strategy::buffer::result_code iterate(Collection& collection,
Iterator begin, Iterator end,
- strategy::buffer::buffer_side_selector side,
+ geometry::strategy::buffer::buffer_side_selector side,
DistanceStrategy const& distance_strategy,
SideStrategy const& side_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
RobustPolicy const& robust_policy,
+ Strategy const& strategy, // side strategy
output_point_type& first_p1)
{
input_point_type const& ultimate_point = *(end - 1);
@@ -647,18 +663,18 @@ struct buffer_inserter<linestring_tag, Linestring, Polygon>
// we have it already from the first phase (left).
// But for the first pass, we have to generate it
output_point_type reverse_p1;
- if (side == strategy::buffer::buffer_side_right)
+ if (side == geometry::strategy::buffer::buffer_side_right)
{
reverse_p1 = first_p1;
}
else
{
std::vector<output_point_type> generated_side;
- strategy::buffer::result_code code
+ geometry::strategy::buffer::result_code code
= side_strategy.apply(ultimate_point, penultimate_point,
- strategy::buffer::buffer_side_right,
+ geometry::strategy::buffer::buffer_side_right,
distance_strategy, generated_side);
- if (code != strategy::buffer::result_normal)
+ if (code != geometry::strategy::buffer::result_normal)
{
// No output or numerical error
return code;
@@ -668,16 +684,18 @@ struct buffer_inserter<linestring_tag, Linestring, Polygon>
output_point_type first_p2, last_p1, last_p2;
- strategy::buffer::result_code result
+ geometry::strategy::buffer::result_code result
= detail::buffer::buffer_range<output_ring_type>::iterate(collection,
begin, end, side,
- distance_strategy, side_strategy, join_strategy, end_strategy, robust_policy,
+ distance_strategy, side_strategy, join_strategy, end_strategy,
+ robust_policy, strategy,
first_p1, first_p2, last_p1, last_p2);
- if (result == strategy::buffer::result_normal)
+ if (result == geometry::strategy::buffer::result_normal)
{
std::vector<output_point_type> range_out;
- end_strategy.apply(penultimate_point, last_p2, ultimate_point, reverse_p1, side, distance_strategy, range_out);
+ end_strategy.apply(penultimate_point, last_p2, ultimate_point, reverse_p1,
+ side, distance_strategy, range_out);
collection.add_endcap(end_strategy, range_out, ultimate_point);
}
return result;
@@ -691,20 +709,23 @@ struct buffer_inserter<linestring_tag, Linestring, Polygon>
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
- typename RobustPolicy
+ typename RobustPolicy,
+ typename Strategy
>
- static inline strategy::buffer::result_code apply(Linestring const& linestring, Collection& collection,
+ static inline geometry::strategy::buffer::result_code apply(Linestring const& linestring,
+ Collection& collection,
DistanceStrategy const& distance,
SideStrategy const& side_strategy,
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
PointStrategy const& point_strategy,
- RobustPolicy const& robust_policy)
+ RobustPolicy const& robust_policy,
+ Strategy const& strategy) // side strategy
{
Linestring simplified;
detail::buffer::simplify_input(linestring, distance, simplified);
- strategy::buffer::result_code code = strategy::buffer::result_no_output;
+ geometry::strategy::buffer::result_code code = geometry::strategy::buffer::result_no_output;
std::size_t n = boost::size(simplified);
if (n > 1)
{
@@ -712,21 +733,23 @@ struct buffer_inserter<linestring_tag, Linestring, Polygon>
output_point_type first_p1;
code = iterate(collection,
boost::begin(simplified), boost::end(simplified),
- strategy::buffer::buffer_side_left,
- distance, side_strategy, join_strategy, end_strategy, robust_policy,
+ geometry::strategy::buffer::buffer_side_left,
+ distance, side_strategy, join_strategy, end_strategy,
+ robust_policy, strategy,
first_p1);
- if (code == strategy::buffer::result_normal)
+ if (code == geometry::strategy::buffer::result_normal)
{
code = iterate(collection,
boost::rbegin(simplified), boost::rend(simplified),
- strategy::buffer::buffer_side_right,
- distance, side_strategy, join_strategy, end_strategy, robust_policy,
+ geometry::strategy::buffer::buffer_side_right,
+ distance, side_strategy, join_strategy, end_strategy,
+ robust_policy, strategy,
first_p1);
}
collection.finish_ring(code);
}
- if (code == strategy::buffer::result_no_output && n >= 1)
+ if (code == geometry::strategy::buffer::result_no_output && n >= 1)
{
// Use point_strategy to buffer degenerated linestring
detail::buffer::buffer_point<output_point_type>
@@ -763,7 +786,8 @@ private:
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
- typename RobustPolicy
+ typename RobustPolicy,
+ typename Strategy
>
static inline
void iterate(Iterator begin, Iterator end,
@@ -774,15 +798,16 @@ private:
EndStrategy const& end_strategy,
PointStrategy const& point_strategy,
RobustPolicy const& robust_policy,
+ Strategy const& strategy, // side strategy
bool is_interior)
{
for (Iterator it = begin; it != end; ++it)
{
collection.start_new_ring();
- strategy::buffer::result_code const code
+ geometry::strategy::buffer::result_code const code
= policy::apply(*it, collection, distance, side_strategy,
join_strategy, end_strategy, point_strategy,
- robust_policy);
+ robust_policy, strategy);
collection.finish_ring(code, is_interior);
}
@@ -797,7 +822,8 @@ private:
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
- typename RobustPolicy
+ typename RobustPolicy,
+ typename Strategy
>
static inline
void apply_interior_rings(InteriorRings const& interior_rings,
@@ -807,12 +833,13 @@ private:
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
PointStrategy const& point_strategy,
- RobustPolicy const& robust_policy)
+ RobustPolicy const& robust_policy,
+ Strategy const& strategy) // side strategy
{
iterate(boost::begin(interior_rings), boost::end(interior_rings),
collection, distance, side_strategy,
join_strategy, end_strategy, point_strategy,
- robust_policy, true);
+ robust_policy, strategy, true);
}
public:
@@ -824,7 +851,8 @@ public:
typename JoinStrategy,
typename EndStrategy,
typename PointStrategy,
- typename RobustPolicy
+ typename RobustPolicy,
+ typename Strategy
>
static inline void apply(PolygonInput const& polygon,
Collection& collection,
@@ -833,16 +861,17 @@ public:
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
PointStrategy const& point_strategy,
- RobustPolicy const& robust_policy)
+ RobustPolicy const& robust_policy,
+ Strategy const& strategy) // side strategy
{
{
collection.start_new_ring();
- strategy::buffer::result_code const code
+ geometry::strategy::buffer::result_code const code
= policy::apply(exterior_ring(polygon), collection,
distance, side_strategy,
join_strategy, end_strategy, point_strategy,
- robust_policy);
+ robust_policy, strategy);
collection.finish_ring(code, false,
geometry::num_interior_rings(polygon) > 0u);
@@ -851,7 +880,7 @@ public:
apply_interior_rings(interior_rings(polygon),
collection, distance, side_strategy,
join_strategy, end_strategy, point_strategy,
- robust_policy);
+ robust_policy, strategy);
}
};
@@ -945,7 +974,7 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator
>::apply(geometry_input, collection,
distance_strategy, side_strategy, join_strategy,
end_strategy, point_strategy,
- robust_policy);
+ robust_policy, intersection_strategy.get_side_strategy());
collection.get_turns();
collection.classify_turns(linear);
diff --git a/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp b/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp
index 7fbbb790bb..c0d906fe62 100644
--- a/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp
+++ b/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp
@@ -142,10 +142,20 @@ struct buffered_piece_collection
robust_point_type
>::type robust_comparable_radius_type;
- typedef typename strategy::side::services::default_strategy
+ typedef typename IntersectionStrategy::side_strategy_type side_strategy_type;
+
+ typedef typename IntersectionStrategy::template area_strategy
+ <
+ point_type
+ >::type area_strategy_type;
+
+ typedef typename IntersectionStrategy::template area_strategy
<
- typename cs_tag<point_type>::type
- >::type side_strategy;
+ robust_point_type
+ >::type robust_area_strategy_type;
+
+ typedef typename area_strategy_type::return_type area_result_type;
+ typedef typename robust_area_strategy_type::return_type robust_area_result_type;
typedef typename geometry::rescale_policy_type
<
@@ -306,7 +316,10 @@ struct buffered_piece_collection
cluster_type m_clusters;
- IntersectionStrategy const& m_intersection_strategy;
+ IntersectionStrategy m_intersection_strategy;
+ side_strategy_type m_side_strategy;
+ area_strategy_type m_area_strategy;
+ robust_area_strategy_type m_robust_area_strategy;
RobustPolicy const& m_robust_policy;
struct redundant_turn
@@ -321,6 +334,9 @@ struct buffered_piece_collection
RobustPolicy const& robust_policy)
: m_first_piece_index(-1)
, m_intersection_strategy(intersection_strategy)
+ , m_side_strategy(intersection_strategy.get_side_strategy())
+ , m_area_strategy(intersection_strategy.template get_area_strategy<point_type>())
+ , m_robust_area_strategy(intersection_strategy.template get_area_strategy<robust_point_type>())
, m_robust_policy(robust_policy)
{}
@@ -478,7 +494,7 @@ struct buffered_piece_collection
for (typename occupation_map_type::iterator it = occupation_map.begin();
it != occupation_map.end(); ++it)
{
- it->second.get_left_turns(it->first, m_turns);
+ it->second.get_left_turns(it->first, m_turns, m_side_strategy);
}
}
@@ -699,7 +715,7 @@ struct buffered_piece_collection
++it)
{
piece& pc = *it;
- if (geometry::area(pc.robust_ring) < 0)
+ if (geometry::area(pc.robust_ring, m_robust_area_strategy) < 0)
{
// Rings can be ccw:
// - in a concave piece
@@ -1220,14 +1236,9 @@ struct buffered_piece_collection
inline void enrich()
{
- typedef typename strategy::side::services::default_strategy
- <
- typename cs_tag<Ring>::type
- >::type side_strategy_type;
-
enrich_intersection_points<false, false, overlay_buffer>(m_turns,
m_clusters, offsetted_rings, offsetted_rings,
- m_robust_policy, side_strategy_type());
+ m_robust_policy, m_side_strategy);
}
// Discards all rings which do have not-OK intersection points only.
@@ -1314,7 +1325,7 @@ struct buffered_piece_collection
buffered_ring<Ring>& ring = *it;
if (! ring.has_intersections()
&& boost::size(ring) > 0u
- && geometry::area(ring) < 0)
+ && geometry::area(ring, m_area_strategy) < 0)
{
if (! point_coveredby_original(geometry::range::front(ring)))
{
@@ -1391,7 +1402,7 @@ struct buffered_piece_collection
template <typename GeometryOutput, typename OutputIterator>
inline OutputIterator assign(OutputIterator out) const
{
- typedef detail::overlay::ring_properties<point_type> properties;
+ typedef detail::overlay::ring_properties<point_type, area_result_type> properties;
std::map<ring_identifier, properties> selected;
@@ -1407,7 +1418,7 @@ struct buffered_piece_collection
if (! it->has_intersections()
&& ! it->is_untouched_outside_original)
{
- properties p = properties(*it);
+ properties p = properties(*it, m_area_strategy);
if (p.valid)
{
ring_identifier id(0, index, -1);
@@ -1423,7 +1434,7 @@ struct buffered_piece_collection
it != boost::end(traversed_rings);
++it, ++index)
{
- properties p = properties(*it);
+ properties p = properties(*it, m_area_strategy);
if (p.valid)
{
ring_identifier id(2, index, -1);
@@ -1431,7 +1442,7 @@ struct buffered_piece_collection
}
}
- detail::overlay::assign_parents(offsetted_rings, traversed_rings, selected, true);
+ detail::overlay::assign_parents(offsetted_rings, traversed_rings, selected, m_intersection_strategy, true);
return detail::overlay::add_rings<GeometryOutput>(selected, offsetted_rings, traversed_rings, out);
}
diff --git a/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp b/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp
index 178c7bcafe..5c012e7151 100644
--- a/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp
+++ b/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp
@@ -1,6 +1,7 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2017.
// Modifications copyright (c) 2017 Oracle and/or its affiliates.
@@ -126,26 +127,31 @@ class piece_turn_visitor
template <std::size_t Dimension, typename Iterator, typename Box>
inline void move_begin_iterator(Iterator& it_begin, Iterator it_beyond,
- signed_size_type& index, int dir, Box const& other_bounding_box)
+ signed_size_type& index, int dir,
+ Box const& this_bounding_box,
+ Box const& other_bounding_box)
{
for(; it_begin != it_beyond
&& it_begin + 1 != it_beyond
&& detail::section::preceding<Dimension>(dir, *(it_begin + 1),
- other_bounding_box, m_robust_policy);
+ this_bounding_box,
+ other_bounding_box,
+ m_robust_policy);
++it_begin, index++)
{}
}
template <std::size_t Dimension, typename Iterator, typename Box>
inline void move_end_iterator(Iterator it_begin, Iterator& it_beyond,
- int dir, Box const& other_bounding_box)
+ int dir, Box const& this_bounding_box,
+ Box const& other_bounding_box)
{
while (it_beyond != it_begin
&& it_beyond - 1 != it_begin
&& it_beyond - 2 != it_begin)
{
if (detail::section::exceeding<Dimension>(dir, *(it_beyond - 2),
- other_bounding_box, m_robust_policy))
+ this_bounding_box, other_bounding_box, m_robust_policy))
{
--it_beyond;
}
@@ -191,23 +197,23 @@ class piece_turn_visitor
// Set begin/end of monotonic ranges, in both x/y directions
signed_size_type index1 = sec1_first_index;
move_begin_iterator<0>(it1_first, it1_beyond, index1,
- section1.directions[0], section2.bounding_box);
+ section1.directions[0], section1.bounding_box, section2.bounding_box);
move_end_iterator<0>(it1_first, it1_beyond,
- section1.directions[0], section2.bounding_box);
+ section1.directions[0], section1.bounding_box, section2.bounding_box);
move_begin_iterator<1>(it1_first, it1_beyond, index1,
- section1.directions[1], section2.bounding_box);
+ section1.directions[1], section1.bounding_box, section2.bounding_box);
move_end_iterator<1>(it1_first, it1_beyond,
- section1.directions[1], section2.bounding_box);
+ section1.directions[1], section1.bounding_box, section2.bounding_box);
signed_size_type index2 = sec2_first_index;
move_begin_iterator<0>(it2_first, it2_beyond, index2,
- section2.directions[0], section1.bounding_box);
+ section2.directions[0], section2.bounding_box, section1.bounding_box);
move_end_iterator<0>(it2_first, it2_beyond,
- section2.directions[0], section1.bounding_box);
+ section2.directions[0], section2.bounding_box, section1.bounding_box);
move_begin_iterator<1>(it2_first, it2_beyond, index2,
- section2.directions[1], section1.bounding_box);
+ section2.directions[1], section2.bounding_box, section1.bounding_box);
move_end_iterator<1>(it2_first, it2_beyond,
- section2.directions[1], section1.bounding_box);
+ section2.directions[1], section2.bounding_box, section1.bounding_box);
turn_type the_model;
the_model.operations[0].piece_index = piece1.index;
@@ -272,7 +278,7 @@ public:
{}
template <typename Section>
- inline void apply(Section const& section1, Section const& section2,
+ inline bool apply(Section const& section1, Section const& section2,
bool first = true)
{
boost::ignore_unused_variable_warning(first);
@@ -285,12 +291,14 @@ public:
|| is_adjacent(piece1, piece2)
|| is_on_same_convex_ring(piece1, piece2)
|| detail::disjoint::disjoint_box_box(section1.bounding_box,
- section2.bounding_box) )
+ section2.bounding_box) )
{
- return;
+ return true;
}
calculate_turns(piece1, piece2, section1, section2);
+
+ return true;
}
};
diff --git a/boost/geometry/algorithms/detail/buffer/turn_in_original_visitor.hpp b/boost/geometry/algorithms/detail/buffer/turn_in_original_visitor.hpp
index da1d084d32..e7cc97539f 100644
--- a/boost/geometry/algorithms/detail/buffer/turn_in_original_visitor.hpp
+++ b/boost/geometry/algorithms/detail/buffer/turn_in_original_visitor.hpp
@@ -212,27 +212,27 @@ public:
{}
template <typename Turn, typename Original>
- inline void apply(Turn const& turn, Original const& original, bool first = true)
+ inline bool apply(Turn const& turn, Original const& original, bool first = true)
{
boost::ignore_unused_variable_warning(first);
if (turn.location != location_ok || turn.within_original)
{
// Skip all points already processed
- return;
+ return true;
}
if (geometry::disjoint(turn.robust_point, original.m_box))
{
// Skip all disjoint
- return;
+ return true;
}
int const code = point_in_original(turn.robust_point, original);
if (code == -1)
{
- return;
+ return true;
}
Turn& mutable_turn = m_mutable_turns[turn.turn_index];
@@ -259,6 +259,8 @@ public:
mutable_turn.within_original = true;
mutable_turn.count_in_original = 1;
}
+
+ return true;
}
private :
diff --git a/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp b/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp
index d7146befb9..d23a3b3fd6 100644
--- a/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp
+++ b/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp
@@ -1,6 +1,7 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2016.
// Modifications copyright (c) 2016 Oracle and/or its affiliates.
@@ -686,32 +687,32 @@ public:
{}
template <typename Turn, typename Piece>
- inline void apply(Turn const& turn, Piece const& piece, bool first = true)
+ inline bool apply(Turn const& turn, Piece const& piece, bool first = true)
{
boost::ignore_unused_variable_warning(first);
if (turn.count_within > 0)
{
// Already inside - no need to check again
- return;
+ return true;
}
if (piece.type == strategy::buffer::buffered_flat_end
|| piece.type == strategy::buffer::buffered_concave)
{
// Turns cannot be located within flat-end or concave pieces
- return;
+ return true;
}
if (! geometry::covered_by(turn.robust_point, piece.robust_envelope))
{
// Easy check: if the turn is not in the envelope, we can safely return
- return;
+ return true;
}
if (skip(turn.operations[0], piece) || skip(turn.operations[1], piece))
{
- return;
+ return true;
}
// TODO: mutable_piece to make some on-demand preparations in analyse
@@ -733,11 +734,11 @@ public:
if (cd < piece.robust_min_comparable_radius)
{
mutable_turn.count_within++;
- return;
+ return true;
}
if (cd > piece.robust_max_comparable_radius)
{
- return;
+ return true;
}
}
@@ -749,20 +750,20 @@ public:
switch(analyse_code)
{
case analyse_disjoint :
- return;
+ return true;
case analyse_on_offsetted :
mutable_turn.count_on_offsetted++; // value is not used anymore
- return;
+ return true;
case analyse_on_original_boundary :
mutable_turn.count_on_original_boundary++;
- return;
+ return true;
case analyse_within :
mutable_turn.count_within++;
- return;
+ return true;
#if ! defined(BOOST_GEOMETRY_BUFFER_USE_SIDE_OF_INTERSECTION)
case analyse_near_offsetted :
mutable_turn.count_within_near_offsetted++;
- return;
+ return true;
#endif
default :
break;
@@ -790,6 +791,8 @@ public:
{
mutable_turn.count_within++;
}
+
+ return true;
}
};
diff --git a/boost/geometry/algorithms/detail/covered_by/implementation.hpp b/boost/geometry/algorithms/detail/covered_by/implementation.hpp
new file mode 100644
index 0000000000..3df8b7783d
--- /dev/null
+++ b/boost/geometry/algorithms/detail/covered_by/implementation.hpp
@@ -0,0 +1,280 @@
+// 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.
+
+// This file was modified by Oracle on 2013, 2014, 2017.
+// Modifications copyright (c) 2013-2017 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+// 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_COVERED_BY_IMPLEMENTATION_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_COVERED_BY_IMPLEMENTATION_HPP
+
+
+#include <cstddef>
+
+#include <boost/geometry/algorithms/detail/covered_by/interface.hpp>
+#include <boost/geometry/algorithms/detail/within/implementation.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace covered_by {
+
+struct use_point_in_geometry
+{
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
+ {
+ return detail::within::point_in_geometry(geometry1, geometry2, strategy) >= 0;
+ }
+};
+
+struct use_relate
+{
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
+ {
+ typedef typename detail::de9im::static_mask_covered_by_type
+ <
+ Geometry1, Geometry2
+ >::type covered_by_mask;
+ return geometry::relate(geometry1, geometry2, covered_by_mask(), strategy);
+ }
+};
+
+}} // namespace detail::covered_by
+#endif // DOXYGEN_NO_DETAIL
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+template <typename Point, typename Box>
+struct covered_by<Point, Box, point_tag, box_tag>
+{
+ template <typename Strategy>
+ static inline bool apply(Point const& point, Box const& box, Strategy const& strategy)
+ {
+ ::boost::ignore_unused_variable_warning(strategy);
+ return strategy.apply(point, box);
+ }
+};
+
+template <typename Box1, typename Box2>
+struct covered_by<Box1, Box2, box_tag, box_tag>
+{
+ template <typename Strategy>
+ static inline bool apply(Box1 const& box1, Box2 const& box2, Strategy const& strategy)
+ {
+ assert_dimension_equal<Box1, Box2>();
+ ::boost::ignore_unused_variable_warning(strategy);
+ return strategy.apply(box1, box2);
+ }
+};
+
+
+// P/P
+
+template <typename Point1, typename Point2>
+struct covered_by<Point1, Point2, point_tag, point_tag>
+ : public detail::covered_by::use_point_in_geometry
+{};
+
+template <typename Point, typename MultiPoint>
+struct covered_by<Point, MultiPoint, point_tag, multi_point_tag>
+ : public detail::covered_by::use_point_in_geometry
+{};
+
+template <typename MultiPoint, typename Point>
+struct covered_by<MultiPoint, Point, multi_point_tag, point_tag>
+ : public detail::within::multi_point_point
+{};
+
+template <typename MultiPoint1, typename MultiPoint2>
+struct covered_by<MultiPoint1, MultiPoint2, multi_point_tag, multi_point_tag>
+ : public detail::within::multi_point_multi_point
+{};
+
+// P/L
+
+template <typename Point, typename Segment>
+struct covered_by<Point, Segment, point_tag, segment_tag>
+ : public detail::covered_by::use_point_in_geometry
+{};
+
+template <typename Point, typename Linestring>
+struct covered_by<Point, Linestring, point_tag, linestring_tag>
+ : public detail::covered_by::use_point_in_geometry
+{};
+
+template <typename Point, typename MultiLinestring>
+struct covered_by<Point, MultiLinestring, point_tag, multi_linestring_tag>
+ : public detail::covered_by::use_point_in_geometry
+{};
+
+template <typename MultiPoint, typename Segment>
+struct covered_by<MultiPoint, Segment, multi_point_tag, segment_tag>
+ : public detail::within::multi_point_single_geometry<false>
+{};
+
+template <typename MultiPoint, typename Linestring>
+struct covered_by<MultiPoint, Linestring, multi_point_tag, linestring_tag>
+ : public detail::within::multi_point_single_geometry<false>
+{};
+
+template <typename MultiPoint, typename MultiLinestring>
+struct covered_by<MultiPoint, MultiLinestring, multi_point_tag, multi_linestring_tag>
+ : public detail::within::multi_point_multi_geometry<false>
+{};
+
+// P/A
+
+template <typename Point, typename Ring>
+struct covered_by<Point, Ring, point_tag, ring_tag>
+ : public detail::covered_by::use_point_in_geometry
+{};
+
+template <typename Point, typename Polygon>
+struct covered_by<Point, Polygon, point_tag, polygon_tag>
+ : public detail::covered_by::use_point_in_geometry
+{};
+
+template <typename Point, typename MultiPolygon>
+struct covered_by<Point, MultiPolygon, point_tag, multi_polygon_tag>
+ : public detail::covered_by::use_point_in_geometry
+{};
+
+template <typename MultiPoint, typename Ring>
+struct covered_by<MultiPoint, Ring, multi_point_tag, ring_tag>
+ : public detail::within::multi_point_single_geometry<false>
+{};
+
+template <typename MultiPoint, typename Polygon>
+struct covered_by<MultiPoint, Polygon, multi_point_tag, polygon_tag>
+ : public detail::within::multi_point_single_geometry<false>
+{};
+
+template <typename MultiPoint, typename MultiPolygon>
+struct covered_by<MultiPoint, MultiPolygon, multi_point_tag, multi_polygon_tag>
+ : public detail::within::multi_point_multi_geometry<false>
+{};
+
+// L/L
+
+template <typename Linestring1, typename Linestring2>
+struct covered_by<Linestring1, Linestring2, linestring_tag, linestring_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename Linestring, typename MultiLinestring>
+struct covered_by<Linestring, MultiLinestring, linestring_tag, multi_linestring_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename MultiLinestring, typename Linestring>
+struct covered_by<MultiLinestring, Linestring, multi_linestring_tag, linestring_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename MultiLinestring1, typename MultiLinestring2>
+struct covered_by<MultiLinestring1, MultiLinestring2, multi_linestring_tag, multi_linestring_tag>
+ : public detail::covered_by::use_relate
+{};
+
+// L/A
+
+template <typename Linestring, typename Ring>
+struct covered_by<Linestring, Ring, linestring_tag, ring_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename MultiLinestring, typename Ring>
+struct covered_by<MultiLinestring, Ring, multi_linestring_tag, ring_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename Linestring, typename Polygon>
+struct covered_by<Linestring, Polygon, linestring_tag, polygon_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename MultiLinestring, typename Polygon>
+struct covered_by<MultiLinestring, Polygon, multi_linestring_tag, polygon_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename Linestring, typename MultiPolygon>
+struct covered_by<Linestring, MultiPolygon, linestring_tag, multi_polygon_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename MultiLinestring, typename MultiPolygon>
+struct covered_by<MultiLinestring, MultiPolygon, multi_linestring_tag, multi_polygon_tag>
+ : public detail::covered_by::use_relate
+{};
+
+// A/A
+
+template <typename Ring1, typename Ring2>
+struct covered_by<Ring1, Ring2, ring_tag, ring_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename Ring, typename Polygon>
+struct covered_by<Ring, Polygon, ring_tag, polygon_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename Polygon, typename Ring>
+struct covered_by<Polygon, Ring, polygon_tag, ring_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename Polygon1, typename Polygon2>
+struct covered_by<Polygon1, Polygon2, polygon_tag, polygon_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename Ring, typename MultiPolygon>
+struct covered_by<Ring, MultiPolygon, ring_tag, multi_polygon_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename MultiPolygon, typename Ring>
+struct covered_by<MultiPolygon, Ring, multi_polygon_tag, ring_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename Polygon, typename MultiPolygon>
+struct covered_by<Polygon, MultiPolygon, polygon_tag, multi_polygon_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename MultiPolygon, typename Polygon>
+struct covered_by<MultiPolygon, Polygon, multi_polygon_tag, polygon_tag>
+ : public detail::covered_by::use_relate
+{};
+
+template <typename MultiPolygon1, typename MultiPolygon2>
+struct covered_by<MultiPolygon1, MultiPolygon2, multi_polygon_tag, multi_polygon_tag>
+ : public detail::covered_by::use_relate
+{};
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_COVERED_BY_IMPLEMENTATION_HPP
diff --git a/boost/geometry/algorithms/detail/covered_by/interface.hpp b/boost/geometry/algorithms/detail/covered_by/interface.hpp
new file mode 100644
index 0000000000..6599078210
--- /dev/null
+++ b/boost/geometry/algorithms/detail/covered_by/interface.hpp
@@ -0,0 +1,261 @@
+// 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.
+
+// This file was modified by Oracle on 2013, 2014, 2017.
+// Modifications copyright (c) 2013-2017 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+// 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_COVERED_BY_INTERFACE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_COVERED_BY_INTERFACE_HPP
+
+
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
+
+#include <boost/geometry/algorithms/detail/within/interface.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
+
+#include <boost/geometry/strategies/cartesian/point_in_box.hpp>
+#include <boost/geometry/strategies/cartesian/box_in_box.hpp>
+#include <boost/geometry/strategies/default_strategy.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+template
+<
+ typename Geometry1,
+ typename Geometry2,
+ typename Tag1 = typename tag<Geometry1>::type,
+ typename Tag2 = typename tag<Geometry2>::type
+>
+struct covered_by
+ : not_implemented<Tag1, Tag2>
+{};
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+namespace resolve_strategy {
+
+struct covered_by
+{
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ concepts::within::check
+ <
+ typename tag<Geometry1>::type,
+ typename tag<Geometry2>::type,
+ typename tag_cast<typename tag<Geometry2>::type, areal_tag>::type,
+ Strategy
+ >();
+ concepts::check<Geometry1 const>();
+ concepts::check<Geometry2 const>();
+ assert_dimension_equal<Geometry1, Geometry2>();
+
+ return dispatch::covered_by<Geometry1, Geometry2>::apply(geometry1,
+ geometry2,
+ strategy);
+ }
+
+ template <typename Geometry1, typename Geometry2>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ default_strategy)
+ {
+ typedef typename strategy::covered_by::services::default_strategy
+ <
+ Geometry1,
+ Geometry2
+ >::type strategy_type;
+
+ return covered_by::apply(geometry1, geometry2, strategy_type());
+ }
+};
+
+} // namespace resolve_strategy
+
+
+namespace resolve_variant {
+
+template <typename Geometry1, typename Geometry2>
+struct covered_by
+{
+ template <typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ return resolve_strategy::covered_by
+ ::apply(geometry1, geometry2, strategy);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
+struct covered_by<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
+{
+ template <typename Strategy>
+ struct visitor: boost::static_visitor<bool>
+ {
+ Geometry2 const& m_geometry2;
+ Strategy const& m_strategy;
+
+ visitor(Geometry2 const& geometry2, Strategy const& strategy)
+ : m_geometry2(geometry2), m_strategy(strategy) {}
+
+ template <typename Geometry1>
+ bool operator()(Geometry1 const& geometry1) const
+ {
+ return covered_by<Geometry1, Geometry2>
+ ::apply(geometry1, m_geometry2, m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline bool
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ return boost::apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1);
+ }
+};
+
+template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct covered_by<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ template <typename Strategy>
+ struct visitor: boost::static_visitor<bool>
+ {
+ Geometry1 const& m_geometry1;
+ Strategy const& m_strategy;
+
+ visitor(Geometry1 const& geometry1, Strategy const& strategy)
+ : m_geometry1(geometry1), m_strategy(strategy) {}
+
+ template <typename Geometry2>
+ bool operator()(Geometry2 const& geometry2) const
+ {
+ return covered_by<Geometry1, Geometry2>
+ ::apply(m_geometry1, geometry2, m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline bool
+ apply(Geometry1 const& geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2,
+ Strategy const& strategy)
+ {
+ return boost::apply_visitor(visitor<Strategy>(geometry1, strategy), geometry2);
+ }
+};
+
+template <
+ BOOST_VARIANT_ENUM_PARAMS(typename T1),
+ BOOST_VARIANT_ENUM_PARAMS(typename T2)
+>
+struct covered_by<
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>
+>
+{
+ template <typename Strategy>
+ struct visitor: boost::static_visitor<bool>
+ {
+ Strategy const& m_strategy;
+
+ visitor(Strategy const& strategy): m_strategy(strategy) {}
+
+ template <typename Geometry1, typename Geometry2>
+ bool operator()(Geometry1 const& geometry1,
+ Geometry2 const& geometry2) const
+ {
+ return covered_by<Geometry1, Geometry2>
+ ::apply(geometry1, geometry2, m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline bool
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2,
+ Strategy const& strategy)
+ {
+ return boost::apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2);
+ }
+};
+
+} // namespace resolve_variant
+
+
+/*!
+\brief \brief_check12{is inside or on border}
+\ingroup covered_by
+\details \details_check12{covered_by, is inside or on border}.
+\tparam Geometry1 \tparam_geometry
+\tparam Geometry2 \tparam_geometry
+\param geometry1 \param_geometry which might be inside or on the border of the second geometry
+\param geometry2 \param_geometry which might cover the first geometry
+\return true if geometry1 is inside of or on the border of geometry2,
+ else false
+\note The default strategy is used for covered_by detection
+
+\qbk{[include reference/algorithms/covered_by.qbk]}
+
+ */
+template<typename Geometry1, typename Geometry2>
+inline bool covered_by(Geometry1 const& geometry1, Geometry2 const& geometry2)
+{
+ return resolve_variant::covered_by<Geometry1, Geometry2>
+ ::apply(geometry1, geometry2, default_strategy());
+}
+
+/*!
+\brief \brief_check12{is inside or on border} \brief_strategy
+\ingroup covered_by
+\details \details_check12{covered_by, is inside or on border}, \brief_strategy. \details_strategy_reasons
+\tparam Geometry1 \tparam_geometry
+\tparam Geometry2 \tparam_geometry
+\param geometry1 \param_geometry which might be inside or on the border of the second geometry
+\param geometry2 \param_geometry which might cover the first geometry
+\param strategy strategy to be used
+\return true if geometry1 is inside of or on the border of geometry2,
+ else false
+
+\qbk{distinguish,with strategy}
+\qbk{[include reference/algorithms/covered_by.qbk]}
+
+*/
+template<typename Geometry1, typename Geometry2, typename Strategy>
+inline bool covered_by(Geometry1 const& geometry1, Geometry2 const& geometry2,
+ Strategy const& strategy)
+{
+ return resolve_variant::covered_by<Geometry1, Geometry2>
+ ::apply(geometry1, geometry2, strategy);
+}
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_COVERED_BY_INTERFACE_HPP
diff --git a/boost/geometry/algorithms/detail/direction_code.hpp b/boost/geometry/algorithms/detail/direction_code.hpp
index 26d53ab4e5..c5c5221109 100644
--- a/boost/geometry/algorithms/detail/direction_code.hpp
+++ b/boost/geometry/algorithms/detail/direction_code.hpp
@@ -2,10 +2,11 @@
// Copyright (c) 2015 Barend Gehrels, Amsterdam, the Netherlands.
-// This file was modified by Oracle on 2015.
-// Modifications copyright (c) 2015 Oracle and/or its affiliates.
+// This file was modified by Oracle on 2015, 2017.
+// Modifications copyright (c) 2015-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -17,14 +18,22 @@
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/util/math.hpp>
+#include <boost/geometry/util/select_coordinate_type.hpp>
+#include <boost/geometry/util/normalize_spheroidal_coordinates.hpp>
+
+#include <boost/mpl/assert.hpp>
+
namespace boost { namespace geometry
{
+
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
+
+// TODO: remove
template <std::size_t Index, typename Point1, typename Point2>
inline int sign_of_difference(Point1 const& point1, Point2 const& point2)
{
@@ -37,35 +46,204 @@ inline int sign_of_difference(Point1 const& point1, Point2 const& point2)
}
-// Gives sense of direction for point p, collinear w.r.t. segment (a,b)
-// Returns -1 if p goes backward w.r.t (a,b), so goes from b in direction of a
-// Returns 1 if p goes forward, so extends (a,b)
-// Returns 0 if p is equal with b, or if (a,b) is degenerate
-// Note that it does not do any collinearity test, that should be done before
-template <typename Point1, typename Point2>
-inline int direction_code(Point1 const& segment_a, Point1 const& segment_b,
- const Point2& p)
+template <typename Point, typename CSTag = typename cs_tag<Point>::type>
+struct direction_code_impl
+{
+ BOOST_MPL_ASSERT_MSG((false), NOT_IMPLEMENTED_FOR_THIS_CS, (CSTag));
+};
+
+template <typename Point>
+struct direction_code_impl<Point, cartesian_tag>
{
- // Suppose segment = (4 3,4 4) and p =(4 2)
- // Then sign_a1 = 1 and sign_p1 = 1 -> goes backward -> return -1
+ template <typename Point1, typename Point2>
+ static inline int apply(Point1 const& segment_a, Point1 const& segment_b,
+ Point2 const& p)
+ {
+ typedef typename geometry::select_coordinate_type
+ <
+ Point1, Point2
+ >::type calc_t;
+
+ if ( (math::equals(geometry::get<0>(segment_b), geometry::get<0>(segment_a))
+ && math::equals(geometry::get<1>(segment_b), geometry::get<1>(segment_a)))
+ || (math::equals(geometry::get<0>(segment_b), geometry::get<0>(p))
+ && math::equals(geometry::get<1>(segment_b), geometry::get<1>(p))) )
+ {
+ return 0;
+ }
+
+ calc_t x1 = geometry::get<0>(segment_b) - geometry::get<0>(segment_a);
+ calc_t y1 = geometry::get<1>(segment_b) - geometry::get<1>(segment_a);
+ calc_t x2 = geometry::get<0>(segment_b) - geometry::get<0>(p);
+ calc_t y2 = geometry::get<1>(segment_b) - geometry::get<1>(p);
+
+ calc_t ax = (std::min)(math::abs(x1), math::abs(x2));
+ calc_t ay = (std::min)(math::abs(y1), math::abs(y2));
+
+ int s1 = 0, s2 = 0;
+ if (ax >= ay)
+ {
+ s1 = x1 > 0 ? 1 : -1;
+ s2 = x2 > 0 ? 1 : -1;
+ }
+ else
+ {
+ s1 = y1 > 0 ? 1 : -1;
+ s2 = y2 > 0 ? 1 : -1;
+ }
- int const sign_a0 = sign_of_difference<0>(segment_b, segment_a);
- int const sign_a1 = sign_of_difference<1>(segment_b, segment_a);
+ return s1 == s2 ? -1 : 1;
+ }
+};
- if (sign_a0 == 0 && sign_a1 == 0)
+template <typename Point>
+struct direction_code_impl<Point, spherical_equatorial_tag>
+{
+ template <typename Point1, typename Point2>
+ static inline int apply(Point1 const& segment_a, Point1 const& segment_b,
+ Point2 const& p)
{
- return 0;
+ typedef typename coordinate_type<Point1>::type coord1_t;
+ typedef typename coordinate_type<Point2>::type coord2_t;
+ typedef typename coordinate_system<Point1>::type::units units_t;
+ typedef typename coordinate_system<Point2>::type::units units2_t;
+ BOOST_MPL_ASSERT_MSG((boost::is_same<units_t, units2_t>::value),
+ NOT_IMPLEMENTED_FOR_DIFFERENT_UNITS,
+ (units_t, units2_t));
+
+ typedef typename geometry::select_coordinate_type <Point1, Point2>::type calc_t;
+ typedef math::detail::constants_on_spheroid<coord1_t, units_t> constants1;
+ typedef math::detail::constants_on_spheroid<coord2_t, units_t> constants2;
+ typedef math::detail::constants_on_spheroid<calc_t, units_t> constants;
+
+ coord1_t const a0 = geometry::get<0>(segment_a);
+ coord1_t const a1 = geometry::get<1>(segment_a);
+ coord1_t const b0 = geometry::get<0>(segment_b);
+ coord1_t const b1 = geometry::get<1>(segment_b);
+ coord2_t const p0 = geometry::get<0>(p);
+ coord2_t const p1 = geometry::get<1>(p);
+ coord1_t const pi_half1 = constants1::max_latitude();
+ coord2_t const pi_half2 = constants2::max_latitude();
+ calc_t const pi = constants::half_period();
+ calc_t const pi_half = constants::max_latitude();
+ calc_t const c0 = 0;
+
+ if ( (math::equals(b0, a0) && math::equals(b1, a1))
+ || (math::equals(b0, p0) && math::equals(b1, p1)) )
+ {
+ return 0;
+ }
+
+ bool const is_a_pole = math::equals(pi_half1, math::abs(a1));
+ bool const is_b_pole = math::equals(pi_half1, math::abs(b1));
+ bool const is_p_pole = math::equals(pi_half2, math::abs(p1));
+
+ if ( is_b_pole && ((is_a_pole && math::sign(b1) == math::sign(a1))
+ || (is_p_pole && math::sign(b1) == math::sign(p1))) )
+ {
+ return 0;
+ }
+
+ // NOTE: as opposed to the implementation for cartesian CS
+ // here point b is the origin
+
+ calc_t const dlon1 = math::longitude_distance_signed<units_t>(b0, a0);
+ calc_t const dlon2 = math::longitude_distance_signed<units_t>(b0, p0);
+
+ bool is_antilon1 = false, is_antilon2 = false;
+ calc_t const dlat1 = latitude_distance_signed(b1, a1, dlon1, pi, is_antilon1);
+ calc_t const dlat2 = latitude_distance_signed(b1, p1, dlon2, pi, is_antilon2);
+
+ calc_t mx = is_a_pole || is_b_pole || is_p_pole ?
+ c0 :
+ (std::min)(is_antilon1 ? c0 : math::abs(dlon1),
+ is_antilon2 ? c0 : math::abs(dlon2));
+ calc_t my = (std::min)(math::abs(dlat1),
+ math::abs(dlat2));
+
+ int s1 = 0, s2 = 0;
+ if (mx >= my)
+ {
+ s1 = dlon1 > 0 ? 1 : -1;
+ s2 = dlon2 > 0 ? 1 : -1;
+ }
+ else
+ {
+ s1 = dlat1 > 0 ? 1 : -1;
+ s2 = dlat2 > 0 ? 1 : -1;
+ }
+
+ return s1 == s2 ? -1 : 1;
}
- int const sign_p0 = sign_of_difference<0>(segment_b, p);
- int const sign_p1 = sign_of_difference<1>(segment_b, p);
+ template <typename T>
+ static inline T latitude_distance_signed(T const& lat1, T const& lat2, T const& lon_ds, T const& pi, bool & is_antilon)
+ {
+ T const c0 = 0;
+
+ T res = lat2 - lat1;
+
+ is_antilon = math::equals(math::abs(lon_ds), pi);
+ if (is_antilon)
+ {
+ res = lat2 + lat1;
+ if (res >= c0)
+ res = pi - res;
+ else
+ res = -pi - res;
+ }
- if (sign_p0 == 0 && sign_p1 == 0)
+ return res;
+ }
+};
+
+template <typename Point>
+struct direction_code_impl<Point, spherical_polar_tag>
+{
+ template <typename Point1, typename Point2>
+ static inline int apply(Point1 segment_a, Point1 segment_b,
+ Point2 p)
{
- return 0;
+ typedef math::detail::constants_on_spheroid
+ <
+ typename coordinate_type<Point1>::type,
+ typename coordinate_system<Point1>::type::units
+ > constants1;
+ typedef math::detail::constants_on_spheroid
+ <
+ typename coordinate_type<Point2>::type,
+ typename coordinate_system<Point2>::type::units
+ > constants2;
+
+ geometry::set<1>(segment_a,
+ constants1::max_latitude() - geometry::get<1>(segment_a));
+ geometry::set<1>(segment_b,
+ constants1::max_latitude() - geometry::get<1>(segment_b));
+ geometry::set<1>(p,
+ constants2::max_latitude() - geometry::get<1>(p));
+
+ return direction_code_impl
+ <
+ Point, spherical_equatorial_tag
+ >::apply(segment_a, segment_b, p);
}
+};
+
+template <typename Point>
+struct direction_code_impl<Point, geographic_tag>
+ : direction_code_impl<Point, spherical_equatorial_tag>
+{};
- return sign_a0 == sign_p0 && sign_a1 == sign_p1 ? -1 : 1;
+// Gives sense of direction for point p, collinear w.r.t. segment (a,b)
+// Returns -1 if p goes backward w.r.t (a,b), so goes from b in direction of a
+// Returns 1 if p goes forward, so extends (a,b)
+// Returns 0 if p is equal with b, or if (a,b) is degenerate
+// Note that it does not do any collinearity test, that should be done before
+template <typename Point1, typename Point2>
+inline int direction_code(Point1 const& segment_a, Point1 const& segment_b,
+ Point2 const& p)
+{
+ return direction_code_impl<Point1>::apply(segment_a, segment_b, p);
}
@@ -73,7 +251,6 @@ inline int direction_code(Point1 const& segment_a, Point1 const& segment_b,
#endif //DOXYGEN_NO_DETAIL
-
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DIRECITON_CODE_HPP
diff --git a/boost/geometry/algorithms/detail/disjoint/box_box.hpp b/boost/geometry/algorithms/detail/disjoint/box_box.hpp
index f830f8161c..87618939b8 100644
--- a/boost/geometry/algorithms/detail/disjoint/box_box.hpp
+++ b/boost/geometry/algorithms/detail/disjoint/box_box.hpp
@@ -121,9 +121,18 @@ struct box_box<Box1, Box2, 0, DimensionCount, spherical_tag>
// calculate positive longitude translation with b1_min as origin
calc_t const diff_min = math::longitude_distance_unsigned<units_t>(b1_min, b2_min);
calc_t const b2_min_transl = b1_min + diff_min; // always right of b1_min
+ calc_t b2_max_transl = b2_min_transl - constants::period() + diff2;
- if (b2_min_transl > b1_max // b2_min right of b1_max
- && b2_min_transl - constants::period() + diff2 < b1_min) // b2_max left of b1_min
+ // if the translation is too close then use the original point
+ // note that math::abs(b2_max_transl - b2_max) takes values very
+ // close to k*2*constants::period() for k=0,1,2,...
+ if (math::abs(b2_max_transl - b2_max) < constants::period() / 2)
+ {
+ b2_max_transl = b2_max;
+ }
+
+ if (b2_min_transl > b1_max // b2_min right of b1_max
+ && b2_max_transl < b1_min) // b2_max left of b1_min
{
return true;
}
diff --git a/boost/geometry/algorithms/detail/disjoint/implementation.hpp b/boost/geometry/algorithms/detail/disjoint/implementation.hpp
index d482c4a5a9..3a3d9865d1 100644
--- a/boost/geometry/algorithms/detail/disjoint/implementation.hpp
+++ b/boost/geometry/algorithms/detail/disjoint/implementation.hpp
@@ -5,8 +5,8 @@
// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
-// This file was modified by Oracle on 2013-2014.
-// Modifications copyright (c) 2013-2014, Oracle and/or its affiliates.
+// This file was modified by Oracle on 2013-2017.
+// Modifications copyright (c) 2013-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
diff --git a/boost/geometry/algorithms/detail/disjoint/multipoint_geometry.hpp b/boost/geometry/algorithms/detail/disjoint/multipoint_geometry.hpp
index 7c1a93cdb7..f8d3e3c593 100644
--- a/boost/geometry/algorithms/detail/disjoint/multipoint_geometry.hpp
+++ b/boost/geometry/algorithms/detail/disjoint/multipoint_geometry.hpp
@@ -1,6 +1,7 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014-2017, Oracle and/or its affiliates.
+// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -30,7 +31,9 @@
#include <boost/geometry/algorithms/detail/check_iterator_range.hpp>
#include <boost/geometry/algorithms/detail/partition.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
#include <boost/geometry/algorithms/detail/disjoint/multirange_geometry.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/point_box.hpp>
#include <boost/geometry/algorithms/detail/disjoint/point_point.hpp>
#include <boost/geometry/algorithms/detail/disjoint/point_geometry.hpp>
#include <boost/geometry/algorithms/detail/relate/less.hpp>
@@ -117,15 +120,21 @@ private:
}
};
- // TODO: After adding non-cartesian Segment envelope to the library
- // this policy should be modified to take envelope strategy.
+ template <typename EnvelopeStrategy>
struct expand_box_segment
{
+ explicit expand_box_segment(EnvelopeStrategy const& strategy)
+ : m_strategy(strategy)
+ {}
+
template <typename Box, typename Segment>
- static inline void apply(Box& total, Segment const& segment)
+ inline void apply(Box& total, Segment const& segment) const
{
- geometry::expand(total, geometry::return_envelope<Box>(segment));
+ geometry::expand(total,
+ geometry::return_envelope<Box>(segment, m_strategy));
}
+
+ EnvelopeStrategy const& m_strategy;
};
struct overlaps_box_point
@@ -134,32 +143,24 @@ private:
static inline bool apply(Box const& box, Point const& point)
{
// The default strategy is enough in this case
- typedef typename strategy::disjoint::services::default_strategy
- <
- Point, Box
- >::type strategy_type;
- return ! dispatch::disjoint<Point, Box>::apply(point, box, strategy_type());
+ return ! detail::disjoint::disjoint_point_box(point, box);
}
};
- // TODO: After implementing disjoint Segment/Box for non-cartesian geometries
- // this strategy should be passed here.
- // TODO: This Segment/Box strategy should somehow be derived from Point/Segment strategy
- // which by default is winding containing CS-specific side strategy
- // TODO: disjoint Segment/Box will be called in this case which may take
- // quite long in non-cartesian CS. So we should consider passing range of bounding boxes
- // of segments after calculating them once.
+ template <typename DisjointStrategy>
struct overlaps_box_segment
{
+ explicit overlaps_box_segment(DisjointStrategy const& strategy)
+ : m_strategy(strategy)
+ {}
+
template <typename Box, typename Segment>
- static inline bool apply(Box const& box, Segment const& segment)
+ inline bool apply(Box const& box, Segment const& segment) const
{
- typedef typename strategy::disjoint::services::default_strategy
- <
- Segment, Box
- >::type strategy_type;
- return ! dispatch::disjoint<Segment, Box>::apply(segment, box, strategy_type());
+ return ! dispatch::disjoint<Segment, Box>::apply(segment, box, m_strategy);
}
+
+ DisjointStrategy const& m_strategy;
};
template <typename PtSegStrategy>
@@ -172,13 +173,15 @@ private:
{}
template <typename Item1, typename Item2>
- inline void apply(Item1 const& item1, Item2 const& item2)
+ inline bool apply(Item1 const& item1, Item2 const& item2)
{
if (! m_intersection_found
&& ! dispatch::disjoint<Item1, Item2>::apply(item1, item2, m_strategy))
{
m_intersection_found = true;
+ return false;
}
+ return true;
}
inline bool intersection_found() const { return m_intersection_found; }
@@ -219,12 +222,22 @@ public:
{
item_visitor_type<Strategy> visitor(strategy);
+ typedef typename Strategy::envelope_strategy_type envelope_strategy_type;
+ typedef typename Strategy::disjoint_strategy_type disjoint_strategy_type;
+
+ // TODO: disjoint Segment/Box may be called in partition multiple times
+ // possibly for non-cartesian segments which could be slow. We should consider
+ // passing a range of bounding boxes of segments after calculating them once.
+ // Alternatively instead of a range of segments a range of Segment/Envelope pairs
+ // should be passed, where envelope would be lazily calculated when needed the first time
geometry::partition
<
geometry::model::box<typename point_type<MultiPoint>::type>
>::apply(multipoint, segment_range(linear), visitor,
- expand_box_point(), overlaps_box_point(),
- expand_box_segment(), overlaps_box_segment());
+ expand_box_point(),
+ overlaps_box_point(),
+ expand_box_segment<envelope_strategy_type>(strategy.get_envelope_strategy()),
+ overlaps_box_segment<disjoint_strategy_type>(strategy.get_disjoint_strategy()));
return ! visitor.intersection_found();
}
@@ -237,6 +250,176 @@ public:
};
+template <typename MultiPoint, typename SingleGeometry>
+class multi_point_single_geometry
+{
+public:
+ template <typename Strategy>
+ static inline bool apply(MultiPoint const& multi_point, SingleGeometry const& single_geometry, Strategy const& strategy)
+ {
+ typedef typename point_type<MultiPoint>::type point1_type;
+ typedef typename point_type<SingleGeometry>::type point2_type;
+ typedef model::box<point2_type> box2_type;
+
+ box2_type box2;
+ geometry::envelope(single_geometry, box2, strategy.get_envelope_strategy());
+ geometry::detail::expand_by_epsilon(box2);
+
+ typedef typename boost::range_const_iterator<MultiPoint>::type iterator;
+ for ( iterator it = boost::begin(multi_point) ; it != boost::end(multi_point) ; ++it )
+ {
+ // The default strategy is enough for Point/Box
+ if (! detail::disjoint::disjoint_point_box(*it, box2)
+ && ! dispatch::disjoint<point1_type, SingleGeometry>::apply(*it, single_geometry, strategy))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ template <typename Strategy>
+ static inline bool apply(SingleGeometry const& single_geometry, MultiPoint const& multi_point, Strategy const& strategy)
+ {
+ return apply(multi_point, single_geometry, strategy);
+ }
+};
+
+
+template <typename MultiPoint, typename MultiGeometry>
+class multi_point_multi_geometry
+{
+private:
+ struct expand_box_point
+ {
+ template <typename Box, typename Point>
+ static inline void apply(Box& total, Point const& point)
+ {
+ geometry::expand(total, point);
+ }
+ };
+
+ struct expand_box_box_pair
+ {
+ template <typename Box, typename BoxPair>
+ inline void apply(Box& total, BoxPair const& box_pair) const
+ {
+ geometry::expand(total, box_pair.first);
+ }
+ };
+
+ struct overlaps_box_point
+ {
+ template <typename Box, typename Point>
+ static inline bool apply(Box const& box, Point const& point)
+ {
+ // The default strategy is enough for Point/Box
+ return ! detail::disjoint::disjoint_point_box(point, box);
+ }
+ };
+
+ struct overlaps_box_box_pair
+ {
+ template <typename Box, typename BoxPair>
+ inline bool apply(Box const& box, BoxPair const& box_pair) const
+ {
+ // The default strategy is enough for Box/Box
+ return ! detail::disjoint::disjoint_box_box(box_pair.first, box);
+ }
+ };
+
+ template <typename PtSegStrategy>
+ class item_visitor_type
+ {
+ public:
+ item_visitor_type(MultiGeometry const& multi_geometry,
+ PtSegStrategy const& strategy)
+ : m_intersection_found(false)
+ , m_multi_geometry(multi_geometry)
+ , m_strategy(strategy)
+ {}
+
+ template <typename Point, typename BoxPair>
+ inline bool apply(Point const& point, BoxPair const& box_pair)
+ {
+ typedef typename boost::range_value<MultiGeometry>::type single_type;
+
+ // The default strategy is enough for Point/Box
+ if (! m_intersection_found
+ && ! detail::disjoint::disjoint_point_box(point, box_pair.first)
+ && ! dispatch::disjoint<Point, single_type>::apply(point, range::at(m_multi_geometry, box_pair.second), m_strategy))
+ {
+ m_intersection_found = true;
+ return false;
+ }
+ return true;
+ }
+
+ inline bool intersection_found() const { return m_intersection_found; }
+
+ private:
+ bool m_intersection_found;
+ MultiGeometry const& m_multi_geometry;
+ PtSegStrategy const& m_strategy;
+ };
+ // structs for partition -- end
+
+public:
+ template <typename Strategy>
+ static inline bool apply(MultiPoint const& multi_point, MultiGeometry const& multi_geometry, Strategy const& strategy)
+ {
+ typedef typename point_type<MultiPoint>::type point1_type;
+ typedef typename point_type<MultiGeometry>::type point2_type;
+ typedef model::box<point1_type> box1_type;
+ typedef model::box<point2_type> box2_type;
+ typedef std::pair<box2_type, std::size_t> box_pair_type;
+
+ typename Strategy::envelope_strategy_type const
+ envelope_strategy = strategy.get_envelope_strategy();
+
+ std::size_t count2 = boost::size(multi_geometry);
+ std::vector<box_pair_type> boxes(count2);
+ for (std::size_t i = 0 ; i < count2 ; ++i)
+ {
+ geometry::envelope(range::at(multi_geometry, i), boxes[i].first, envelope_strategy);
+ geometry::detail::expand_by_epsilon(boxes[i].first);
+ boxes[i].second = i;
+ }
+
+ item_visitor_type<Strategy> visitor(multi_geometry, strategy);
+
+ geometry::partition
+ <
+ box1_type
+ >::apply(multi_point, boxes, visitor,
+ expand_box_point(),
+ overlaps_box_point(),
+ expand_box_box_pair(),
+ overlaps_box_box_pair());
+
+ return ! visitor.intersection_found();
+ }
+
+ template <typename Strategy>
+ static inline bool apply(MultiGeometry const& multi_geometry, MultiPoint const& multi_point, Strategy const& strategy)
+ {
+ return apply(multi_point, multi_geometry, strategy);
+ }
+};
+
+
+template <typename MultiPoint, typename Areal, typename Tag = typename tag<Areal>::type>
+struct multipoint_areal
+ : multi_point_single_geometry<MultiPoint, Areal>
+{};
+
+template <typename MultiPoint, typename Areal>
+struct multipoint_areal<MultiPoint, Areal, multi_polygon_tag>
+ : multi_point_multi_geometry<MultiPoint, Areal>
+{};
+
+
}} // namespace detail::disjoint
#endif // DOXYGEN_NO_DETAIL
@@ -321,6 +504,22 @@ struct disjoint
{};
+template <typename Areal, typename MultiPoint, std::size_t DimensionCount>
+struct disjoint
+ <
+ Areal, MultiPoint, DimensionCount, areal_tag, multi_point_tag, false
+ > : detail::disjoint::multipoint_areal<MultiPoint, Areal>
+{};
+
+
+template <typename MultiPoint, typename Areal, std::size_t DimensionCount>
+struct disjoint
+ <
+ MultiPoint, Areal, DimensionCount, multi_point_tag, areal_tag, false
+ > : detail::disjoint::multipoint_areal<MultiPoint, Areal>
+{};
+
+
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
diff --git a/boost/geometry/algorithms/detail/disjoint/segment_box.hpp b/boost/geometry/algorithms/detail/disjoint/segment_box.hpp
index c2741ce72c..fe849e1091 100644
--- a/boost/geometry/algorithms/detail/disjoint/segment_box.hpp
+++ b/boost/geometry/algorithms/detail/disjoint/segment_box.hpp
@@ -8,8 +8,9 @@
// This file was modified by Oracle on 2013-2017.
// Modifications copyright (c) 2013-2017, Oracle and/or its affiliates.
-// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -24,9 +25,18 @@
#include <cstddef>
#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/core/radian_access.hpp>
+#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/point_box.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
+#include <boost/geometry/algorithms/detail/envelope/segment.hpp>
+#include <boost/geometry/algorithms/detail/normalize.hpp>
#include <boost/geometry/algorithms/dispatch/disjoint.hpp>
+#include <boost/geometry/formulas/vertex_longitude.hpp>
+
+#include <boost/geometry/geometries/box.hpp>
namespace boost { namespace geometry
{
@@ -36,10 +46,161 @@ namespace boost { namespace geometry
namespace detail { namespace disjoint
{
+template <typename CS_Tag>
+struct disjoint_segment_box_sphere_or_spheroid
+{
+private:
+
+ template <typename CT>
+ static inline void swap(CT& lon1,
+ CT& lat1,
+ CT& lon2,
+ CT& lat2)
+ {
+ std::swap(lon1, lon2);
+ std::swap(lat1, lat2);
+ }
+
+
+public:
+
+ template <typename Segment, typename Box, typename Strategy>
+ static inline bool apply(Segment const& segment,
+ Box const& box,
+ Strategy const& azimuth_strategy)
+ {
+ assert_dimension_equal<Segment, Box>();
+
+ typedef typename point_type<Segment>::type segment_point_type;
+ typedef typename cs_tag<Segment>::type segment_cs_type;
+
+ segment_point_type p0, p1;
+ geometry::detail::assign_point_from_index<0>(segment, p0);
+ geometry::detail::assign_point_from_index<1>(segment, p1);
+
+ // Simplest cases first
+
+ // Case 1: if box contains one of segment's endpoints then they are not disjoint
+ if (! disjoint_point_box(p0, box) || ! disjoint_point_box(p1, box))
+ {
+ return false;
+ }
+
+ // Case 2: disjoint if bounding boxes are disjoint
+
+ typedef typename coordinate_type<segment_point_type>::type CT;
+
+ segment_point_type p0_normalized =
+ geometry::detail::return_normalized<segment_point_type>(p0);
+ segment_point_type p1_normalized =
+ geometry::detail::return_normalized<segment_point_type>(p1);
+
+ CT lon1 = geometry::get_as_radian<0>(p0_normalized);
+ CT lat1 = geometry::get_as_radian<1>(p0_normalized);
+ CT lon2 = geometry::get_as_radian<0>(p1_normalized);
+ CT lat2 = geometry::get_as_radian<1>(p1_normalized);
+
+ if (lon1 > lon2)
+ {
+ swap(lon1, lat1, lon2, lat2);
+ }
+
+ //Compute alp1 outside envelope and pass it to envelope_segment_impl
+ //in order for it to be used later in the algorithm
+ CT alp1;
+
+ azimuth_strategy.apply(lon1, lat1, lon2, lat2, alp1);
+
+ geometry::model::box<segment_point_type> box_seg;
+
+ geometry::detail::envelope::envelope_segment_impl<segment_cs_type>
+ ::template apply<geometry::radian>(lon1, lat1,
+ lon2, lat2,
+ box_seg,
+ azimuth_strategy,
+ alp1);
+ if (disjoint_box_box(box, box_seg))
+ {
+ return true;
+ }
+
+ // Case 3: test intersection by comparing angles
+
+ CT a_b0, a_b1, a_b2, a_b3;
+
+ CT b_lon_min = geometry::get_as_radian<geometry::min_corner, 0>(box);
+ CT b_lat_min = geometry::get_as_radian<geometry::min_corner, 1>(box);
+ CT b_lon_max = geometry::get_as_radian<geometry::max_corner, 0>(box);
+ CT b_lat_max = geometry::get_as_radian<geometry::max_corner, 1>(box);
+
+ azimuth_strategy.apply(lon1, lat1, b_lon_min, b_lat_min, a_b0);
+ azimuth_strategy.apply(lon1, lat1, b_lon_max, b_lat_min, a_b1);
+ azimuth_strategy.apply(lon1, lat1, b_lon_min, b_lat_max, a_b2);
+ azimuth_strategy.apply(lon1, lat1, b_lon_max, b_lat_max, a_b3);
+
+ bool b0 = alp1 > a_b0;
+ bool b1 = alp1 > a_b1;
+ bool b2 = alp1 > a_b2;
+ bool b3 = alp1 > a_b3;
+
+ // if not all box points on the same side of the segment then
+ // there is an intersection
+ if (!(b0 && b1 && b2 && b3) && (b0 || b1 || b2 || b3))
+ {
+ return false;
+ }
+
+ // Case 4: The only intersection case not covered above is when all four
+ // points of the box are above (below) the segment in northern (southern)
+ // hemisphere. Then we have to compute the vertex of the segment
+
+ CT vertex_lat;
+ CT lat_sum = lat1 + lat2;
+
+ if ((b0 && b1 && b2 && b3 && lat_sum > CT(0))
+ || (!(b0 && b1 && b2 && b3) && lat_sum < CT(0)))
+ {
+ CT b_lat_below; //latitude of box closest to equator
+
+ if (lat_sum > CT(0))
+ {
+ vertex_lat = geometry::get_as_radian<geometry::max_corner, 1>(box_seg);
+ b_lat_below = b_lat_min;
+ } else {
+ vertex_lat = geometry::get_as_radian<geometry::min_corner, 1>(box_seg);
+ b_lat_below = b_lat_max;
+ }
+
+ //optimization TODO: computing the spherical longitude should suffice for
+ // the majority of cases
+ CT vertex_lon = geometry::formula::vertex_longitude<CT, CS_Tag>
+ ::apply(lon1, lat1,
+ lon2, lat2,
+ vertex_lat,
+ alp1,
+ azimuth_strategy);
+
+ // Check if the vertex point is within the band defined by the
+ // minimum and maximum longitude of the box; if yes, then return
+ // false if the point is above the min latitude of the box; return
+ // true in all other cases
+ if (vertex_lon >= b_lon_min && vertex_lon <= b_lon_max
+ && std::abs(vertex_lat) > std::abs(b_lat_below))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+};
+
struct disjoint_segment_box
{
template <typename Segment, typename Box, typename Strategy>
- static inline bool apply(Segment const& segment, Box const& box, Strategy const& strategy)
+ static inline bool apply(Segment const& segment,
+ Box const& box,
+ Strategy const& strategy)
{
return strategy.apply(segment, box);
}
@@ -56,7 +217,7 @@ namespace dispatch
template <typename Segment, typename Box, std::size_t DimensionCount>
struct disjoint<Segment, Box, DimensionCount, segment_tag, box_tag, false>
- : detail::disjoint::disjoint_segment_box
+ : detail::disjoint::disjoint_segment_box
{};
diff --git a/boost/geometry/algorithms/detail/envelope/segment.hpp b/boost/geometry/algorithms/detail/envelope/segment.hpp
index 7631e84883..7e37194968 100644
--- a/boost/geometry/algorithms/detail/envelope/segment.hpp
+++ b/boost/geometry/algorithms/detail/envelope/segment.hpp
@@ -130,19 +130,16 @@ private:
CalculationType& lat1,
CalculationType& lon2,
CalculationType& lat2,
+ CalculationType a1,
+ CalculationType a2,
Strategy const& strategy)
{
// coordinates are assumed to be in radians
BOOST_GEOMETRY_ASSERT(lon1 <= lon2);
- CalculationType lon1_rad = math::as_radian<Units>(lon1);
CalculationType lat1_rad = math::as_radian<Units>(lat1);
- CalculationType lon2_rad = math::as_radian<Units>(lon2);
CalculationType lat2_rad = math::as_radian<Units>(lat2);
- CalculationType a1, a2;
- strategy.apply(lon1_rad, lat1_rad, lon2_rad, lat2_rad, a1, a2);
-
if (lat1 > lat2)
{
std::swap(lat1, lat2);
@@ -189,12 +186,11 @@ private:
}
}
- template <typename Units, typename CalculationType, typename Strategy>
- static inline void apply(CalculationType& lon1,
- CalculationType& lat1,
- CalculationType& lon2,
- CalculationType& lat2,
- Strategy const& strategy)
+ template <typename Units, typename CalculationType>
+ static inline void special_cases(CalculationType& lon1,
+ CalculationType& lat1,
+ CalculationType& lon2,
+ CalculationType& lat2)
{
typedef math::detail::constants_on_spheroid
<
@@ -249,23 +245,19 @@ private:
lon1 += constants::period();
swap(lon1, lat1, lon2, lat2);
}
-
- compute_box_corners<Units>(lon1, lat1, lon2, lat2, strategy);
}
-public:
- template <
- typename Units,
- typename CalculationType,
- typename Box,
- typename Strategy
- >
- static inline void apply(CalculationType lon1,
- CalculationType lat1,
- CalculationType lon2,
- CalculationType lat2,
- Box& mbr,
- Strategy const& strategy)
+ template
+ <
+ typename Units,
+ typename CalculationType,
+ typename Box
+ >
+ static inline void create_box(CalculationType lon1,
+ CalculationType lat1,
+ CalculationType lon2,
+ CalculationType lat2,
+ Box& mbr)
{
typedef typename coordinate_type<Box>::type box_coordinate_type;
@@ -276,8 +268,6 @@ public:
helper_box_type radian_mbr;
- apply<Units>(lon1, lat1, lon2, lat2, strategy);
-
geometry::set
<
min_corner, 0
@@ -300,6 +290,85 @@ public:
transform_units(radian_mbr, mbr);
}
+
+
+ template <typename Units, typename CalculationType, typename Strategy>
+ static inline void apply(CalculationType& lon1,
+ CalculationType& lat1,
+ CalculationType& lon2,
+ CalculationType& lat2,
+ Strategy const& strategy)
+ {
+ special_cases<Units>(lon1, lat1, lon2, lat2);
+
+ CalculationType lon1_rad = math::as_radian<Units>(lon1);
+ CalculationType lat1_rad = math::as_radian<Units>(lat1);
+ CalculationType lon2_rad = math::as_radian<Units>(lon2);
+ CalculationType lat2_rad = math::as_radian<Units>(lat2);
+ CalculationType alp1, alp2;
+ strategy.apply(lon1_rad, lat1_rad, lon2_rad, lat2_rad, alp1, alp2);
+
+ compute_box_corners<Units>(lon1, lat1, lon2, lat2, alp1, alp2, strategy);
+ }
+
+ template <typename Units, typename CalculationType, typename Strategy>
+ static inline void apply(CalculationType& lon1,
+ CalculationType& lat1,
+ CalculationType& lon2,
+ CalculationType& lat2,
+ Strategy const& strategy,
+ CalculationType alp1)
+ {
+ special_cases<Units>(lon1, lat1, lon2, lat2);
+
+ CalculationType lon1_rad = math::as_radian<Units>(lon1);
+ CalculationType lat1_rad = math::as_radian<Units>(lat1);
+ CalculationType lon2_rad = math::as_radian<Units>(lon2);
+ CalculationType lat2_rad = math::as_radian<Units>(lat2);
+ CalculationType alp2;
+ strategy.apply(lon2_rad, lat2_rad, lon1_rad, lat1_rad, alp2);
+ alp2 += math::pi<CalculationType>();
+
+ compute_box_corners<Units>(lon1, lat1, lon2, lat2, alp1, alp2, strategy);
+ }
+
+public:
+ template
+ <
+ typename Units,
+ typename CalculationType,
+ typename Box,
+ typename Strategy
+ >
+ static inline void apply(CalculationType lon1,
+ CalculationType lat1,
+ CalculationType lon2,
+ CalculationType lat2,
+ Box& mbr,
+ Strategy const& strategy)
+ {
+ apply<Units>(lon1, lat1, lon2, lat2, strategy);
+ create_box<Units>(lon1, lat1, lon2, lat2, mbr);
+ }
+
+ template
+ <
+ typename Units,
+ typename CalculationType,
+ typename Box,
+ typename Strategy
+ >
+ static inline void apply(CalculationType lon1,
+ CalculationType lat1,
+ CalculationType lon2,
+ CalculationType lat2,
+ Box& mbr,
+ Strategy const& strategy,
+ CalculationType alp1)
+ {
+ apply<Units>(lon1, lat1, lon2, lat2, strategy, alp1);
+ create_box<Units>(lon1, lat1, lon2, lat2, mbr);
+ }
};
template <std::size_t Dimension, std::size_t DimensionCount>
diff --git a/boost/geometry/algorithms/detail/equals/implementation.hpp b/boost/geometry/algorithms/detail/equals/implementation.hpp
new file mode 100644
index 0000000000..310059a427
--- /dev/null
+++ b/boost/geometry/algorithms/detail/equals/implementation.hpp
@@ -0,0 +1,397 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
+// Copyright (c) 2014-2015 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2014, 2015, 2016, 2017.
+// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// 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_IMPLEMENTATION_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_IMPLEMENTATION_HPP
+
+
+#include <cstddef>
+#include <vector>
+
+#include <boost/range.hpp>
+#include <boost/type_traits/is_base_of.hpp>
+
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
+
+// For trivial checks
+#include <boost/geometry/algorithms/area.hpp>
+#include <boost/geometry/algorithms/length.hpp>
+#include <boost/geometry/util/math.hpp>
+#include <boost/geometry/util/select_coordinate_type.hpp>
+#include <boost/geometry/util/select_most_precise.hpp>
+
+#include <boost/geometry/algorithms/detail/equals/collect_vectors.hpp>
+#include <boost/geometry/algorithms/detail/equals/interface.hpp>
+#include <boost/geometry/algorithms/detail/relate/relate_impl.hpp>
+#include <boost/geometry/algorithms/relate.hpp>
+
+#include <boost/geometry/views/detail/indexed_point_view.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace equals
+{
+
+
+template
+<
+ std::size_t Dimension,
+ std::size_t DimensionCount
+>
+struct point_point
+{
+ template <typename Point1, typename Point2, typename Strategy>
+ static inline bool apply(Point1 const& point1, Point2 const& point2, Strategy const& strategy)
+ {
+ return ! detail::disjoint::point_point
+ <
+ Point1, Point2,
+ Dimension, DimensionCount
+ >::apply(point1, point2, strategy);
+ }
+};
+
+
+template
+<
+ std::size_t Dimension,
+ std::size_t DimensionCount
+>
+struct box_box
+{
+ template <typename Box1, typename Box2, typename Strategy>
+ static inline bool apply(Box1 const& box1, Box2 const& box2, Strategy const& strategy)
+ {
+ if (!geometry::math::equals(get<min_corner, Dimension>(box1), get<min_corner, Dimension>(box2))
+ || !geometry::math::equals(get<max_corner, Dimension>(box1), get<max_corner, Dimension>(box2)))
+ {
+ return false;
+ }
+ return box_box<Dimension + 1, DimensionCount>::apply(box1, box2, strategy);
+ }
+};
+
+template <std::size_t DimensionCount>
+struct box_box<DimensionCount, DimensionCount>
+{
+ template <typename Box1, typename Box2, typename Strategy>
+ static inline bool apply(Box1 const& , Box2 const& , Strategy const& )
+ {
+ return true;
+ }
+};
+
+
+struct segment_segment
+{
+ template <typename Segment1, typename Segment2, typename Strategy>
+ static inline bool apply(Segment1 const& segment1, Segment2 const& segment2, Strategy const& )
+ {
+ return equals::equals_point_point(
+ indexed_point_view<Segment1 const, 0>(segment1),
+ indexed_point_view<Segment2 const, 0>(segment2) )
+ ? equals::equals_point_point(
+ indexed_point_view<Segment1 const, 1>(segment1),
+ indexed_point_view<Segment2 const, 1>(segment2) )
+ : ( equals::equals_point_point(
+ indexed_point_view<Segment1 const, 0>(segment1),
+ indexed_point_view<Segment2 const, 1>(segment2) )
+ && equals::equals_point_point(
+ indexed_point_view<Segment1 const, 1>(segment1),
+ indexed_point_view<Segment2 const, 0>(segment2) )
+ );
+ }
+};
+
+
+struct area_check
+{
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ return geometry::math::equals(
+ geometry::area(geometry1,
+ strategy.template get_area_strategy<Geometry1>()),
+ geometry::area(geometry2,
+ strategy.template get_area_strategy<Geometry2>()));
+ }
+};
+
+
+struct length_check
+{
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ return geometry::math::equals(
+ geometry::length(geometry1,
+ strategy.template get_distance_strategy<Geometry1>()),
+ geometry::length(geometry2,
+ strategy.template get_distance_strategy<Geometry2>()));
+ }
+};
+
+
+template <typename Geometry1, typename Geometry2, typename IntersectionStrategy>
+struct collected_vector
+{
+ typedef typename geometry::select_most_precise
+ <
+ typename select_coordinate_type
+ <
+ Geometry1, Geometry2
+ >::type,
+ double
+ >::type calculation_type;
+
+ typedef geometry::collected_vector
+ <
+ calculation_type,
+ Geometry1,
+ typename IntersectionStrategy::side_strategy_type
+ > type;
+};
+
+template <typename TrivialCheck>
+struct equals_by_collection
+{
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ if (! TrivialCheck::apply(geometry1, geometry2, strategy))
+ {
+ return false;
+ }
+
+ typedef typename collected_vector
+ <
+ Geometry1, Geometry2, Strategy
+ >::type collected_vector_type;
+
+ std::vector<collected_vector_type> c1, c2;
+
+ geometry::collect_vectors(c1, geometry1);
+ geometry::collect_vectors(c2, geometry2);
+
+ if (boost::size(c1) != boost::size(c2))
+ {
+ return false;
+ }
+
+ std::sort(c1.begin(), c1.end());
+ std::sort(c2.begin(), c2.end());
+
+ // Just check if these vectors are equal.
+ return std::equal(c1.begin(), c1.end(), c2.begin());
+ }
+};
+
+template<typename Geometry1, typename Geometry2>
+struct equals_by_relate
+ : detail::relate::relate_impl
+ <
+ detail::de9im::static_mask_equals_type,
+ Geometry1,
+ Geometry2
+ >
+{};
+
+// If collect_vectors which is a SideStrategy-dispatched optimization
+// is implemented in a way consistent with the Intersection/Side Strategy
+// then collect_vectors is used, otherwise relate is used.
+// NOTE: the result could be conceptually different for invalid
+// geometries in different coordinate systems because collect_vectors
+// and relate treat invalid geometries differently.
+template<typename TrivialCheck>
+struct equals_by_collection_or_relate
+{
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ typedef typename boost::is_base_of
+ <
+ nyi::not_implemented_tag,
+ typename collected_vector
+ <
+ Geometry1, Geometry2, Strategy
+ >::type
+ >::type enable_relate_type;
+
+ return apply(geometry1, geometry2, strategy, enable_relate_type());
+ }
+
+private:
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy,
+ boost::false_type /*enable_relate*/)
+ {
+ return equals_by_collection<TrivialCheck>::apply(geometry1, geometry2, strategy);
+ }
+
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy,
+ boost::true_type /*enable_relate*/)
+ {
+ return equals_by_relate<Geometry1, Geometry2>::apply(geometry1, geometry2, strategy);
+ }
+};
+
+
+}} // namespace detail::equals
+#endif // DOXYGEN_NO_DETAIL
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+template <typename P1, typename P2, std::size_t DimensionCount, bool Reverse>
+struct equals<P1, P2, point_tag, point_tag, DimensionCount, Reverse>
+ : detail::equals::point_point<0, DimensionCount>
+{};
+
+template <typename MultiPoint1, typename MultiPoint2, std::size_t DimensionCount, bool Reverse>
+struct equals<MultiPoint1, MultiPoint2, multi_point_tag, multi_point_tag, DimensionCount, Reverse>
+ : detail::equals::equals_by_relate<MultiPoint1, MultiPoint2>
+{};
+
+template <typename MultiPoint, typename Point, std::size_t DimensionCount, bool Reverse>
+struct equals<Point, MultiPoint, point_tag, multi_point_tag, DimensionCount, Reverse>
+ : detail::equals::equals_by_relate<Point, MultiPoint>
+{};
+
+template <typename Box1, typename Box2, std::size_t DimensionCount, bool Reverse>
+struct equals<Box1, Box2, box_tag, box_tag, DimensionCount, Reverse>
+ : detail::equals::box_box<0, DimensionCount>
+{};
+
+
+template <typename Ring1, typename Ring2, bool Reverse>
+struct equals<Ring1, Ring2, ring_tag, ring_tag, 2, Reverse>
+ : detail::equals::equals_by_collection_or_relate<detail::equals::area_check>
+{};
+
+
+template <typename Polygon1, typename Polygon2, bool Reverse>
+struct equals<Polygon1, Polygon2, polygon_tag, polygon_tag, 2, Reverse>
+ : detail::equals::equals_by_collection_or_relate<detail::equals::area_check>
+{};
+
+
+template <typename Polygon, typename Ring, bool Reverse>
+struct equals<Polygon, Ring, polygon_tag, ring_tag, 2, Reverse>
+ : detail::equals::equals_by_collection_or_relate<detail::equals::area_check>
+{};
+
+
+template <typename Ring, typename Box, bool Reverse>
+struct equals<Ring, Box, ring_tag, box_tag, 2, Reverse>
+ : detail::equals::equals_by_collection<detail::equals::area_check>
+{};
+
+
+template <typename Polygon, typename Box, bool Reverse>
+struct equals<Polygon, Box, polygon_tag, box_tag, 2, Reverse>
+ : detail::equals::equals_by_collection<detail::equals::area_check>
+{};
+
+template <typename Segment1, typename Segment2, std::size_t DimensionCount, bool Reverse>
+struct equals<Segment1, Segment2, segment_tag, segment_tag, DimensionCount, Reverse>
+ : detail::equals::segment_segment
+{};
+
+template <typename LineString1, typename LineString2, bool Reverse>
+struct equals<LineString1, LineString2, linestring_tag, linestring_tag, 2, Reverse>
+ : detail::equals::equals_by_relate<LineString1, LineString2>
+{};
+
+template <typename LineString, typename MultiLineString, bool Reverse>
+struct equals<LineString, MultiLineString, linestring_tag, multi_linestring_tag, 2, Reverse>
+ : detail::equals::equals_by_relate<LineString, MultiLineString>
+{};
+
+template <typename MultiLineString1, typename MultiLineString2, bool Reverse>
+struct equals<MultiLineString1, MultiLineString2, multi_linestring_tag, multi_linestring_tag, 2, Reverse>
+ : detail::equals::equals_by_relate<MultiLineString1, MultiLineString2>
+{};
+
+
+template <typename MultiPolygon1, typename MultiPolygon2, bool Reverse>
+struct equals
+ <
+ MultiPolygon1, MultiPolygon2,
+ multi_polygon_tag, multi_polygon_tag,
+ 2,
+ Reverse
+ >
+ : detail::equals::equals_by_collection_or_relate<detail::equals::area_check>
+{};
+
+
+template <typename Polygon, typename MultiPolygon, bool Reverse>
+struct equals
+ <
+ Polygon, MultiPolygon,
+ polygon_tag, multi_polygon_tag,
+ 2,
+ Reverse
+ >
+ : detail::equals::equals_by_collection_or_relate<detail::equals::area_check>
+{};
+
+template <typename MultiPolygon, typename Ring, bool Reverse>
+struct equals
+ <
+ MultiPolygon, Ring,
+ multi_polygon_tag, ring_tag,
+ 2,
+ Reverse
+ >
+ : detail::equals::equals_by_collection_or_relate<detail::equals::area_check>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_IMPLEMENTATION_HPP
+
diff --git a/boost/geometry/algorithms/detail/equals/interface.hpp b/boost/geometry/algorithms/detail/equals/interface.hpp
new file mode 100644
index 0000000000..eacf95e9fe
--- /dev/null
+++ b/boost/geometry/algorithms/detail/equals/interface.hpp
@@ -0,0 +1,317 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
+// Copyright (c) 2014-2015 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2014, 2015, 2016, 2017.
+// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+
+// 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_INTERFACE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_INTERFACE_HPP
+
+
+#include <cstddef>
+
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
+
+#include <boost/geometry/core/coordinate_dimension.hpp>
+#include <boost/geometry/core/reverse_dispatch.hpp>
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+
+#include <boost/geometry/algorithms/not_implemented.hpp>
+
+#include <boost/geometry/strategies/default_strategy.hpp>
+#include <boost/geometry/strategies/relate.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+template
+<
+ typename Geometry1,
+ typename Geometry2,
+ typename Tag1 = typename tag<Geometry1>::type,
+ typename Tag2 = typename tag<Geometry2>::type,
+ std::size_t DimensionCount = dimension<Geometry1>::type::value,
+ bool Reverse = reverse_dispatch<Geometry1, Geometry2>::type::value
+>
+struct equals: not_implemented<Tag1, Tag2>
+{};
+
+
+// If reversal is needed, perform it
+template
+<
+ typename Geometry1, typename Geometry2,
+ typename Tag1, typename Tag2,
+ std::size_t DimensionCount
+>
+struct equals<Geometry1, Geometry2, Tag1, Tag2, DimensionCount, true>
+ : equals<Geometry2, Geometry1, Tag2, Tag1, DimensionCount, false>
+{
+ template <typename Strategy>
+ static inline bool apply(Geometry1 const& g1, Geometry2 const& g2, Strategy const& strategy)
+ {
+ return equals
+ <
+ Geometry2, Geometry1,
+ Tag2, Tag1,
+ DimensionCount,
+ false
+ >::apply(g2, g1, strategy);
+ }
+};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+namespace resolve_strategy
+{
+
+struct equals
+{
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ return dispatch::equals
+ <
+ Geometry1, Geometry2
+ >::apply(geometry1, geometry2, strategy);
+ }
+
+ template <typename Geometry1, typename Geometry2>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ default_strategy)
+ {
+ typedef typename strategy::relate::services::default_strategy
+ <
+ Geometry1,
+ Geometry2
+ >::type strategy_type;
+
+ return dispatch::equals
+ <
+ Geometry1, Geometry2
+ >::apply(geometry1, geometry2, strategy_type());
+ }
+};
+
+} // namespace resolve_strategy
+
+
+namespace resolve_variant {
+
+template <typename Geometry1, typename Geometry2>
+struct equals
+{
+ template <typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ concepts::check_concepts_and_equal_dimensions
+ <
+ Geometry1 const,
+ Geometry2 const
+ >();
+
+ return resolve_strategy::equals
+ ::apply(geometry1, geometry2, strategy);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
+struct equals<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
+{
+ template <typename Strategy>
+ struct visitor: static_visitor<bool>
+ {
+ Geometry2 const& m_geometry2;
+ Strategy const& m_strategy;
+
+ visitor(Geometry2 const& geometry2, Strategy const& strategy)
+ : m_geometry2(geometry2)
+ , m_strategy(strategy)
+ {}
+
+ template <typename Geometry1>
+ inline bool operator()(Geometry1 const& geometry1) const
+ {
+ return equals<Geometry1, Geometry2>
+ ::apply(geometry1, m_geometry2, m_strategy);
+ }
+
+ };
+
+ template <typename Strategy>
+ static inline bool apply(
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy
+ )
+ {
+ return boost::apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1);
+ }
+};
+
+template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct equals<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ template <typename Strategy>
+ struct visitor: static_visitor<bool>
+ {
+ Geometry1 const& m_geometry1;
+ Strategy const& m_strategy;
+
+ visitor(Geometry1 const& geometry1, Strategy const& strategy)
+ : m_geometry1(geometry1)
+ , m_strategy(strategy)
+ {}
+
+ template <typename Geometry2>
+ inline bool operator()(Geometry2 const& geometry2) const
+ {
+ return equals<Geometry1, Geometry2>
+ ::apply(m_geometry1, geometry2, m_strategy);
+ }
+
+ };
+
+ template <typename Strategy>
+ static inline bool apply(
+ Geometry1 const& geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2,
+ Strategy const& strategy
+ )
+ {
+ return boost::apply_visitor(visitor<Strategy>(geometry1, strategy), geometry2);
+ }
+};
+
+template <
+ BOOST_VARIANT_ENUM_PARAMS(typename T1),
+ BOOST_VARIANT_ENUM_PARAMS(typename T2)
+>
+struct equals<
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>
+>
+{
+ template <typename Strategy>
+ struct visitor: static_visitor<bool>
+ {
+ Strategy const& m_strategy;
+
+ visitor(Strategy const& strategy)
+ : m_strategy(strategy)
+ {}
+
+ template <typename Geometry1, typename Geometry2>
+ inline bool operator()(Geometry1 const& geometry1,
+ Geometry2 const& geometry2) const
+ {
+ return equals<Geometry1, Geometry2>
+ ::apply(geometry1, geometry2, m_strategy);
+ }
+
+ };
+
+ template <typename Strategy>
+ static inline bool apply(
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2,
+ Strategy const& strategy
+ )
+ {
+ return boost::apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2);
+ }
+};
+
+} // namespace resolve_variant
+
+
+/*!
+\brief \brief_check{are spatially equal}
+\details \details_check12{equals, is spatially equal}. Spatially equal means
+ that the same point set is included. A box can therefore be spatially equal
+ to a ring or a polygon, or a linestring can be spatially equal to a
+ multi-linestring or a segment. This only works theoretically, not all
+ combinations are implemented yet.
+\ingroup equals
+\tparam Geometry1 \tparam_geometry
+\tparam Geometry2 \tparam_geometry
+\tparam Strategy \tparam_strategy{Equals}
+\param geometry1 \param_geometry
+\param geometry2 \param_geometry
+\param strategy \param_strategy{equals}
+\return \return_check2{are spatially equal}
+
+\qbk{distinguish,with strategy}
+\qbk{[include reference/algorithms/equals.qbk]}
+ */
+template <typename Geometry1, typename Geometry2, typename Strategy>
+inline bool equals(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+{
+ return resolve_variant::equals
+ <
+ Geometry1, Geometry2
+ >::apply(geometry1, geometry2, strategy);
+}
+
+
+/*!
+\brief \brief_check{are spatially equal}
+\details \details_check12{equals, is spatially equal}. Spatially equal means
+ that the same point set is included. A box can therefore be spatially equal
+ to a ring or a polygon, or a linestring can be spatially equal to a
+ multi-linestring or a segment. This only works theoretically, not all
+ combinations are implemented yet.
+\ingroup equals
+\tparam Geometry1 \tparam_geometry
+\tparam Geometry2 \tparam_geometry
+\param geometry1 \param_geometry
+\param geometry2 \param_geometry
+\return \return_check2{are spatially equal}
+
+\qbk{[include reference/algorithms/equals.qbk]}
+ */
+template <typename Geometry1, typename Geometry2>
+inline bool equals(Geometry1 const& geometry1, Geometry2 const& geometry2)
+{
+ return resolve_variant::equals<Geometry1, Geometry2>
+ ::apply(geometry1, geometry2, default_strategy());
+}
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_EQUALS_INTERFACE_HPP
+
diff --git a/boost/geometry/algorithms/detail/extreme_points.hpp b/boost/geometry/algorithms/detail/extreme_points.hpp
index 65795cd05b..61e984ee3c 100644
--- a/boost/geometry/algorithms/detail/extreme_points.hpp
+++ b/boost/geometry/algorithms/detail/extreme_points.hpp
@@ -5,6 +5,11 @@
// Copyright (c) 2009-2013 Mateusz Loskot, London, UK.
// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
+// This file was modified by Oracle on 2017.
+// Modifications copyright (c) 2017 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
// 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)
@@ -117,12 +122,6 @@ struct extreme_points_on_ring
typedef typename boost::range_iterator<Ring const>::type range_iterator;
typedef typename geometry::point_type<Ring>::type point_type;
- typedef typename geometry::strategy::side::services::default_strategy
- <
- typename geometry::cs_tag<point_type>::type
- >::type side_strategy;
-
-
template <typename CirclingIterator, typename Points>
static inline bool extend(CirclingIterator& it,
std::size_t n,
@@ -214,10 +213,11 @@ struct extreme_points_on_ring
return true;
}
- template <typename Extremes, typename Intruders, typename CirclingIterator>
+ template <typename Extremes, typename Intruders, typename CirclingIterator, typename SideStrategy>
static inline void get_intruders(Ring const& ring, CirclingIterator left, CirclingIterator right,
Extremes const& extremes,
- Intruders& intruders)
+ Intruders& intruders,
+ SideStrategy const& strategy)
{
if (boost::size(extremes) < 3)
{
@@ -238,8 +238,8 @@ struct extreme_points_on_ring
if (coordinate > min_value && other_coordinate > other_min && other_coordinate < other_max)
{
int const factor = geometry::point_order<Ring>::value == geometry::clockwise ? 1 : -1;
- int const first_side = side_strategy::apply(*right, extremes.front(), *(extremes.begin() + 1)) * factor;
- int const last_side = side_strategy::apply(*right, *(extremes.rbegin() + 1), extremes.back()) * factor;
+ int const first_side = strategy.apply(*right, extremes.front(), *(extremes.begin() + 1)) * factor;
+ int const last_side = strategy.apply(*right, *(extremes.rbegin() + 1), extremes.back()) * factor;
// If not lying left from any of the extemes side
if (first_side != 1 && last_side != 1)
@@ -263,10 +263,11 @@ struct extreme_points_on_ring
}
}
- template <typename Extremes, typename Intruders>
+ template <typename Extremes, typename Intruders, typename SideStrategy>
static inline void get_intruders(Ring const& ring,
Extremes const& extremes,
- Intruders& intruders)
+ Intruders& intruders,
+ SideStrategy const& strategy)
{
std::size_t const n = boost::size(ring);
if (n >= 3)
@@ -275,12 +276,12 @@ struct extreme_points_on_ring
geometry::ever_circling_range_iterator<Ring const> right(ring);
++right;
- get_intruders(ring, left, right, extremes, intruders);
+ get_intruders(ring, left, right, extremes, intruders, strategy);
}
}
- template <typename Iterator>
- static inline bool right_turn(Ring const& ring, Iterator it)
+ template <typename Iterator, typename SideStrategy>
+ static inline bool right_turn(Ring const& ring, Iterator it, SideStrategy const& strategy)
{
typename std::iterator_traits<Iterator>::difference_type const index
= std::distance(boost::begin(ring), it);
@@ -295,8 +296,8 @@ struct extreme_points_on_ring
}
int const factor = geometry::point_order<Ring>::value == geometry::clockwise ? 1 : -1;
- int const first_side = side_strategy::apply(*(right - 1), *right, *left) * factor;
- int const last_side = side_strategy::apply(*left, *(left + 1), *right) * factor;
+ int const first_side = strategy.apply(*(right - 1), *right, *left) * factor;
+ int const last_side = strategy.apply(*left, *(left + 1), *right) * factor;
//std::cout << "Candidate at " << geometry::wkt(*it) << " first=" << first_side << " last=" << last_side << std::endl;
@@ -306,8 +307,11 @@ struct extreme_points_on_ring
// Gets the extreme segments (top point plus neighbouring points), plus intruders, if any, on the same ring
- template <typename Extremes, typename Intruders>
- static inline bool apply(Ring const& ring, Extremes& extremes, Intruders& intruders)
+ template <typename Extremes, typename Intruders, typename SideStrategy>
+ static inline bool apply(Ring const& ring,
+ Extremes& extremes,
+ Intruders& intruders,
+ SideStrategy const& strategy)
{
std::size_t const n = boost::size(ring);
if (n < 3)
@@ -321,7 +325,7 @@ struct extreme_points_on_ring
compare<Dimension> smaller;
for (range_iterator it = max_it + 1; it != boost::end(ring); ++it)
{
- if (smaller(*max_it, *it) && right_turn(ring, it))
+ if (smaller(*max_it, *it) && right_turn(ring, it, strategy))
{
max_it = it;
}
@@ -365,7 +369,7 @@ struct extreme_points_on_ring
std::copy(points.begin(), points.end(), std::back_inserter(extremes));
- get_intruders(ring, left, right, extremes, intruders);
+ get_intruders(ring, left, right, extremes, intruders, strategy);
return true;
}
@@ -403,8 +407,9 @@ struct extreme_points<Ring, Dimension, ring_tag>
template<typename Polygon, std::size_t Dimension>
struct extreme_points<Polygon, Dimension, polygon_tag>
{
- template <typename Extremes, typename Intruders>
- static inline bool apply(Polygon const& polygon, Extremes& extremes, Intruders& intruders)
+ template <typename Extremes, typename Intruders, typename SideStrategy>
+ static inline bool apply(Polygon const& polygon, Extremes& extremes, Intruders& intruders,
+ SideStrategy const& strategy)
{
typedef typename geometry::ring_type<Polygon>::type ring_type;
typedef detail::extreme_points::extreme_points_on_ring
@@ -412,7 +417,8 @@ struct extreme_points<Polygon, Dimension, polygon_tag>
ring_type, Dimension
> ring_implementation;
- if (! ring_implementation::apply(geometry::exterior_ring(polygon), extremes, intruders))
+ if (! ring_implementation::apply(geometry::exterior_ring(polygon),
+ extremes, intruders, strategy))
{
return false;
}
@@ -423,7 +429,7 @@ struct extreme_points<Polygon, Dimension, polygon_tag>
for (typename detail::interior_iterator<Polygon const>::type
it = boost::begin(rings); it != boost::end(rings); ++it)
{
- ring_implementation::get_intruders(*it, extremes, intruders);
+ ring_implementation::get_intruders(*it, extremes, intruders, strategy);
}
return true;
@@ -433,8 +439,9 @@ struct extreme_points<Polygon, Dimension, polygon_tag>
template<typename Box>
struct extreme_points<Box, 1, box_tag>
{
- template <typename Extremes, typename Intruders>
- static inline bool apply(Box const& box, Extremes& extremes, Intruders& )
+ template <typename Extremes, typename Intruders, typename SideStrategy>
+ static inline bool apply(Box const& box, Extremes& extremes, Intruders& ,
+ SideStrategy const& )
{
extremes.resize(4);
geometry::detail::assign_box_corners_oriented<false>(box, extremes);
@@ -446,8 +453,9 @@ struct extreme_points<Box, 1, box_tag>
template<typename Box>
struct extreme_points<Box, 0, box_tag>
{
- template <typename Extremes, typename Intruders>
- static inline bool apply(Box const& box, Extremes& extremes, Intruders& )
+ template <typename Extremes, typename Intruders, typename SideStrategy>
+ static inline bool apply(Box const& box, Extremes& extremes, Intruders& ,
+ SideStrategy const& )
{
extremes.resize(4);
geometry::detail::assign_box_corners_oriented<false>(box, extremes);
@@ -460,8 +468,9 @@ struct extreme_points<Box, 0, box_tag>
template<typename MultiPolygon, std::size_t Dimension>
struct extreme_points<MultiPolygon, Dimension, multi_polygon_tag>
{
- template <typename Extremes, typename Intruders>
- static inline bool apply(MultiPolygon const& multi, Extremes& extremes, Intruders& intruders)
+ template <typename Extremes, typename Intruders, typename SideStrategy>
+ static inline bool apply(MultiPolygon const& multi, Extremes& extremes,
+ Intruders& intruders, SideStrategy const& strategy)
{
// Get one for the very first polygon, that is (for the moment) enough.
// It is not guaranteed the "extreme" then, but for the current purpose
@@ -473,7 +482,7 @@ struct extreme_points<MultiPolygon, Dimension, multi_polygon_tag>
typename boost::range_value<MultiPolygon const>::type,
Dimension,
polygon_tag
- >::apply(*boost::begin(multi), extremes, intruders);
+ >::apply(*boost::begin(multi), extremes, intruders, strategy);
}
return false;
@@ -489,8 +498,18 @@ struct extreme_points<MultiPolygon, Dimension, multi_polygon_tag>
for Edge=0 in dimension 0, the right side)
\note We could specify a strategy (less/greater) to get bottom/left side too. However, until now we don't need that.
*/
-template <std::size_t Edge, typename Geometry, typename Extremes, typename Intruders>
-inline bool extreme_points(Geometry const& geometry, Extremes& extremes, Intruders& intruders)
+template
+<
+ std::size_t Edge,
+ typename Geometry,
+ typename Extremes,
+ typename Intruders,
+ typename SideStrategy
+>
+inline bool extreme_points(Geometry const& geometry,
+ Extremes& extremes,
+ Intruders& intruders,
+ SideStrategy const& strategy)
{
concepts::check<Geometry const>();
@@ -509,7 +528,11 @@ inline bool extreme_points(Geometry const& geometry, Extremes& extremes, Intrude
const
>();
- return dispatch::extreme_points<Geometry, Edge>::apply(geometry, extremes, intruders);
+ return dispatch::extreme_points
+ <
+ Geometry,
+ Edge
+ >::apply(geometry, extremes, intruders, strategy);
}
diff --git a/boost/geometry/algorithms/detail/get_left_turns.hpp b/boost/geometry/algorithms/detail/get_left_turns.hpp
index 95ab98c236..e9f6a50859 100644
--- a/boost/geometry/algorithms/detail/get_left_turns.hpp
+++ b/boost/geometry/algorithms/detail/get_left_turns.hpp
@@ -2,6 +2,11 @@
// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// This file was modified by Oracle on 2017.
+// Modifications copyright (c) 2017, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
// 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)
@@ -60,17 +65,14 @@ inline int squared_length(Vector const& vector)
}
-template <typename Point>
+template <typename Point, typename SideStrategy>
struct angle_less
{
typedef Point vector_type;
- typedef typename strategy::side::services::default_strategy
- <
- typename cs_tag<Point>::type
- >::type side_strategy_type;
- angle_less(Point const& origin)
+ angle_less(Point const& origin, SideStrategy const& strategy)
: m_origin(origin)
+ , m_strategy(strategy)
{}
template <typename Angle>
@@ -89,8 +91,7 @@ struct angle_less
return quadrant_p < quadrant_q;
}
// Same quadrant, check if p is located left of q
- int const side = side_strategy_type::apply(m_origin, q.point,
- p.point);
+ int const side = m_strategy.apply(m_origin, q.point, p.point);
if (side != 0)
{
return side == 1;
@@ -114,19 +115,17 @@ struct angle_less
private:
Point m_origin;
+ SideStrategy m_strategy;
};
-template <typename Point>
+template <typename Point, typename SideStrategy>
struct angle_equal_to
{
typedef Point vector_type;
- typedef typename strategy::side::services::default_strategy
- <
- typename cs_tag<Point>::type
- >::type side_strategy_type;
-
- inline angle_equal_to(Point const& origin)
+
+ inline angle_equal_to(Point const& origin, SideStrategy const& strategy)
: m_origin(origin)
+ , m_strategy(strategy)
{}
template <typename Angle>
@@ -143,13 +142,13 @@ struct angle_equal_to
return false;
}
// Same quadrant, check if p/q are collinear
- int const side = side_strategy_type::apply(m_origin, q.point,
- p.point);
+ int const side = m_strategy.apply(m_origin, q.point, p.point);
return side == 0;
}
private:
Point m_origin;
+ SideStrategy m_strategy;
};
template <typename AngleCollection, typename Turns>
@@ -193,13 +192,14 @@ inline void get_left_turns(AngleCollection const& sorted_angles,
//! Returns the number of clusters
-template <typename Point, typename AngleCollection>
-inline std::size_t assign_cluster_indices(AngleCollection& sorted, Point const& origin)
+template <typename Point, typename AngleCollection, typename SideStrategy>
+inline std::size_t assign_cluster_indices(AngleCollection& sorted, Point const& origin,
+ SideStrategy const& strategy)
{
// Assign same cluster_index for all turns in same direction
BOOST_GEOMETRY_ASSERT(boost::size(sorted) >= 4u);
- angle_equal_to<Point> comparator(origin);
+ angle_equal_to<Point, SideStrategy> comparator(origin, strategy);
typename boost::range_iterator<AngleCollection>::type it = sorted.begin();
std::size_t cluster_index = 0;
diff --git a/boost/geometry/algorithms/detail/has_self_intersections.hpp b/boost/geometry/algorithms/detail/has_self_intersections.hpp
index 9a388a4d80..c34bb217a6 100644
--- a/boost/geometry/algorithms/detail/has_self_intersections.hpp
+++ b/boost/geometry/algorithms/detail/has_self_intersections.hpp
@@ -81,7 +81,7 @@ inline bool has_self_intersections(Geometry const& geometry,
std::deque<turn_info> turns;
detail::disjoint::disjoint_interrupt_policy policy;
- geometry::self_turns<detail::overlay::assign_null_policy>(geometry, strategy, robust_policy, turns, policy);
+ detail::self_get_turn_points::self_turns<false, detail::overlay::assign_null_policy>(geometry, strategy, robust_policy, turns, policy);
#ifdef BOOST_GEOMETRY_DEBUG_HAS_SELF_INTERSECTIONS
bool first = true;
diff --git a/boost/geometry/algorithms/detail/intersects/implementation.hpp b/boost/geometry/algorithms/detail/intersects/implementation.hpp
new file mode 100644
index 0000000000..2379168e83
--- /dev/null
+++ b/boost/geometry/algorithms/detail/intersects/implementation.hpp
@@ -0,0 +1,88 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+
+// This file was modified by Oracle on 2013-2017.
+// Modifications copyright (c) 2013-2017, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+// 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_INTERSECTS_IMPLEMENTATION_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTS_IMPLEMENTATION_HPP
+
+
+#include <deque>
+
+#include <boost/geometry/algorithms/detail/intersects/interface.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/implementation.hpp>
+
+#include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp>
+#include <boost/geometry/policies/disjoint_interrupt_policy.hpp>
+#include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
+#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
+
+#include <boost/geometry/strategies/relate.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace intersects
+{
+
+template <typename Geometry>
+struct self_intersects
+{
+ static bool apply(Geometry const& geometry)
+ {
+ concepts::check<Geometry const>();
+
+ typedef typename geometry::point_type<Geometry>::type point_type;
+ typedef typename strategy::relate::services::default_strategy
+ <
+ Geometry, Geometry
+ >::type strategy_type;
+ typedef detail::no_rescale_policy rescale_policy_type;
+
+ typedef detail::overlay::turn_info
+ <
+ point_type,
+ typename segment_ratio_type<point_type, rescale_policy_type>::type
+ > turn_info;
+
+ std::deque<turn_info> turns;
+
+ typedef detail::overlay::get_turn_info
+ <
+ detail::overlay::assign_null_policy
+ > turn_policy;
+
+ strategy_type strategy;
+ rescale_policy_type robust_policy;
+
+ detail::disjoint::disjoint_interrupt_policy policy;
+ detail::self_get_turn_points::get_turns
+ <
+ false, turn_policy
+ >::apply(geometry, strategy, robust_policy, turns, policy, 0);
+ return policy.has_intersections;
+ }
+};
+
+}} // namespace detail::intersects
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTS_IMPLEMENTATION_HPP
diff --git a/boost/geometry/algorithms/detail/intersects/interface.hpp b/boost/geometry/algorithms/detail/intersects/interface.hpp
new file mode 100644
index 0000000000..8940a426f3
--- /dev/null
+++ b/boost/geometry/algorithms/detail/intersects/interface.hpp
@@ -0,0 +1,115 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
+
+// This file was modified by Oracle on 2013-2017.
+// Modifications copyright (c) 2013-2017, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+// 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_INTERSECTS_INTERFACE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTS_INTERFACE_HPP
+
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+
+#include <boost/geometry/algorithms/detail/disjoint/interface.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace intersects
+{
+
+// Forward declaration
+template <typename Geometry>
+struct self_intersects;
+
+}} // namespace detail::intersects
+#endif // DOXYGEN_NO_DETAIL
+
+
+/*!
+\brief \brief_check{has at least one intersection (crossing or self-tangency)}
+\note This function can be called for one geometry (self-intersection) and
+ also for two geometries (intersection)
+\ingroup intersects
+\tparam Geometry \tparam_geometry
+\param geometry \param_geometry
+\return \return_check{is self-intersecting}
+
+\qbk{distinguish,one geometry}
+\qbk{[def __one_parameter__]}
+\qbk{[include reference/algorithms/intersects.qbk]}
+*/
+template <typename Geometry>
+inline bool intersects(Geometry const& geometry)
+{
+ return detail::intersects::self_intersects<Geometry>::apply(geometry);
+}
+
+
+/*!
+\brief \brief_check2{have at least one intersection}
+\ingroup intersects
+\tparam Geometry1 \tparam_geometry
+\tparam Geometry2 \tparam_geometry
+\tparam Strategy \tparam_strategy{Intersects}
+\param geometry1 \param_geometry
+\param geometry2 \param_geometry
+\param strategy \param_strategy{intersects}
+\return \return_check2{intersect each other}
+
+\qbk{distinguish,with strategy}
+\qbk{[include reference/algorithms/intersects.qbk]}
+ */
+template <typename Geometry1, typename Geometry2, typename Strategy>
+inline bool intersects(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+{
+ concepts::check<Geometry1 const>();
+ concepts::check<Geometry2 const>();
+
+ return ! geometry::disjoint(geometry1, geometry2, strategy);
+}
+
+
+/*!
+\brief \brief_check2{have at least one intersection}
+\ingroup intersects
+\tparam Geometry1 \tparam_geometry
+\tparam Geometry2 \tparam_geometry
+\param geometry1 \param_geometry
+\param geometry2 \param_geometry
+\return \return_check2{intersect each other}
+
+\qbk{distinguish,two geometries}
+\qbk{[include reference/algorithms/intersects.qbk]}
+ */
+template <typename Geometry1, typename Geometry2>
+inline bool intersects(Geometry1 const& geometry1, Geometry2 const& geometry2)
+{
+ concepts::check<Geometry1 const>();
+ concepts::check<Geometry2 const>();
+
+ return ! geometry::disjoint(geometry1, geometry2);
+}
+
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTS_INTERFACE_HPP
diff --git a/boost/geometry/algorithms/detail/is_simple/linear.hpp b/boost/geometry/algorithms/detail/is_simple/linear.hpp
index 52b9d9d1c8..5acf56c5b1 100644
--- a/boost/geometry/algorithms/detail/is_simple/linear.hpp
+++ b/boost/geometry/algorithms/detail/is_simple/linear.hpp
@@ -219,12 +219,12 @@ inline bool has_self_intersections(Linear const& linear, Strategy const& strateg
detail::self_get_turn_points::get_turns
<
- turn_policy
+ false, turn_policy
>::apply(linear,
strategy,
detail::no_rescale_policy(),
turns,
- interrupt_policy);
+ interrupt_policy, 0);
detail::is_valid::debug_print_turns(turns.begin(), turns.end());
debug_print_boundary_points(linear);
@@ -236,7 +236,9 @@ inline bool has_self_intersections(Linear const& linear, Strategy const& strateg
template <typename Linestring, bool CheckSelfIntersections = true>
struct is_simple_linestring
{
- static inline bool apply(Linestring const& linestring)
+ template <typename Strategy>
+ static inline bool apply(Linestring const& linestring,
+ Strategy const& strategy)
{
simplicity_failure_policy policy;
return ! boost::empty(linestring)
@@ -247,7 +249,7 @@ struct is_simple_linestring
&& ! detail::is_valid::has_spikes
<
Linestring, closed
- >::apply(linestring, policy);
+ >::apply(linestring, policy, strategy.get_side_strategy());
}
};
@@ -258,7 +260,10 @@ struct is_simple_linestring<Linestring, true>
static inline bool apply(Linestring const& linestring,
Strategy const& strategy)
{
- return is_simple_linestring<Linestring, false>::apply(linestring)
+ return is_simple_linestring
+ <
+ Linestring, false
+ >::apply(linestring, strategy)
&& ! has_self_intersections(linestring, strategy);
}
};
@@ -267,23 +272,44 @@ struct is_simple_linestring<Linestring, true>
template <typename MultiLinestring>
struct is_simple_multilinestring
{
+private:
+ template <typename Strategy>
+ struct per_linestring
+ {
+ per_linestring(Strategy const& strategy)
+ : m_strategy(strategy)
+ {}
+
+ template <typename Linestring>
+ inline bool apply(Linestring const& linestring) const
+ {
+ return detail::is_simple::is_simple_linestring
+ <
+ Linestring,
+ false // do not compute self-intersections
+ >::apply(linestring, m_strategy);
+ }
+
+ Strategy const& m_strategy;
+ };
+
+public:
template <typename Strategy>
static inline bool apply(MultiLinestring const& multilinestring,
Strategy const& strategy)
{
+ typedef per_linestring<Strategy> per_ls;
+
// check each of the linestrings for simplicity
// but do not compute self-intersections yet; these will be
// computed for the entire multilinestring
if ( ! detail::check_iterator_range
<
- is_simple_linestring
- <
- typename boost::range_value<MultiLinestring>::type,
- false // do not compute self-intersections
- >,
+ per_ls, // do not compute self-intersections
true // allow empty multilinestring
>::apply(boost::begin(multilinestring),
- boost::end(multilinestring))
+ boost::end(multilinestring),
+ per_ls(strategy))
)
{
return false;
diff --git a/boost/geometry/algorithms/detail/is_valid/has_spikes.hpp b/boost/geometry/algorithms/detail/is_valid/has_spikes.hpp
index aa90e52db6..96efec79cd 100644
--- a/boost/geometry/algorithms/detail/is_valid/has_spikes.hpp
+++ b/boost/geometry/algorithms/detail/is_valid/has_spikes.hpp
@@ -1,8 +1,9 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2014-2015, Oracle and/or its affiliates.
+// Copyright (c) 2014-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
@@ -91,8 +92,9 @@ struct has_spikes
return std::find_if(second, last, not_equal(*first));
}
- template <typename VisitPolicy>
- static inline bool apply(Range const& range, VisitPolicy& visitor)
+ template <typename VisitPolicy, typename SideStrategy>
+ static inline bool apply(Range const& range, VisitPolicy& visitor,
+ SideStrategy const& strategy)
{
boost::ignore_unused(visitor);
@@ -124,9 +126,8 @@ struct has_spikes
while (next != boost::end(view))
{
- if ( geometry::detail::point_is_spike_or_equal(*prev,
- *next,
- *cur) )
+ if ( geometry::detail::point_is_spike_or_equal(*prev, *next, *cur,
+ strategy) )
{
return
! visitor.template apply<failure_spikes>(is_linear, *cur);
@@ -146,7 +147,7 @@ struct has_spikes
boost::rend(view));
iterator next = find_different_from_first(cur, boost::end(view));
- if (detail::point_is_spike_or_equal(*prev, *next, *cur))
+ if (detail::point_is_spike_or_equal(*prev, *next, *cur, strategy))
{
return
! visitor.template apply<failure_spikes>(is_linear, *cur);
diff --git a/boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp b/boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp
index b91dc6a697..b36e9f38b7 100644
--- a/boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp
+++ b/boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp
@@ -86,7 +86,7 @@ public:
IsAcceptableTurn
> interrupt_policy;
- geometry::self_turns<turn_policy>(geometry,
+ detail::self_get_turn_points::self_turns<false, turn_policy>(geometry,
strategy,
robust_policy,
turns,
diff --git a/boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp b/boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp
index 0d80d6f6c0..fccc0ffdb7 100644
--- a/boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp
+++ b/boost/geometry/algorithms/detail/is_valid/is_acceptable_turn.hpp
@@ -138,10 +138,17 @@ public:
}
operation_type const op = acceptable_operation<MultiPolygon>::value;
+ if ( base::check_turn(turn, method_touch_interior, op)
+ || base::check_turn(turn, method_touch, op))
+ {
+ return true;
+ }
- return base::check_turn(turn, method_touch_interior, op)
- || base::check_turn(turn, method_touch, op)
- ;
+ // Turn is acceptable only in case of a touch(interior) and both lines
+ // (polygons) do not cross
+ return (turn.method == method_touch
+ || turn.method == method_touch_interior)
+ && turn.touch_only;
}
};
diff --git a/boost/geometry/algorithms/detail/is_valid/linear.hpp b/boost/geometry/algorithms/detail/is_valid/linear.hpp
index 6bc6b86cf8..39cb36ef5b 100644
--- a/boost/geometry/algorithms/detail/is_valid/linear.hpp
+++ b/boost/geometry/algorithms/detail/is_valid/linear.hpp
@@ -43,9 +43,10 @@ namespace detail { namespace is_valid
template <typename Linestring>
struct is_valid_linestring
{
- template <typename VisitPolicy>
+ template <typename VisitPolicy, typename Strategy>
static inline bool apply(Linestring const& linestring,
- VisitPolicy& visitor)
+ VisitPolicy& visitor,
+ Strategy const& strategy)
{
if (has_invalid_coordinate<Linestring>::apply(linestring, visitor))
{
@@ -75,15 +76,12 @@ struct is_valid_linestring
{
return visitor.template apply<no_failure>();
}
- return ! has_spikes<Linestring, closed>::apply(linestring, visitor);
- }
- template <typename VisitPolicy, typename Strategy>
- static inline bool apply(Linestring const& linestring,
- VisitPolicy& visitor,
- Strategy const&)
- {
- return apply(linestring, visitor);
+ return ! has_spikes
+ <
+ Linestring, closed
+ >::apply(linestring, visitor,
+ strategy.get_side_strategy());
}
};
@@ -132,10 +130,13 @@ class is_valid
>
{
private:
- template <typename VisitPolicy>
+ template <typename VisitPolicy, typename Strategy>
struct per_linestring
{
- per_linestring(VisitPolicy& policy) : m_policy(policy) {}
+ per_linestring(VisitPolicy& policy, Strategy const& strategy)
+ : m_policy(policy)
+ , m_strategy(strategy)
+ {}
template <typename Linestring>
inline bool apply(Linestring const& linestring) const
@@ -143,17 +144,18 @@ private:
return detail::is_valid::is_valid_linestring
<
Linestring
- >::apply(linestring, m_policy);
+ >::apply(linestring, m_policy, m_strategy);
}
VisitPolicy& m_policy;
+ Strategy const& m_strategy;
};
public:
template <typename VisitPolicy, typename Strategy>
static inline bool apply(MultiLinestring const& multilinestring,
VisitPolicy& visitor,
- Strategy const&)
+ Strategy const& strategy)
{
if (BOOST_GEOMETRY_CONDITION(
AllowEmptyMultiGeometries && boost::empty(multilinestring)))
@@ -161,13 +163,15 @@ public:
return visitor.template apply<no_failure>();
}
+ typedef per_linestring<VisitPolicy, Strategy> per_ls;
+
return detail::check_iterator_range
<
- per_linestring<VisitPolicy>,
+ per_ls,
false // do not check for empty multilinestring (done above)
>::apply(boost::begin(multilinestring),
boost::end(multilinestring),
- per_linestring<VisitPolicy>(visitor));
+ per_ls(visitor, strategy));
}
};
diff --git a/boost/geometry/algorithms/detail/is_valid/multipolygon.hpp b/boost/geometry/algorithms/detail/is_valid/multipolygon.hpp
index 84dacc57f1..ed24b13810 100644
--- a/boost/geometry/algorithms/detail/is_valid/multipolygon.hpp
+++ b/boost/geometry/algorithms/detail/is_valid/multipolygon.hpp
@@ -76,45 +76,66 @@ private:
<
typename PolygonIterator,
typename TurnIterator,
- typename VisitPolicy
+ typename VisitPolicy,
+ typename Strategy
>
static inline
bool are_polygon_interiors_disjoint(PolygonIterator polygons_first,
PolygonIterator polygons_beyond,
TurnIterator turns_first,
TurnIterator turns_beyond,
- VisitPolicy& visitor)
+ VisitPolicy& visitor,
+ Strategy const& strategy)
{
boost::ignore_unused(visitor);
- // collect all polygons that have turns
+ // collect all polygons that have crossing turns
std::set<signed_size_type> multi_indices;
for (TurnIterator tit = turns_first; tit != turns_beyond; ++tit)
{
- multi_indices.insert(tit->operations[0].seg_id.multi_index);
- multi_indices.insert(tit->operations[1].seg_id.multi_index);
+ if (! tit->touch_only)
+ {
+ multi_indices.insert(tit->operations[0].seg_id.multi_index);
+ multi_indices.insert(tit->operations[1].seg_id.multi_index);
+ }
}
+ typedef geometry::model::box<typename point_type<MultiPolygon>::type> box_type;
+ typedef typename base::template partition_item<PolygonIterator, box_type> item_type;
+
// put polygon iterators without turns in a vector
- std::vector<PolygonIterator> polygon_iterators;
+ std::vector<item_type> polygon_iterators;
signed_size_type multi_index = 0;
for (PolygonIterator it = polygons_first; it != polygons_beyond;
++it, ++multi_index)
{
if (multi_indices.find(multi_index) == multi_indices.end())
{
- polygon_iterators.push_back(it);
+ polygon_iterators.push_back(item_type(it));
}
}
- typename base::item_visitor_type item_visitor;
+ // prepare strategies
+ typedef typename std::iterator_traits<PolygonIterator>::value_type polygon_type;
+ typedef typename Strategy::template point_in_geometry_strategy
+ <
+ polygon_type, polygon_type
+ >::type within_strategy_type;
+ within_strategy_type const within_strategy
+ = strategy.template get_point_in_geometry_strategy<polygon_type, polygon_type>();
+ typedef typename Strategy::envelope_strategy_type envelope_strategy_type;
+ envelope_strategy_type const envelope_strategy
+ = strategy.get_envelope_strategy();
+
+ // call partition to check if polygons are disjoint from each other
+ typename base::template item_visitor_type<within_strategy_type> item_visitor(within_strategy);
geometry::partition
<
geometry::model::box<typename point_type<MultiPolygon>::type>
>::apply(polygon_iterators, item_visitor,
- typename base::expand_box(),
- typename base::overlaps_box());
+ typename base::template expand_box<envelope_strategy_type>(envelope_strategy),
+ typename base::template overlaps_box<envelope_strategy_type>(envelope_strategy));
if (item_visitor.items_overlap)
{
@@ -155,13 +176,15 @@ private:
<
typename PolygonIterator,
typename TurnIterator,
- typename VisitPolicy
+ typename VisitPolicy,
+ typename Strategy
>
static inline bool apply(PolygonIterator polygons_first,
PolygonIterator polygons_beyond,
TurnIterator turns_first,
TurnIterator turns_beyond,
- VisitPolicy& visitor)
+ VisitPolicy& visitor,
+ Strategy const& strategy)
{
signed_size_type multi_index = 0;
for (PolygonIterator it = polygons_first; it != polygons_beyond;
@@ -185,7 +208,8 @@ private:
if (! Predicate::apply(*it,
filtered_turns_first,
filtered_turns_beyond,
- visitor))
+ visitor,
+ strategy))
{
return false;
}
@@ -200,19 +224,21 @@ private:
<
typename PolygonIterator,
typename TurnIterator,
- typename VisitPolicy
+ typename VisitPolicy,
+ typename Strategy
>
static inline bool have_holes_inside(PolygonIterator polygons_first,
PolygonIterator polygons_beyond,
TurnIterator turns_first,
TurnIterator turns_beyond,
- VisitPolicy& visitor)
+ VisitPolicy& visitor,
+ Strategy const& strategy)
{
return has_property_per_polygon
<
typename base::has_holes_inside
>::apply(polygons_first, polygons_beyond,
- turns_first, turns_beyond, visitor);
+ turns_first, turns_beyond, visitor, strategy);
}
@@ -221,19 +247,21 @@ private:
<
typename PolygonIterator,
typename TurnIterator,
- typename VisitPolicy
+ typename VisitPolicy,
+ typename Strategy
>
static inline bool have_connected_interior(PolygonIterator polygons_first,
PolygonIterator polygons_beyond,
TurnIterator turns_first,
TurnIterator turns_beyond,
- VisitPolicy& visitor)
+ VisitPolicy& visitor,
+ Strategy const& strategy)
{
return has_property_per_polygon
<
typename base::has_connected_interior
>::apply(polygons_first, polygons_beyond,
- turns_first, turns_beyond, visitor);
+ turns_first, turns_beyond, visitor, strategy);
}
@@ -307,7 +335,8 @@ public:
boost::end(multipolygon),
turns.begin(),
turns.end(),
- visitor))
+ visitor,
+ strategy))
{
return false;
}
@@ -320,7 +349,8 @@ public:
boost::end(multipolygon),
turns.begin(),
turns.end(),
- visitor))
+ visitor,
+ strategy))
{
return false;
}
@@ -332,7 +362,8 @@ public:
boost::end(multipolygon),
turns.begin(),
turns.end(),
- visitor);
+ visitor,
+ strategy);
}
};
diff --git a/boost/geometry/algorithms/detail/is_valid/polygon.hpp b/boost/geometry/algorithms/detail/is_valid/polygon.hpp
index f7e22fb8d2..5c6229b793 100644
--- a/boost/geometry/algorithms/detail/is_valid/polygon.hpp
+++ b/boost/geometry/algorithms/detail/is_valid/polygon.hpp
@@ -1,5 +1,7 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
+// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
+
// Copyright (c) 2014-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
@@ -43,6 +45,7 @@
#include <boost/geometry/algorithms/expand.hpp>
#include <boost/geometry/algorithms/num_interior_rings.hpp>
#include <boost/geometry/algorithms/validity_failure_type.hpp>
+#include <boost/geometry/algorithms/detail/point_on_border.hpp>
#include <boost/geometry/algorithms/within.hpp>
#include <boost/geometry/algorithms/detail/check_iterator_range.hpp>
@@ -142,43 +145,103 @@ protected:
};
+ // Iterator value_type is a Ring or Polygon
+ template <typename Iterator, typename Box>
+ struct partition_item
+ {
+ explicit partition_item(Iterator it)
+ : m_it(it)
+ , m_is_initialized(false)
+ {}
+
+ Iterator get() const
+ {
+ return m_it;
+ }
+
+ template <typename EnvelopeStrategy>
+ Box const& get_envelope(EnvelopeStrategy const& strategy) const
+ {
+ if (! m_is_initialized)
+ {
+ m_box = geometry::return_envelope<Box>(*m_it, strategy);
+ m_is_initialized = true;
+ }
+ return m_box;
+ }
+
+ private:
+ Iterator m_it;
+ mutable Box m_box;
+ mutable bool m_is_initialized;
+ };
+
// structs for partition -- start
+ template <typename EnvelopeStrategy>
struct expand_box
{
+ explicit expand_box(EnvelopeStrategy const& strategy) : m_strategy(strategy) {}
+
template <typename Box, typename Iterator>
- static inline void apply(Box& total, Iterator const& it)
+ inline void apply(Box& total, partition_item<Iterator, Box> const& item) const
{
- geometry::expand(total, geometry::return_envelope<Box>(*it));
+ geometry::expand(total, item.get_envelope(m_strategy));
}
+ EnvelopeStrategy const& m_strategy;
};
+ template <typename EnvelopeStrategy>
struct overlaps_box
{
+ explicit overlaps_box(EnvelopeStrategy const& strategy) : m_strategy(strategy) {}
+
template <typename Box, typename Iterator>
- static inline bool apply(Box const& box, Iterator const& it)
+ inline bool apply(Box const& box, partition_item<Iterator, Box> const& item) const
{
- return ! geometry::disjoint(*it, box);
+ return ! geometry::disjoint(item.get_envelope(m_strategy), box);
}
+
+ EnvelopeStrategy const& m_strategy;
};
+ template <typename WithinStrategy>
struct item_visitor_type
{
bool items_overlap;
+ WithinStrategy const& m_strategy;
+
+ explicit item_visitor_type(WithinStrategy const& strategy)
+ : items_overlap(false)
+ , m_strategy(strategy)
+ {}
- item_visitor_type() : items_overlap(false) {}
+ template <typename Item>
+ inline bool is_within(Item const& first, Item const& second)
+ {
+ typename point_type<Polygon>::type point;
+ typedef detail::point_on_border::point_on_range<true> pob;
+
+ // TODO: this should check for a point on the interior, instead
+ // of on border. Or it should check using the overlap function.
+
+ return pob::apply(point, points_begin(first), points_end(first))
+ && geometry::within(point, second, m_strategy);
+ }
- template <typename Item1, typename Item2>
- inline void apply(Item1 const& item1, Item2 const& item2)
+ template <typename Iterator, typename Box>
+ inline bool apply(partition_item<Iterator, Box> const& item1,
+ partition_item<Iterator, Box> const& item2)
{
if (! items_overlap
- && (geometry::within(*points_begin(*item1), *item2)
- || geometry::within(*points_begin(*item2), *item1))
- )
+ && (is_within(*item1.get(), *item2.get())
+ || is_within(*item2.get(), *item1.get())))
{
items_overlap = true;
+ return false; // interrupt
}
+ return true;
}
};
// structs for partition -- end
@@ -189,14 +252,16 @@ protected:
typename RingIterator,
typename ExteriorRing,
typename TurnIterator,
- typename VisitPolicy
+ typename VisitPolicy,
+ typename Strategy
>
static inline bool are_holes_inside(RingIterator rings_first,
RingIterator rings_beyond,
ExteriorRing const& exterior_ring,
TurnIterator turns_first,
TurnIterator turns_beyond,
- VisitPolicy& visitor)
+ VisitPolicy& visitor,
+ Strategy const& strategy)
{
boost::ignore_unused(visitor);
@@ -217,6 +282,14 @@ protected:
}
}
+ // prepare strategy
+ typedef typename std::iterator_traits<RingIterator>::value_type inter_ring_type;
+ typename Strategy::template point_in_geometry_strategy
+ <
+ inter_ring_type, ExteriorRing
+ >::type const in_exterior_strategy
+ = strategy.template get_point_in_geometry_strategy<inter_ring_type, ExteriorRing>();
+
signed_size_type ring_index = 0;
for (RingIterator it = rings_first; it != rings_beyond;
++it, ++ring_index)
@@ -224,7 +297,7 @@ protected:
// do not examine interior rings that have turns with the
// exterior ring
if (ring_indices.find(ring_index) == ring_indices.end()
- && ! geometry::covered_by(range::front(*it), exterior_ring))
+ && ! geometry::covered_by(range::front(*it), exterior_ring, in_exterior_strategy))
{
return visitor.template apply<failure_interior_rings_outside>();
}
@@ -237,26 +310,42 @@ protected:
ring_indices.insert(tit->operations[1].seg_id.ring_index);
}
+ typedef geometry::model::box<typename point_type<Polygon>::type> box_type;
+ typedef partition_item<RingIterator, box_type> item_type;
+
// put iterators for interior rings without turns in a vector
- std::vector<RingIterator> ring_iterators;
+ std::vector<item_type> ring_iterators;
ring_index = 0;
for (RingIterator it = rings_first; it != rings_beyond;
++it, ++ring_index)
{
if (ring_indices.find(ring_index) == ring_indices.end())
{
- ring_iterators.push_back(it);
+ ring_iterators.push_back(item_type(it));
}
}
- // call partition to check is interior rings are disjoint from
+ // prepare strategies
+ typedef typename Strategy::template point_in_geometry_strategy
+ <
+ inter_ring_type, inter_ring_type
+ >::type in_interior_strategy_type;
+ in_interior_strategy_type const in_interior_strategy
+ = strategy.template get_point_in_geometry_strategy<inter_ring_type, inter_ring_type>();
+ typedef typename Strategy::envelope_strategy_type envelope_strategy_type;
+ envelope_strategy_type const envelope_strategy
+ = strategy.get_envelope_strategy();
+
+ // call partition to check if interior rings are disjoint from
// each other
- item_visitor_type item_visitor;
+ item_visitor_type<in_interior_strategy_type> item_visitor(in_interior_strategy);
geometry::partition
<
- geometry::model::box<typename point_type<Polygon>::type>
- >::apply(ring_iterators, item_visitor, expand_box(), overlaps_box());
+ box_type
+ >::apply(ring_iterators, item_visitor,
+ expand_box<envelope_strategy_type>(envelope_strategy),
+ overlaps_box<envelope_strategy_type>(envelope_strategy));
if (item_visitor.items_overlap)
{
@@ -273,35 +362,40 @@ protected:
typename InteriorRings,
typename ExteriorRing,
typename TurnIterator,
- typename VisitPolicy
+ typename VisitPolicy,
+ typename Strategy
>
static inline bool are_holes_inside(InteriorRings const& interior_rings,
ExteriorRing const& exterior_ring,
TurnIterator first,
TurnIterator beyond,
- VisitPolicy& visitor)
+ VisitPolicy& visitor,
+ Strategy const& strategy)
{
return are_holes_inside(boost::begin(interior_rings),
boost::end(interior_rings),
exterior_ring,
first,
beyond,
- visitor);
+ visitor,
+ strategy);
}
struct has_holes_inside
{
- template <typename TurnIterator, typename VisitPolicy>
+ template <typename TurnIterator, typename VisitPolicy, typename Strategy>
static inline bool apply(Polygon const& polygon,
TurnIterator first,
TurnIterator beyond,
- VisitPolicy& visitor)
+ VisitPolicy& visitor,
+ Strategy const& strategy)
{
return are_holes_inside(geometry::interior_rings(polygon),
geometry::exterior_ring(polygon),
first,
beyond,
- visitor);
+ visitor,
+ strategy);
}
};
@@ -310,11 +404,12 @@ protected:
struct has_connected_interior
{
- template <typename TurnIterator, typename VisitPolicy>
+ template <typename TurnIterator, typename VisitPolicy, typename Strategy>
static inline bool apply(Polygon const& polygon,
TurnIterator first,
TurnIterator beyond,
- VisitPolicy& visitor)
+ VisitPolicy& visitor,
+ Strategy const& )
{
boost::ignore_unused(visitor);
@@ -388,7 +483,8 @@ public:
if (! has_holes_inside::apply(polygon,
turns.begin(), turns.end(),
- visitor))
+ visitor,
+ strategy))
{
return false;
}
@@ -399,7 +495,8 @@ public:
return has_connected_interior::apply(polygon,
turns.begin(),
turns.end(),
- visitor);
+ visitor,
+ strategy);
}
};
diff --git a/boost/geometry/algorithms/detail/is_valid/ring.hpp b/boost/geometry/algorithms/detail/is_valid/ring.hpp
index 9ab68fdc48..0b95950430 100644
--- a/boost/geometry/algorithms/detail/is_valid/ring.hpp
+++ b/boost/geometry/algorithms/detail/is_valid/ring.hpp
@@ -115,7 +115,10 @@ struct is_properly_oriented
geometry::closure<Ring>::value
> ring_area_type;
- typedef typename default_area_result<Ring>::type area_result_type;
+ typedef typename Strategy::template area_strategy
+ <
+ point_type
+ >::type::return_type area_result_type;
typename ring_area_predicate
<
@@ -195,7 +198,7 @@ struct is_valid_ring
return
is_topologically_closed<Ring, closure>::apply(ring, visitor)
&& ! has_duplicates<Ring, closure>::apply(ring, visitor)
- && ! has_spikes<Ring, closure>::apply(ring, visitor)
+ && ! has_spikes<Ring, closure>::apply(ring, visitor, strategy.get_side_strategy())
&& (! CheckSelfIntersections
|| has_valid_self_turns<Ring>::apply(ring, visitor, strategy))
&& is_properly_oriented<Ring, IsInteriorRing>::apply(ring, visitor, strategy);
diff --git a/boost/geometry/algorithms/detail/multi_modify.hpp b/boost/geometry/algorithms/detail/multi_modify.hpp
index f0b9ddd3e6..23187f9323 100644
--- a/boost/geometry/algorithms/detail/multi_modify.hpp
+++ b/boost/geometry/algorithms/detail/multi_modify.hpp
@@ -4,6 +4,10 @@
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// This file was modified by Oracle on 2017.
+// Modifications copyright (c) 2017 Oracle and/or its affiliates.
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -40,6 +44,18 @@ struct multi_modify
Policy::apply(*it);
}
}
+
+ template <typename Strategy>
+ static inline void apply(MultiGeometry& multi, Strategy const& strategy)
+ {
+ typedef typename boost::range_iterator<MultiGeometry>::type iterator_type;
+ for (iterator_type it = boost::begin(multi);
+ it != boost::end(multi);
+ ++it)
+ {
+ Policy::apply(*it, strategy);
+ }
+ }
};
diff --git a/boost/geometry/algorithms/detail/occupation_info.hpp b/boost/geometry/algorithms/detail/occupation_info.hpp
index 4048d59d75..fc74f0cc7f 100644
--- a/boost/geometry/algorithms/detail/occupation_info.hpp
+++ b/boost/geometry/algorithms/detail/occupation_info.hpp
@@ -2,6 +2,11 @@
// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
+// This file was modified by Oracle on 2017.
+// Modifications copyright (c) 2017, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
// 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)
@@ -99,12 +104,18 @@ public :
}
}
- template <typename RobustPoint, typename Turns>
- inline void get_left_turns(RobustPoint const& origin, Turns& turns)
+ template <typename RobustPoint, typename Turns, typename SideStrategy>
+ inline void get_left_turns(RobustPoint const& origin, Turns& turns,
+ SideStrategy const& strategy)
{
+ typedef detail::left_turns::angle_less
+ <
+ typename AngleInfo::point_type,
+ SideStrategy
+ > angle_less;
+
// Sort on angle
- std::sort(m_angles.begin(), m_angles.end(),
- detail::left_turns::angle_less<typename AngleInfo::point_type>(origin));
+ std::sort(m_angles.begin(), m_angles.end(), angle_less(origin, strategy));
// Group same-angled elements
std::size_t cluster_size = detail::left_turns::assign_cluster_indices(m_angles, origin);
diff --git a/boost/geometry/algorithms/detail/overlaps/implementation.hpp b/boost/geometry/algorithms/detail/overlaps/implementation.hpp
new file mode 100644
index 0000000000..49f44bef81
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlaps/implementation.hpp
@@ -0,0 +1,156 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
+
+// This file was modified by Oracle on 2014, 2015, 2017.
+// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+// 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_OVERLAPS_IMPLEMENTATION_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAPS_IMPLEMENTATION_HPP
+
+
+#include <cstddef>
+
+#include <boost/geometry/core/access.hpp>
+
+#include <boost/geometry/algorithms/not_implemented.hpp>
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+
+#include <boost/geometry/algorithms/relate.hpp>
+#include <boost/geometry/algorithms/detail/overlaps/interface.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlaps
+{
+
+template
+<
+ std::size_t Dimension,
+ std::size_t DimensionCount
+>
+struct box_box_loop
+{
+ template <typename Box1, typename Box2>
+ static inline void apply(Box1 const& b1, Box2 const& b2,
+ bool& overlaps, bool& one_in_two, bool& two_in_one)
+ {
+ assert_dimension_equal<Box1, Box2>();
+
+ typedef typename coordinate_type<Box1>::type coordinate_type1;
+ typedef typename coordinate_type<Box2>::type coordinate_type2;
+
+ coordinate_type1 const& min1 = get<min_corner, Dimension>(b1);
+ coordinate_type1 const& max1 = get<max_corner, Dimension>(b1);
+ coordinate_type2 const& min2 = get<min_corner, Dimension>(b2);
+ coordinate_type2 const& max2 = get<max_corner, Dimension>(b2);
+
+ // We might use the (not yet accepted) Boost.Interval
+ // submission in the future
+
+ // If:
+ // B1: |-------|
+ // B2: |------|
+ // in any dimension -> no overlap
+ if (max1 <= min2 || min1 >= max2)
+ {
+ overlaps = false;
+ return;
+ }
+
+ // If:
+ // B1: |--------------------|
+ // B2: |-------------|
+ // in all dimensions -> within, then no overlap
+ // B1: |--------------------|
+ // B2: |-------------|
+ // this is "within-touch" -> then no overlap. So use < and >
+ if (min1 < min2 || max1 > max2)
+ {
+ one_in_two = false;
+ }
+
+ // Same other way round
+ if (min2 < min1 || max2 > max1)
+ {
+ two_in_one = false;
+ }
+
+ box_box_loop
+ <
+ Dimension + 1,
+ DimensionCount
+ >::apply(b1, b2, overlaps, one_in_two, two_in_one);
+ }
+};
+
+template
+<
+ std::size_t DimensionCount
+>
+struct box_box_loop<DimensionCount, DimensionCount>
+{
+ template <typename Box1, typename Box2>
+ static inline void apply(Box1 const& , Box2 const&, bool&, bool&, bool&)
+ {
+ }
+};
+
+struct box_box
+{
+ template <typename Box1, typename Box2, typename Strategy>
+ static inline bool apply(Box1 const& b1, Box2 const& b2, Strategy const& /*strategy*/)
+ {
+ bool overlaps = true;
+ bool within1 = true;
+ bool within2 = true;
+ box_box_loop
+ <
+ 0,
+ dimension<Box1>::type::value
+ >::apply(b1, b2, overlaps, within1, within2);
+
+ /*
+ \see http://docs.codehaus.org/display/GEOTDOC/02+Geometry+Relationships#02GeometryRelationships-Overlaps
+ where is stated that "inside" is not an "overlap",
+ this is true and is implemented as such.
+ */
+ return overlaps && ! within1 && ! within2;
+ }
+};
+
+}} // namespace detail::overlaps
+#endif // DOXYGEN_NO_DETAIL
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+template <typename Box1, typename Box2>
+struct overlaps<Box1, Box2, box_tag, box_tag>
+ : detail::overlaps::box_box
+{};
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAPS_IMPLEMENTATION_HPP
diff --git a/boost/geometry/algorithms/detail/overlaps/interface.hpp b/boost/geometry/algorithms/detail/overlaps/interface.hpp
new file mode 100644
index 0000000000..f9f6a853fd
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlaps/interface.hpp
@@ -0,0 +1,124 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
+
+// This file was modified by Oracle on 2014, 2015, 2017.
+// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+// 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_OVERLAPS_INTERFACE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAPS_INTERFACE_HPP
+
+
+#include <cstddef>
+
+#include <boost/geometry/algorithms/not_implemented.hpp>
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+
+#include <boost/geometry/algorithms/detail/relate/relate_impl.hpp>
+
+#include <boost/geometry/strategies/relate.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template
+<
+ typename Geometry1,
+ typename Geometry2,
+ typename Tag1 = typename tag<Geometry1>::type,
+ typename Tag2 = typename tag<Geometry2>::type
+>
+struct overlaps
+ : detail::relate::relate_impl
+ <
+ detail::de9im::static_mask_overlaps_type,
+ Geometry1,
+ Geometry2
+ >
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+/*!
+\brief \brief_check2{overlap}
+\ingroup overlaps
+\tparam Geometry1 \tparam_geometry
+\tparam Geometry2 \tparam_geometry
+\tparam Strategy \tparam_strategy{Overlaps}
+\param geometry1 \param_geometry
+\param geometry2 \param_geometry
+\param strategy \param_strategy{overlaps}
+\return \return_check2{overlap}
+
+\qbk{distinguish,with strategy}
+\qbk{[include reference/algorithms/overlaps.qbk]}
+*/
+template <typename Geometry1, typename Geometry2, typename Strategy>
+inline bool overlaps(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+{
+ concepts::check<Geometry1 const>();
+ concepts::check<Geometry2 const>();
+
+ return dispatch::overlaps
+ <
+ Geometry1,
+ Geometry2
+ >::apply(geometry1, geometry2, strategy);
+}
+
+/*!
+\brief \brief_check2{overlap}
+\ingroup overlaps
+\tparam Geometry1 \tparam_geometry
+\tparam Geometry2 \tparam_geometry
+\param geometry1 \param_geometry
+\param geometry2 \param_geometry
+\return \return_check2{overlap}
+
+\qbk{[include reference/algorithms/overlaps.qbk]}
+*/
+template <typename Geometry1, typename Geometry2>
+inline bool overlaps(Geometry1 const& geometry1, Geometry2 const& geometry2)
+{
+ concepts::check<Geometry1 const>();
+ concepts::check<Geometry2 const>();
+
+ typedef typename strategy::relate::services::default_strategy
+ <
+ Geometry1,
+ Geometry2
+ >::type strategy_type;
+
+ return dispatch::overlaps
+ <
+ Geometry1,
+ Geometry2
+ >::apply(geometry1, geometry2, strategy_type());
+}
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAPS_INTERFACE_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/aggregate_operations.hpp b/boost/geometry/algorithms/detail/overlay/aggregate_operations.hpp
index df62a1f2f6..106ecaad07 100644
--- a/boost/geometry/algorithms/detail/overlay/aggregate_operations.hpp
+++ b/boost/geometry/algorithms/detail/overlay/aggregate_operations.hpp
@@ -24,8 +24,12 @@ struct ring_with_direction
{
ring_identifier ring_id;
direction_type direction;
- bool only_turn_on_ring;
+ std::size_t turn_index;
+ int operation_index;
+ operation_type operation;
+ signed_size_type region_id;
+ bool isolated;
inline bool operator<(ring_with_direction const& other) const
{
@@ -36,7 +40,11 @@ struct ring_with_direction
ring_with_direction()
: direction(dir_unknown)
- , only_turn_on_ring(false)
+ , turn_index(-1)
+ , operation_index(0)
+ , operation(operation_none)
+ , region_id(-1)
+ , isolated(false)
{}
};
@@ -50,28 +58,168 @@ struct rank_with_rings
{
}
+ inline bool all_equal(direction_type dir_type) const
+ {
+ for (std::set<ring_with_direction>::const_iterator it = rings.begin();
+ it != rings.end(); ++it)
+ {
+ if (it->direction != dir_type)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
inline bool all_to() const
{
+ return all_equal(sort_by_side::dir_to);
+ }
+
+ inline bool all_from() const
+ {
+ return all_equal(sort_by_side::dir_from);
+ }
+
+ inline bool has_only(operation_type op) const
+ {
+ for (std::set<ring_with_direction>::const_iterator it = rings.begin();
+ it != rings.end(); ++it)
+ {
+ const ring_with_direction& rwd = *it;
+ if (rwd.operation != op)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ //! Check if set has both op1 and op2, but no others
+ inline bool has_only_both(operation_type op1, operation_type op2) const
+ {
+ bool has1 = false;
+ bool has2 = false;
for (std::set<ring_with_direction>::const_iterator it = rings.begin();
it != rings.end(); ++it)
{
- if (it->direction == sort_by_side::dir_from)
+ const ring_with_direction& rwd = *it;
+
+ if (rwd.operation == op1) { has1 = true; }
+ else if (rwd.operation == op2) { has2 = true; }
+ else { return false; }
+ }
+ return has1 && has2;
+ }
+
+ inline bool is_isolated() const
+ {
+ for (std::set<ring_with_direction>::const_iterator it = rings.begin();
+ it != rings.end(); ++it)
+ {
+ const ring_with_direction& rwd = *it;
+ if (! rwd.isolated)
{
return false;
}
}
return true;
}
+
+ inline bool has_unique_region_id() const
+ {
+ int region_id = -1;
+ for (std::set<ring_with_direction>::const_iterator it = rings.begin();
+ it != rings.end(); ++it)
+ {
+ const ring_with_direction& rwd = *it;
+ if (region_id == -1)
+ {
+ region_id = rwd.region_id;
+ }
+ else if (rwd.region_id != region_id)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ inline int region_id() const
+ {
+ int region_id = -1;
+ for (std::set<ring_with_direction>::const_iterator it = rings.begin();
+ it != rings.end(); ++it)
+ {
+ const ring_with_direction& rwd = *it;
+ if (region_id == -1)
+ {
+ region_id = rwd.region_id;
+ }
+ else if (rwd.region_id != region_id)
+ {
+ return -1;
+ }
+ }
+ return region_id;
+ }
+
+ template <typename Turns>
+ inline bool traversable(Turns const& turns) const
+ {
+ typedef typename boost::range_value<Turns>::type turn_type;
+ typedef typename turn_type::turn_operation_type turn_operation_type;
+
+ for (std::set<ring_with_direction>::const_iterator it = rings.begin();
+ it != rings.end(); ++it)
+ {
+ const ring_with_direction& rwd = *it;
+ turn_type const& turn = turns[rwd.turn_index];
+ turn_operation_type const& op = turn.operations[rwd.operation_index];
+
+ // TODO: this is still necessary, but makes it order-dependent
+ // which should not be done.
+
+ // This would obsolete the whole function and should be solved
+ // in a different way
+ if (op.visited.finalized() || op.visited.visited())
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
};
-template <typename Sbs>
-inline void aggregate_operations(Sbs const& sbs, std::vector<rank_with_rings>& aggregation)
+template <typename Sbs, typename Turns>
+inline void aggregate_operations(Sbs const& sbs, std::vector<rank_with_rings>& aggregation,
+ Turns const& turns,
+ operation_type target_operation)
{
+ typedef typename boost::range_value<Turns>::type turn_type;
+ typedef typename turn_type::turn_operation_type turn_operation_type;
+
aggregation.clear();
for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++)
{
typename Sbs::rp const& ranked_point = sbs.m_ranked_points[i];
+ turn_type const& turn = turns[ranked_point.turn_index];
+
+ turn_operation_type const& op = turn.operations[ranked_point.operation_index];
+
+ if (! ((target_operation == operation_union && ranked_point.rank == 0)
+ || op.operation == target_operation
+ || op.operation == operation_continue
+ || (op.operation == operation_blocked && ranked_point.direction == dir_from)))
+ {
+ // Always take rank 0 (because self-turns are blocked)
+ // Don't consider union/blocked (aggregate is only used for intersections)
+ // Blocked is allowed for from
+ continue;
+ }
+
if (aggregation.empty() || aggregation.back().rank != ranked_point.rank)
{
rank_with_rings current;
@@ -81,10 +229,14 @@ inline void aggregate_operations(Sbs const& sbs, std::vector<rank_with_rings>& a
ring_with_direction rwd;
segment_identifier const& sid = ranked_point.seg_id;
+
rwd.ring_id = ring_identifier(sid.source_index, sid.multi_index, sid.ring_index);
rwd.direction = ranked_point.direction;
- rwd.only_turn_on_ring = ranked_point.only_turn_on_ring;
-
+ rwd.turn_index = ranked_point.turn_index;
+ rwd.operation_index = ranked_point.operation_index;
+ rwd.operation = op.operation;
+ rwd.region_id = op.enriched.region_id;
+ rwd.isolated = op.enriched.isolated;
aggregation.back().rings.insert(rwd);
}
diff --git a/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp b/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp
index 03c06c28d1..fb73840798 100644
--- a/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp
+++ b/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp
@@ -2,8 +2,8 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
-// This file was modified by Oracle on 2014.
-// Modifications copyright (c) 2014 Oracle and/or its affiliates.
+// This file was modified by Oracle on 2014, 2017.
+// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -63,8 +63,9 @@ inline bool points_equal_or_close(Point1 const& point1,
}
-template <typename Range, typename Point, typename RobustPolicy>
+template <typename Range, typename Point, typename SideStrategy, typename RobustPolicy>
inline void append_no_dups_or_spikes(Range& range, Point const& point,
+ SideStrategy const& strategy,
RobustPolicy const& robust_policy)
{
#ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION
@@ -92,6 +93,7 @@ inline void append_no_dups_or_spikes(Range& range, Point const& point,
&& point_is_spike_or_equal(point,
*(boost::end(range) - 3),
*(boost::end(range) - 2),
+ strategy,
robust_policy))
{
// Use the Concept/traits, so resize and append again
@@ -100,8 +102,9 @@ inline void append_no_dups_or_spikes(Range& range, Point const& point,
}
}
-template <typename Range, typename RobustPolicy>
+template <typename Range, typename SideStrategy, typename RobustPolicy>
inline void clean_closing_dups_and_spikes(Range& range,
+ SideStrategy const& strategy,
RobustPolicy const& robust_policy)
{
std::size_t const minsize
@@ -135,7 +138,7 @@ inline void clean_closing_dups_and_spikes(Range& range,
// Check if closing point is a spike (this is so if the second point is
// considered as a spike w.r.t. the last segment)
- if (point_is_spike_or_equal(*second, *ultimate, *first, robust_policy))
+ if (point_is_spike_or_equal(*second, *ultimate, *first, strategy, robust_policy))
{
range::erase(range, first);
if (BOOST_GEOMETRY_CONDITION(closed))
diff --git a/boost/geometry/algorithms/detail/overlay/assign_parents.hpp b/boost/geometry/algorithms/detail/overlay/assign_parents.hpp
index 2408b4b68e..78160f5204 100644
--- a/boost/geometry/algorithms/detail/overlay/assign_parents.hpp
+++ b/boost/geometry/algorithms/detail/overlay/assign_parents.hpp
@@ -20,7 +20,8 @@
#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/algorithms/detail/overlay/range_in_geometry.hpp>
+#include <boost/geometry/algorithms/covered_by.hpp>
#include <boost/geometry/geometries/box.hpp>
@@ -37,50 +38,88 @@ namespace detail { namespace overlay
template
<
typename Item,
+ typename InnerGeometry,
typename Geometry1, typename Geometry2,
- typename RingCollection
+ typename RingCollection,
+ typename Strategy
+>
+static inline bool within_selected_input(Item const& item2,
+ InnerGeometry const& inner_geometry,
+ ring_identifier const& outer_id,
+ Geometry1 const& geometry1, Geometry2 const& geometry2,
+ RingCollection const& collection,
+ Strategy const& strategy)
+{
+ typedef typename geometry::tag<Geometry1>::type tag1;
+ typedef typename geometry::tag<Geometry2>::type tag2;
+
+ // NOTE: range_in_geometry first checks the item2.point and then
+ // if this point is on boundary it checks points of inner_geometry
+ // ring until a point inside/outside other geometry ring is found
+ switch (outer_id.source_index)
+ {
+ // covered_by
+ case 0 :
+ return range_in_geometry(item2.point, inner_geometry,
+ get_ring<tag1>::apply(outer_id, geometry1), strategy) >= 0;
+ case 1 :
+ return range_in_geometry(item2.point, inner_geometry,
+ get_ring<tag2>::apply(outer_id, geometry2), strategy) >= 0;
+ case 2 :
+ return range_in_geometry(item2.point, inner_geometry,
+ get_ring<void>::apply(outer_id, collection), strategy) >= 0;
+ }
+ return false;
+}
+
+template
+<
+ typename Item,
+ typename Geometry1, typename Geometry2,
+ typename RingCollection,
+ typename Strategy
>
-static inline bool within_selected_input(Item const& item2, ring_identifier const& ring_id,
+static inline bool within_selected_input(Item const& item2,
+ ring_identifier const& inner_id, ring_identifier const& outer_id,
Geometry1 const& geometry1, Geometry2 const& geometry2,
- RingCollection const& collection)
+ RingCollection const& collection,
+ Strategy const& strategy)
{
typedef typename geometry::tag<Geometry1>::type tag1;
typedef typename geometry::tag<Geometry2>::type tag2;
- switch (ring_id.source_index)
+ switch (inner_id.source_index)
{
case 0 :
- return geometry::within(item2.point,
- get_ring<tag1>::apply(ring_id, geometry1));
- break;
+ return within_selected_input(item2,
+ get_ring<tag1>::apply(inner_id, geometry1),
+ outer_id, geometry1, geometry2, collection, strategy);
case 1 :
- return geometry::within(item2.point,
- get_ring<tag2>::apply(ring_id, geometry2));
- break;
+ return within_selected_input(item2,
+ get_ring<tag2>::apply(inner_id, geometry2),
+ outer_id, geometry1, geometry2, collection, strategy);
case 2 :
- return geometry::within(item2.point,
- get_ring<void>::apply(ring_id, collection));
- break;
+ return within_selected_input(item2,
+ get_ring<void>::apply(inner_id, collection),
+ outer_id, geometry1, geometry2, collection, strategy);
}
return false;
}
-template <typename Point>
+template <typename Point, typename AreaType>
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;
+ AreaType real_area;
+ AreaType 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)
+ inline ring_info_helper(ring_identifier i, AreaType const& a)
: id(i), real_area(a), abs_area(geometry::math::abs(a))
{}
};
@@ -104,7 +143,14 @@ struct ring_info_helper_ovelaps_box
}
};
-template <typename Geometry1, typename Geometry2, typename Collection, typename RingMap>
+template
+<
+ typename Geometry1,
+ typename Geometry2,
+ typename Collection,
+ typename RingMap,
+ typename Strategy
+>
struct assign_visitor
{
typedef typename RingMap::mapped_type ring_info_type;
@@ -113,26 +159,27 @@ struct assign_visitor
Geometry2 const& m_geometry2;
Collection const& m_collection;
RingMap& m_ring_map;
+ Strategy const& m_strategy;
bool m_check_for_orientation;
-
inline assign_visitor(Geometry1 const& g1, Geometry2 const& g2, Collection const& c,
- RingMap& map, bool check)
+ RingMap& map, Strategy const& strategy, bool check)
: m_geometry1(g1)
, m_geometry2(g2)
, m_collection(c)
, m_ring_map(map)
+ , m_strategy(strategy)
, m_check_for_orientation(check)
{}
template <typename Item>
- inline void apply(Item const& outer, Item const& inner, bool first = true)
+ inline bool apply(Item const& outer, Item const& inner, bool first = true)
{
if (first && outer.abs_area < inner.abs_area)
{
// Apply with reversed arguments
apply(inner, outer, false);
- return;
+ return true;
}
if (m_check_for_orientation
@@ -141,8 +188,10 @@ struct assign_visitor
{
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)
+ if (geometry::covered_by(inner_in_map.point, outer.envelope)
+ && within_selected_input(inner_in_map, inner.id, outer.id,
+ m_geometry1, m_geometry2, m_collection,
+ m_strategy)
)
{
// Assign a parent if there was no earlier parent, or the newly
@@ -155,6 +204,8 @@ struct assign_visitor
}
}
}
+
+ return true;
}
};
@@ -165,12 +216,14 @@ template
<
typename Geometry1, typename Geometry2,
typename RingCollection,
- typename RingMap
+ typename RingMap,
+ typename Strategy
>
inline void assign_parents(Geometry1 const& geometry1,
Geometry2 const& geometry2,
RingCollection const& collection,
RingMap& ring_map,
+ Strategy const& strategy,
bool check_for_orientation = false)
{
typedef typename geometry::tag<Geometry1>::type tag1;
@@ -179,11 +232,15 @@ inline void assign_parents(Geometry1 const& geometry1,
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 Strategy::template area_strategy
+ <
+ point_type
+ >::type::return_type area_result_type;
typedef typename RingMap::iterator map_iterator_type;
{
- typedef ring_info_helper<point_type> helper;
+ typedef ring_info_helper<point_type, area_result_type> helper;
typedef std::vector<helper> vector_type;
typedef typename boost::range_iterator<vector_type const>::type vector_iterator_type;
@@ -204,17 +261,21 @@ inline void assign_parents(Geometry1 const& geometry1,
{
case 0 :
geometry::envelope(get_ring<tag1>::apply(it->first, geometry1),
- item.envelope);
+ item.envelope, strategy.get_envelope_strategy());
break;
case 1 :
geometry::envelope(get_ring<tag2>::apply(it->first, geometry2),
- item.envelope);
+ item.envelope, strategy.get_envelope_strategy());
break;
case 2 :
geometry::envelope(get_ring<void>::apply(it->first, collection),
- item.envelope);
+ item.envelope, strategy.get_envelope_strategy());
break;
}
+
+ // Expand envelope slightly
+ expand_by_epsilon(item.envelope);
+
if (item.real_area > 0)
{
count_positive++;
@@ -257,8 +318,9 @@ inline void assign_parents(Geometry1 const& geometry1,
assign_visitor
<
Geometry1, Geometry2,
- RingCollection, RingMap
- > visitor(geometry1, geometry2, collection, ring_map, check_for_orientation);
+ RingCollection, RingMap,
+ Strategy
+ > visitor(geometry1, geometry2, collection, ring_map, strategy, check_for_orientation);
geometry::partition
<
@@ -315,18 +377,20 @@ template
<
typename Geometry,
typename RingCollection,
- typename RingMap
+ typename RingMap,
+ typename Strategy
>
inline void assign_parents(Geometry const& geometry,
RingCollection const& collection,
RingMap& ring_map,
+ Strategy const& strategy,
bool check_for_orientation)
{
// Call it with an empty geometry as second geometry (source_id == 1)
// (ring_map should be empty for source_id==1)
Geometry empty;
- assign_parents(geometry, empty, collection, ring_map, check_for_orientation);
+ assign_parents(geometry, empty, collection, ring_map, strategy, check_for_orientation);
}
diff --git a/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp b/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp
index 795523d7a0..0e9bfe2ea0 100644
--- a/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp
+++ b/boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp
@@ -20,6 +20,7 @@
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/convert.hpp>
+#include <boost/geometry/algorithms/detail/signed_size_type.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/util/range.hpp>
#include <boost/geometry/iterators/ever_circling_iterator.hpp>
diff --git a/boost/geometry/algorithms/detail/overlay/copy_segments.hpp b/boost/geometry/algorithms/detail/overlay/copy_segments.hpp
index fe1a034f8b..c6f540a978 100644
--- a/boost/geometry/algorithms/detail/overlay/copy_segments.hpp
+++ b/boost/geometry/algorithms/detail/overlay/copy_segments.hpp
@@ -2,8 +2,8 @@
// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
-// This file was modified by Oracle on 2014.
-// Modifications copyright (c) 2014 Oracle and/or its affiliates.
+// This file was modified by Oracle on 2014, 2017.
+// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -36,6 +36,7 @@
#include <boost/geometry/algorithms/detail/overlay/append_no_duplicates.hpp>
#include <boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp>
+#include <boost/geometry/algorithms/detail/signed_size_type.hpp>
#include <boost/geometry/util/range.hpp>
@@ -56,12 +57,14 @@ struct copy_segments_ring
<
typename Ring,
typename SegmentIdentifier,
+ typename SideStrategy,
typename RobustPolicy,
typename RangeOut
>
static inline void apply(Ring const& ring,
SegmentIdentifier const& seg_id,
signed_size_type to_index,
+ SideStrategy const& strategy,
RobustPolicy const& robust_policy,
RangeOut& current_output)
{
@@ -108,7 +111,7 @@ struct copy_segments_ring
for (signed_size_type i = 0; i < count; ++i, ++it)
{
- detail::overlay::append_no_dups_or_spikes(current_output, *it, robust_policy);
+ detail::overlay::append_no_dups_or_spikes(current_output, *it, strategy, robust_policy);
}
}
};
@@ -118,20 +121,23 @@ class copy_segments_linestring
{
private:
// remove spikes
- template <typename RangeOut, typename Point, typename RobustPolicy>
+ template <typename RangeOut, typename Point, typename SideStrategy, typename RobustPolicy>
static inline void append_to_output(RangeOut& current_output,
Point const& point,
+ SideStrategy const& strategy,
RobustPolicy const& robust_policy,
boost::true_type const&)
{
detail::overlay::append_no_dups_or_spikes(current_output, point,
+ strategy,
robust_policy);
}
// keep spikes
- template <typename RangeOut, typename Point, typename RobustPolicy>
+ template <typename RangeOut, typename Point, typename SideStrategy, typename RobustPolicy>
static inline void append_to_output(RangeOut& current_output,
Point const& point,
+ SideStrategy const&,
RobustPolicy const&,
boost::false_type const&)
{
@@ -143,12 +149,14 @@ public:
<
typename LineString,
typename SegmentIdentifier,
+ typename SideStrategy,
typename RobustPolicy,
typename RangeOut
>
static inline void apply(LineString const& ls,
SegmentIdentifier const& seg_id,
signed_size_type to_index,
+ SideStrategy const& strategy,
RobustPolicy const& robust_policy,
RangeOut& current_output)
{
@@ -169,7 +177,7 @@ public:
for (signed_size_type i = 0; i < count; ++i, ++it)
{
- append_to_output(current_output, *it, robust_policy,
+ append_to_output(current_output, *it, strategy, robust_policy,
boost::integral_constant<bool, RemoveSpikes>());
}
}
@@ -182,12 +190,14 @@ struct copy_segments_polygon
<
typename Polygon,
typename SegmentIdentifier,
+ typename SideStrategy,
typename RobustPolicy,
typename RangeOut
>
static inline void apply(Polygon const& polygon,
SegmentIdentifier const& seg_id,
signed_size_type to_index,
+ SideStrategy const& strategy,
RobustPolicy const& robust_policy,
RangeOut& current_output)
{
@@ -198,6 +208,7 @@ struct copy_segments_polygon
? geometry::exterior_ring(polygon)
: range::at(geometry::interior_rings(polygon), seg_id.ring_index),
seg_id, to_index,
+ strategy,
robust_policy,
current_output
);
@@ -212,12 +223,14 @@ struct copy_segments_box
<
typename Box,
typename SegmentIdentifier,
+ typename SideStrategy,
typename RobustPolicy,
typename RangeOut
>
static inline void apply(Box const& box,
SegmentIdentifier const& seg_id,
signed_size_type to_index,
+ SideStrategy const& strategy,
RobustPolicy const& robust_policy,
RangeOut& current_output)
{
@@ -238,7 +251,7 @@ struct copy_segments_box
for (signed_size_type i = 0; i < count; i++, index++)
{
detail::overlay::append_no_dups_or_spikes(current_output,
- bp[index % 5], robust_policy);
+ bp[index % 5], strategy, robust_policy);
}
}
@@ -252,12 +265,14 @@ struct copy_segments_multi
<
typename MultiGeometry,
typename SegmentIdentifier,
+ typename SideStrategy,
typename RobustPolicy,
typename RangeOut
>
static inline void apply(MultiGeometry const& multi_geometry,
SegmentIdentifier const& seg_id,
signed_size_type to_index,
+ SideStrategy const& strategy,
RobustPolicy const& robust_policy,
RangeOut& current_output)
{
@@ -271,6 +286,7 @@ struct copy_segments_multi
// Call the single-version
Policy::apply(range::at(multi_geometry, seg_id.multi_index),
seg_id, to_index,
+ strategy,
robust_policy,
current_output);
}
@@ -340,12 +356,14 @@ template
bool Reverse,
typename Geometry,
typename SegmentIdentifier,
+ typename SideStrategy,
typename RobustPolicy,
typename RangeOut
>
inline void copy_segments(Geometry const& geometry,
SegmentIdentifier const& seg_id,
signed_size_type to_index,
+ SideStrategy const& strategy,
RobustPolicy const& robust_policy,
RangeOut& range_out)
{
@@ -355,7 +373,7 @@ inline void copy_segments(Geometry const& geometry,
<
typename tag<Geometry>::type,
Reverse
- >::apply(geometry, seg_id, to_index, robust_policy, range_out);
+ >::apply(geometry, seg_id, to_index, strategy, robust_policy, range_out);
}
diff --git a/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp b/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp
index 5cab2b4cb8..47225328df 100644
--- a/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp
+++ b/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp
@@ -2,6 +2,11 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// This file was modified by Oracle on 2017.
+// Modifications copyright (c) 2017 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
// 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)
@@ -19,20 +24,21 @@
# include <iostream>
# include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
# include <boost/geometry/io/wkt/wkt.hpp>
-# define BOOST_GEOMETRY_DEBUG_IDENTIFIER
+# if ! defined(BOOST_GEOMETRY_DEBUG_IDENTIFIER)
+# define BOOST_GEOMETRY_DEBUG_IDENTIFIER
+ #endif
#endif
#include <boost/range.hpp>
-#include <boost/geometry/iterators/ever_circling_iterator.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/handle_colocations.hpp>
+#include <boost/geometry/algorithms/detail/overlay/handle_self_turns.hpp>
+#include <boost/geometry/algorithms/detail/overlay/is_self_turn.hpp>
#include <boost/geometry/algorithms/detail/overlay/less_by_segment_ratio.hpp>
#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
-#include <boost/geometry/algorithms/detail/overlay/sort_by_side.hpp>
#include <boost/geometry/policies/robustness/robust_type.hpp>
-#include <boost/geometry/strategies/side.hpp>
+
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
# include <boost/geometry/algorithms/detail/overlay/check_enrich.hpp>
#endif
@@ -58,7 +64,7 @@ template
typename Turns,
typename Geometry1, typename Geometry2,
typename RobustPolicy,
- typename Strategy
+ typename SideStrategy
>
inline void enrich_sort(Operations& operations,
Turns const& turns,
@@ -66,7 +72,7 @@ inline void enrich_sort(Operations& operations,
Geometry1 const& geometry1,
Geometry2 const& geometry2,
RobustPolicy const& robust_policy,
- Strategy const& /*strategy*/)
+ SideStrategy const& strategy)
{
std::sort(boost::begin(operations),
boost::end(operations),
@@ -76,8 +82,9 @@ inline void enrich_sort(Operations& operations,
typename boost::range_value<Operations>::type,
Geometry1, Geometry2,
RobustPolicy,
+ SideStrategy,
Reverse1, Reverse2
- >(turns, for_operation, geometry1, geometry2, robust_policy));
+ >(turns, for_operation, geometry1, geometry2, robust_policy, strategy));
}
@@ -145,7 +152,7 @@ inline void enrich_assign(Operations& operations, Turns& turns)
it != boost::end(operations);
++it)
{
- op_type& op = turns[it->turn_index]
+ op_type const& op = turns[it->turn_index]
.operations[it->operation_index];
std::cout << it->turn_index
@@ -171,9 +178,7 @@ inline void enrich_assign(Operations& operations, Turns& turns)
template <typename Turns, typename MappedVector>
-inline void create_map(Turns const& turns,
- detail::overlay::operation_type for_operation,
- MappedVector& mapped_vector)
+inline void create_map(Turns const& turns, MappedVector& mapped_vector)
{
typedef typename boost::range_value<Turns>::type turn_type;
typedef typename turn_type::container_type container_type;
@@ -195,15 +200,6 @@ inline void create_map(Turns const& turns,
continue;
}
- if (for_operation == operation_intersection
- && turn.cluster_id == -1
- && turn.both(operation_union))
- {
- // Only include uu turns if part of cluster (to block potential paths),
- // otherwise they can block possibly viable paths
- continue;
- }
-
std::size_t op_index = 0;
for (typename boost::range_iterator<container_type const>::type
op_it = boost::begin(turn.operations);
@@ -225,6 +221,56 @@ inline void create_map(Turns const& turns,
}
}
+template <typename Point1, typename Point2>
+inline typename geometry::coordinate_type<Point1>::type
+ distance_measure(Point1 const& a, Point2 const& b)
+{
+ // TODO: use comparable distance for point-point instead - but that
+ // causes currently cycling include problems
+ typedef typename geometry::coordinate_type<Point1>::type ctype;
+ ctype const dx = get<0>(a) - get<0>(b);
+ ctype const dy = get<1>(a) - get<1>(b);
+ return dx * dx + dy * dy;
+}
+
+template <typename Turns>
+inline void calculate_remaining_distance(Turns& turns)
+{
+ typedef typename boost::range_value<Turns>::type turn_type;
+ typedef typename turn_type::turn_operation_type op_type;
+
+ for (typename boost::range_iterator<Turns>::type
+ it = boost::begin(turns);
+ it != boost::end(turns);
+ ++it)
+ {
+ turn_type& turn = *it;
+ if (! turn.both(detail::overlay::operation_continue))
+ {
+ continue;
+ }
+
+ op_type& op0 = turn.operations[0];
+ op_type& op1 = turn.operations[1];
+
+ if (op0.remaining_distance != 0
+ || op1.remaining_distance != 0)
+ {
+ continue;
+ }
+
+ int const to_index0 = op0.enriched.get_next_turn_index();
+ int const to_index1 = op1.enriched.get_next_turn_index();
+ if (to_index1 >= 0
+ && to_index1 >= 0
+ && to_index0 != to_index1)
+ {
+ op0.remaining_distance = distance_measure(turn.point, turns[to_index0].point);
+ op1.remaining_distance = distance_measure(turn.point, turns[to_index1].point);
+ }
+ }
+}
+
}} // namespace detail::overlay
#endif //DOXYGEN_NO_DETAIL
@@ -239,7 +285,7 @@ inline void create_map(Turns const& turns,
\tparam Clusters type of cluster container
\tparam Geometry1 \tparam_geometry
\tparam Geometry2 \tparam_geometry
-\tparam Strategy side strategy type
+\tparam SideStrategy side strategy type
\param turns container containing intersection points
\param clusters container containing clusters
\param geometry1 \param_geometry
@@ -255,16 +301,21 @@ template
typename Clusters,
typename Geometry1, typename Geometry2,
typename RobustPolicy,
- typename Strategy
+ typename SideStrategy
>
inline void enrich_intersection_points(Turns& turns,
Clusters& clusters,
Geometry1 const& geometry1, Geometry2 const& geometry2,
RobustPolicy const& robust_policy,
- Strategy const& strategy)
+ SideStrategy const& strategy)
{
- static const detail::overlay::operation_type for_operation
+ static const detail::overlay::operation_type target_operation
= detail::overlay::operation_from_overlay<OverlayType>::value;
+ static const detail::overlay::operation_type opposite_operation
+ = target_operation == detail::overlay::operation_union
+ ? detail::overlay::operation_intersection
+ : detail::overlay::operation_union;
+
typedef typename boost::range_value<Turns>::type turn_type;
typedef typename turn_type::turn_operation_type op_type;
typedef detail::overlay::indexed_turn_operation
@@ -278,27 +329,68 @@ inline void enrich_intersection_points(Turns& turns,
std::vector<indexed_turn_operation>
> mapped_vector_type;
+ bool has_cc = false;
bool const has_colocations
- = detail::overlay::handle_colocations<Reverse1, Reverse2>(turns,
+ = detail::overlay::handle_colocations<Reverse1, Reverse2, OverlayType>(turns,
clusters, geometry1, geometry2);
- // Discard none turns, if any
+ // Discard turns not part of target overlay
for (typename boost::range_iterator<Turns>::type
it = boost::begin(turns);
it != boost::end(turns);
++it)
{
- if (it->both(detail::overlay::operation_none))
+ turn_type& turn = *it;
+
+ if (turn.both(detail::overlay::operation_none))
+ {
+ turn.discarded = true;
+ continue;
+ }
+
+ if (turn.both(opposite_operation))
{
- it->discarded = true;
+ // For intersections, remove uu to avoid the need to travel
+ // a union (during intersection) in uu/cc clusters (e.g. #31,#32,#33)
+ // Also, for union, discard ii
+ turn.discarded = true;
+ turn.cluster_id = -1;
+ continue;
+ }
+
+ if (detail::overlay::is_self_turn<OverlayType>(turn)
+ && turn.cluster_id < 0
+ && ! turn.both(target_operation))
+ {
+ // Only keep self-uu-turns or self-ii-turns
+ turn.discarded = true;
+ turn.cluster_id = -1;
+ continue;
+ }
+
+ if (! turn.discarded
+ && turn.both(detail::overlay::operation_continue))
+ {
+ has_cc = true;
}
}
+ detail::overlay::discard_closed_turns
+ <
+ OverlayType,
+ target_operation
+ >::apply(turns, geometry1, geometry2);
+ detail::overlay::discard_open_turns
+ <
+ OverlayType,
+ target_operation
+ >::apply(turns, geometry1, geometry2);
+
// 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(turns, for_operation, mapped_vector);
+ detail::overlay::create_map(turns, mapped_vector);
// No const-iterator; contents of mapped copy is temporary,
// and changed by enrich
@@ -312,7 +404,7 @@ inline void enrich_intersection_points(Turns& turns,
<< mit->first << std::endl;
#endif
detail::overlay::enrich_sort<Reverse1, Reverse2>(
- mit->second, turns, for_operation,
+ mit->second, turns, target_operation,
geometry1, geometry2,
robust_policy, strategy);
}
@@ -331,8 +423,22 @@ inline void enrich_intersection_points(Turns& turns,
if (has_colocations)
{
- detail::overlay::gather_cluster_properties<Reverse1, Reverse2>(
- clusters, turns, for_operation, geometry1, geometry2);
+ // First gather cluster properties (using even clusters with
+ // discarded turns - for open turns), then clean up clusters
+ detail::overlay::gather_cluster_properties
+ <
+ Reverse1,
+ Reverse2,
+ OverlayType
+ >(clusters, turns, target_operation,
+ geometry1, geometry2, strategy);
+
+ detail::overlay::cleanup_clusters(turns, clusters);
+ }
+
+ if (has_cc)
+ {
+ detail::overlay::calculate_remaining_distance(turns);
}
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
diff --git a/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp b/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp
index 2643415343..fdffd665e4 100644
--- a/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp
+++ b/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp
@@ -37,10 +37,17 @@ struct enrichment_info
, startable(true)
, count_left(0)
, count_right(0)
+ , rank(-1)
, zone(-1)
- , only_turn_on_ring(false)
+ , region_id(-1)
+ , isolated(false)
{}
+ inline signed_size_type get_next_turn_index() const
+ {
+ return next_ip_index == -1 ? travels_to_ip_index : next_ip_index;
+ }
+
// 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
@@ -57,8 +64,10 @@ struct enrichment_info
// Counts if polygons left/right of this operation
std::size_t count_left;
std::size_t count_right;
+ signed_size_type rank; // in cluster
signed_size_type zone; // open zone, in cluster
- bool only_turn_on_ring; // True if it is the only turn on a ring (for clusters)
+ signed_size_type region_id;
+ bool isolated;
};
diff --git a/boost/geometry/algorithms/detail/overlay/follow.hpp b/boost/geometry/algorithms/detail/overlay/follow.hpp
index 22807b5140..589e12cc2b 100644
--- a/boost/geometry/algorithms/detail/overlay/follow.hpp
+++ b/boost/geometry/algorithms/detail/overlay/follow.hpp
@@ -2,10 +2,10 @@
// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
-// This file was modified by Oracle on 2014.
-// Modifications copyright (c) 2014 Oracle and/or its affiliates.
-
+// This file was modified by Oracle on 2014, 2017.
+// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -55,21 +55,14 @@ template
typename Turn,
typename Operation,
typename LineString,
- typename Polygon
+ typename Polygon,
+ typename PtInPolyStrategy
>
static inline bool last_covered_by(Turn const& turn, Operation const& op,
- LineString const& linestring, Polygon const& polygon)
+ LineString const& linestring, Polygon const& polygon,
+ PtInPolyStrategy const& strategy)
{
- // 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, *(::boost::begin(linestring) + op.seg_id.segment_index), turn.point);
-
- return geometry::covered_by(point_in_between, polygon);
+ return geometry::covered_by(range::at(linestring, op.seg_id.segment_index), polygon, strategy);
}
@@ -78,17 +71,19 @@ template
typename Turn,
typename Operation,
typename LineString,
- typename Polygon
+ typename Polygon,
+ typename PtInPolyStrategy
>
static inline bool is_leaving(Turn const& turn, Operation const& op,
bool entered, bool first,
- LineString const& linestring, Polygon const& polygon)
+ LineString const& linestring, Polygon const& polygon,
+ PtInPolyStrategy const& strategy)
{
if (op.operation == operation_union)
{
return entered
|| turn.method == method_crosses
- || (first && last_covered_by(turn, op, linestring, polygon))
+ || (first && last_covered_by(turn, op, linestring, polygon, strategy))
;
}
return false;
@@ -100,11 +95,13 @@ template
typename Turn,
typename Operation,
typename LineString,
- typename Polygon
+ typename Polygon,
+ typename PtInPolyStrategy
>
static inline bool is_staying_inside(Turn const& turn, Operation const& op,
bool entered, bool first,
- LineString const& linestring, Polygon const& polygon)
+ LineString const& linestring, Polygon const& polygon,
+ PtInPolyStrategy const& strategy)
{
if (turn.method == method_crosses)
{
@@ -115,7 +112,7 @@ static inline bool is_staying_inside(Turn const& turn, Operation const& op,
if (is_entering(turn, op))
{
- return entered || (first && last_covered_by(turn, op, linestring, polygon));
+ return entered || (first && last_covered_by(turn, op, linestring, polygon, strategy));
}
return false;
@@ -126,14 +123,16 @@ template
typename Turn,
typename Operation,
typename Linestring,
- typename Polygon
+ typename Polygon,
+ typename PtInPolyStrategy
>
static inline bool was_entered(Turn const& turn, Operation const& op, bool first,
- Linestring const& linestring, Polygon const& polygon)
+ Linestring const& linestring, Polygon const& polygon,
+ PtInPolyStrategy const& strategy)
{
if (first && (turn.method == method_collinear || turn.method == method_equal))
{
- return last_covered_by(turn, op, linestring, polygon);
+ return last_covered_by(turn, op, linestring, polygon, strategy);
}
return false;
}
@@ -158,6 +157,7 @@ struct action_selector<overlay_intersection, RemoveSpikes>
typename LineString,
typename Point,
typename Operation,
+ typename SideStrategy,
typename RobustPolicy
>
static inline void enter(LineStringOut& current_piece,
@@ -165,6 +165,7 @@ struct action_selector<overlay_intersection, RemoveSpikes>
segment_identifier& segment_id,
signed_size_type , Point const& point,
Operation const& operation,
+ SideStrategy const& ,
RobustPolicy const& ,
OutputIterator& )
{
@@ -181,6 +182,7 @@ struct action_selector<overlay_intersection, RemoveSpikes>
typename LineString,
typename Point,
typename Operation,
+ typename SideStrategy,
typename RobustPolicy
>
static inline void leave(LineStringOut& current_piece,
@@ -188,6 +190,7 @@ struct action_selector<overlay_intersection, RemoveSpikes>
segment_identifier& segment_id,
signed_size_type index, Point const& point,
Operation const& ,
+ SideStrategy const& strategy,
RobustPolicy const& robust_policy,
OutputIterator& out)
{
@@ -196,7 +199,7 @@ struct action_selector<overlay_intersection, RemoveSpikes>
detail::copy_segments::copy_segments_linestring
<
false, RemoveSpikes
- >::apply(linestring, segment_id, index, robust_policy, current_piece);
+ >::apply(linestring, segment_id, index, strategy, robust_policy, current_piece);
detail::overlay::append_no_duplicates(current_piece, point);
if (::boost::size(current_piece) > 1)
{
@@ -235,17 +238,9 @@ struct action_selector<overlay_intersection, RemoveSpikes>
return entered;
}
- template
- <
- typename Point,
- typename Geometry,
- typename RobustPolicy
- >
- static inline bool included(Point const& point,
- Geometry const& geometry,
- RobustPolicy const& )
+ static inline bool included(int inside_value)
{
- return geometry::covered_by(point, geometry);
+ return inside_value >= 0; // covered_by
}
};
@@ -263,6 +258,7 @@ struct action_selector<overlay_difference, RemoveSpikes>
typename LineString,
typename Point,
typename Operation,
+ typename SideStrategy,
typename RobustPolicy
>
static inline void enter(LineStringOut& current_piece,
@@ -270,11 +266,12 @@ struct action_selector<overlay_difference, RemoveSpikes>
segment_identifier& segment_id,
signed_size_type index, Point const& point,
Operation const& operation,
+ SideStrategy const& strategy,
RobustPolicy const& robust_policy,
OutputIterator& out)
{
normal_action::leave(current_piece, linestring, segment_id, index,
- point, operation, robust_policy, out);
+ point, operation, strategy, robust_policy, out);
}
template
@@ -284,6 +281,7 @@ struct action_selector<overlay_difference, RemoveSpikes>
typename LineString,
typename Point,
typename Operation,
+ typename SideStrategy,
typename RobustPolicy
>
static inline void leave(LineStringOut& current_piece,
@@ -291,11 +289,12 @@ struct action_selector<overlay_difference, RemoveSpikes>
segment_identifier& segment_id,
signed_size_type index, Point const& point,
Operation const& operation,
+ SideStrategy const& strategy,
RobustPolicy const& robust_policy,
OutputIterator& out)
{
normal_action::enter(current_piece, linestring, segment_id, index,
- point, operation, robust_policy, out);
+ point, operation, strategy, robust_policy, out);
}
template
@@ -319,17 +318,9 @@ struct action_selector<overlay_difference, RemoveSpikes>
return ! normal_action::is_entered(entered);
}
- template
- <
- typename Point,
- typename Geometry,
- typename RobustPolicy
- >
- static inline bool included(Point const& point,
- Geometry const& geometry,
- RobustPolicy const& robust_policy)
+ static inline bool included(int inside_value)
{
- return ! normal_action::included(point, geometry, robust_policy);
+ return ! normal_action::included(inside_value);
}
};
@@ -403,33 +394,27 @@ class follow
public :
- template
- <
- typename Point,
- typename Geometry,
- typename RobustPolicy
- >
- static inline bool included(Point const& point,
- Geometry const& geometry,
- RobustPolicy const& robust_policy)
+ static inline bool included(int inside_value)
{
return following::action_selector
<
OverlayType, RemoveSpikes
- >::included(point, geometry, robust_policy);
+ >::included(inside_value);
}
template
<
typename Turns,
typename OutputIterator,
- typename RobustPolicy
+ typename RobustPolicy,
+ typename Strategy
>
static inline OutputIterator apply(LineString const& linestring, Polygon const& polygon,
detail::overlay::operation_type , // TODO: this parameter might be redundant
Turns& turns,
RobustPolicy const& robust_policy,
- OutputIterator out)
+ OutputIterator out,
+ Strategy const& strategy)
{
typedef typename boost::range_iterator<Turns>::type turn_iterator;
typedef typename boost::range_value<Turns>::type turn_type;
@@ -440,6 +425,12 @@ public :
typedef following::action_selector<OverlayType, RemoveSpikes> action;
+ typename Strategy::template point_in_geometry_strategy
+ <
+ LineString, Polygon
+ >::type const pt_in_poly_strategy
+ = strategy.template get_point_in_geometry_strategy<LineString, Polygon>();
+
// 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>());
@@ -454,13 +445,13 @@ public :
{
turn_operation_iterator_type iit = boost::begin(it->operations);
- if (following::was_entered(*it, *iit, first, linestring, polygon))
+ if (following::was_entered(*it, *iit, first, linestring, polygon, pt_in_poly_strategy))
{
debug_traverse(*it, *iit, "-> Was entered");
entered = true;
}
- if (following::is_staying_inside(*it, *iit, entered, first, linestring, polygon))
+ if (following::is_staying_inside(*it, *iit, entered, first, linestring, polygon, pt_in_poly_strategy))
{
debug_traverse(*it, *iit, "-> Staying inside");
@@ -473,17 +464,17 @@ public :
entered = true;
action::enter(current_piece, linestring, current_segment_id,
iit->seg_id.segment_index, it->point, *iit,
- robust_policy,
+ strategy, robust_policy,
out);
}
- else if (following::is_leaving(*it, *iit, entered, first, linestring, polygon))
+ else if (following::is_leaving(*it, *iit, entered, first, linestring, polygon, pt_in_poly_strategy))
{
debug_traverse(*it, *iit, "-> Leaving");
entered = false;
action::leave(current_piece, linestring, current_segment_id,
iit->seg_id.segment_index, it->point, *iit,
- robust_policy,
+ strategy, robust_policy,
out);
}
first = false;
@@ -497,7 +488,7 @@ public :
>::apply(linestring,
current_segment_id,
static_cast<signed_size_type>(boost::size(linestring) - 1),
- robust_policy,
+ strategy, robust_policy,
current_piece);
}
diff --git a/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp b/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp
index c249ff57ff..2a374bf0b0 100644
--- a/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp
+++ b/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp
@@ -2,12 +2,14 @@
// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
-// Copyright (c) 2014-2015, Oracle and/or its affiliates.
+// Copyright (c) 2014-2017, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
-// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_LINEAR_LINEAR_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_LINEAR_LINEAR_HPP
@@ -183,7 +185,8 @@ protected:
typename TurnIterator,
typename TurnOperationIterator,
typename SegmentIdentifier,
- typename OutputIterator
+ typename OutputIterator,
+ typename SideStrategy
>
static inline OutputIterator
process_turn(TurnIterator it,
@@ -193,7 +196,8 @@ protected:
Linestring const& linestring,
LinestringOut& current_piece,
SegmentIdentifier& current_segment_id,
- OutputIterator oit)
+ OutputIterator oit,
+ SideStrategy const& strategy)
{
// We don't rescale linear/linear
detail::no_rescale_policy robust_policy;
@@ -208,7 +212,7 @@ protected:
action::enter(current_piece, linestring,
current_segment_id,
op_it->seg_id.segment_index,
- it->point, *op_it, robust_policy, oit);
+ it->point, *op_it, strategy, robust_policy, oit);
}
++enter_count;
}
@@ -223,7 +227,7 @@ protected:
action::leave(current_piece, linestring,
current_segment_id,
op_it->seg_id.segment_index,
- it->point, *op_it, robust_policy, oit);
+ it->point, *op_it, strategy, robust_policy, oit);
}
}
else if ( FollowIsolatedPoints
@@ -249,14 +253,16 @@ protected:
template
<
typename SegmentIdentifier,
- typename OutputIterator
+ typename OutputIterator,
+ typename SideStrategy
>
static inline OutputIterator
process_end(bool entered,
Linestring const& linestring,
SegmentIdentifier const& current_segment_id,
LinestringOut& current_piece,
- OutputIterator oit)
+ OutputIterator oit,
+ SideStrategy const& strategy)
{
if ( action::is_entered(entered) )
{
@@ -269,6 +275,7 @@ protected:
>::apply(linestring,
current_segment_id,
static_cast<signed_size_type>(boost::size(linestring) - 1),
+ strategy,
robust_policy,
current_piece);
}
@@ -283,11 +290,12 @@ protected:
}
public:
- template <typename TurnIterator, typename OutputIterator>
+ template <typename TurnIterator, typename OutputIterator, typename SideStrategy>
static inline OutputIterator
apply(Linestring const& linestring, Linear const&,
TurnIterator first, TurnIterator beyond,
- OutputIterator oit)
+ OutputIterator oit,
+ SideStrategy const& strategy)
{
// Iterate through all intersection points (they are
// ordered along the each line)
@@ -304,7 +312,8 @@ public:
entered, enter_count,
linestring,
current_piece, current_segment_id,
- oit);
+ oit,
+ strategy);
}
#if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW)
@@ -318,7 +327,8 @@ public:
return process_end(entered, linestring,
current_segment_id, current_piece,
- oit);
+ oit,
+ strategy);
}
};
@@ -413,11 +423,12 @@ protected:
};
public:
- template <typename TurnIterator, typename OutputIterator>
+ template <typename TurnIterator, typename OutputIterator, typename SideStrategy>
static inline OutputIterator
apply(MultiLinestring const& multilinestring, Linear const& linear,
TurnIterator first, TurnIterator beyond,
- OutputIterator oit)
+ OutputIterator oit,
+ SideStrategy const& strategy)
{
BOOST_GEOMETRY_ASSERT( first != beyond );
@@ -447,7 +458,7 @@ public:
has_other_multi_id(current_multi_id));
oit = Base::apply(*(ls_first + current_multi_id),
- linear, per_ls_current, per_ls_next, oit);
+ linear, per_ls_current, per_ls_next, oit, strategy);
signed_size_type next_multi_id = -1;
linestring_iterator ls_next = ls_beyond;
diff --git a/boost/geometry/algorithms/detail/overlay/get_relative_order.hpp b/boost/geometry/algorithms/detail/overlay/get_relative_order.hpp
index ea9aa29f19..2eec6af665 100644
--- a/boost/geometry/algorithms/detail/overlay/get_relative_order.hpp
+++ b/boost/geometry/algorithms/detail/overlay/get_relative_order.hpp
@@ -2,6 +2,11 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// This file was modified by Oracle on 2017.
+// Modifications copyright (c) 2017 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
// 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)
@@ -31,20 +36,15 @@ namespace detail { namespace overlay
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 typename strategy::side::services::default_strategy
- <
- typename cs_tag<Point1>::type
- >::type strategy;
-
- template <typename Point>
+ template <typename Point, typename SideStrategy>
static inline int value_via_product(Point const& ti, Point const& tj,
- Point const& ui, Point const& uj, int factor)
+ Point const& ui, Point const& uj, int factor,
+ SideStrategy const& strategy)
{
- int const side_ti_u = strategy::apply(ti, tj, ui);
- int const side_tj_u = strategy::apply(ti, tj, uj);
+ 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 ")
@@ -57,13 +57,15 @@ struct get_relative_order
}
+ template <typename Point1, typename SideStrategy>
static inline int apply(
Point1 const& pi, Point1 const& pj,
Point1 const& ri, Point1 const& rj,
- Point1 const& si, Point1 const& sj)
+ Point1 const& si, Point1 const& sj,
+ SideStrategy const& strategy)
{
- int const side_ri_p = strategy::apply(pi, pj, ri);
- int const side_si_p = strategy::apply(pi, pj, si);
+ 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);
@@ -72,10 +74,10 @@ struct get_relative_order
std::cout << " s//p: " << side_si_p << " / " << side_sj_p;
#endif
- int value = value_via_product(si, sj, ri, rj, 1);
+ int value = value_via_product(si, sj, ri, rj, 1, strategy);
if (value == 0)
{
- value = value_via_product(ri, rj, si, sj, -1);
+ value = value_via_product(ri, rj, si, sj, -1, strategy);
}
int const order = side_ri_p * side_ri_p * side_si_p * value;
diff --git a/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp
index 08bc342186..895952c8fc 100644
--- a/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp
+++ b/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp
@@ -190,6 +190,7 @@ struct touch_interior : public base_turn_handler
// Q turns left on the right side of P (test "MR3")
// Both directions for "intersection"
both(ti, operation_intersection);
+ ti.touch_only = true;
}
else if (side_qi_p == 1 && side_qk_p == 1 && side_qk_q == -1)
{
@@ -197,6 +198,7 @@ struct touch_interior : public base_turn_handler
// Union: take both operation
// Intersection: skip
both(ti, operation_union);
+ ti.touch_only = true;
}
else if (side_qi_p == side_qk_p && side_qi_p == side_qk_q)
{
@@ -207,6 +209,7 @@ struct touch_interior : public base_turn_handler
unsigned int index = side_qk_q == 1 ? index_q : index_p;
ti.operations[index].operation = operation_union;
ti.operations[1 - index].operation = operation_intersection;
+ ti.touch_only = true;
}
else if (side_qk_p == 0)
{
@@ -346,6 +349,7 @@ struct touch : public base_turn_handler
if (side_pk_q2 == -side_qk_q)
{
ui_else_iu(! q_turns_left, ti);
+ ti.touch_only = true;
return;
}
@@ -358,6 +362,10 @@ struct touch : public base_turn_handler
{
ti.operations[1].operation = operation_blocked;
}
+ else
+ {
+ ti.touch_only = true;
+ }
//block_second(block_q, ti);
return;
}
@@ -373,6 +381,10 @@ struct touch : public base_turn_handler
: side_qi_p1 == 1 || side_qk_p1 == 1
? operation_union
: operation_intersection;
+ if (! block_q)
+ {
+ ti.touch_only = true;
+ }
return;
}
@@ -400,6 +412,7 @@ struct touch : public base_turn_handler
if (side_pk_q1 == side_qk_p1)
{
uu_else_ii(right_to_left, ti);
+ ti.touch_only = true;
return;
}
}
@@ -418,6 +431,7 @@ struct touch : public base_turn_handler
if (side_pk_q2 == side_qk_p1)
{
ui_else_iu(right_to_left, ti);
+ ti.touch_only = true;
return;
}
}
diff --git a/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp b/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp
index 5f2cb07faf..f8247cd240 100644
--- a/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp
+++ b/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp
@@ -66,7 +66,7 @@ struct side_calculator
Qj const& m_qj;
Qk const& m_qk;
- SideStrategy const& m_side_strategy;
+ SideStrategy m_side_strategy;
};
template <typename Point1, typename Point2, typename RobustPolicy>
diff --git a/boost/geometry/algorithms/detail/overlay/get_turns.hpp b/boost/geometry/algorithms/detail/overlay/get_turns.hpp
index 4e97a84a37..f88dfe8422 100644
--- a/boost/geometry/algorithms/detail/overlay/get_turns.hpp
+++ b/boost/geometry/algorithms/detail/overlay/get_turns.hpp
@@ -1,7 +1,7 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
-// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
+// Copyright (c) 2014-2017 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2014, 2016, 2017.
// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates.
@@ -90,6 +90,9 @@ struct no_interrupt_policy
{
static bool const enabled = false;
+ // variable required by self_get_turn_points::get_turns
+ static bool const has_intersections = false;
+
template <typename Range>
static inline bool apply(Range const&)
{
@@ -230,7 +233,7 @@ public :
// section 2: [--------------]
// section 1: |----|---|---|---|---|
for (prev1 = it1++, next1++;
- it1 != end1 && ! detail::section::exceeding<0>(dir1, *prev1, sec2.bounding_box, robust_policy);
+ it1 != end1 && ! detail::section::exceeding<0>(dir1, *prev1, sec1.bounding_box, sec2.bounding_box, robust_policy);
++prev1, ++it1, ++index1, ++next1, ++ndi1)
{
ever_circling_iterator<range1_iterator> nd_next1(
@@ -248,7 +251,7 @@ public :
next2++;
for (prev2 = it2++, next2++;
- it2 != end2 && ! detail::section::exceeding<0>(dir2, *prev2, sec1.bounding_box, robust_policy);
+ it2 != end2 && ! detail::section::exceeding<0>(dir2, *prev2, sec2.bounding_box, sec1.bounding_box, robust_policy);
++prev2, ++it2, ++index2, ++next2, ++ndi2)
{
bool skip = same_source;
@@ -356,7 +359,7 @@ private :
// 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, typename RobustPolicy>
- static inline void get_start_point_iterator(Section & section,
+ static inline void get_start_point_iterator(Section const& section,
Range const& range,
typename boost::range_iterator<Range const>::type& it,
typename boost::range_iterator<Range const>::type& prev,
@@ -370,7 +373,7 @@ private :
// Mimic section-iterator:
// Skip to point such that section interects other box
prev = it++;
- for(; it != end && detail::section::preceding<0>(dir, *it, other_bounding_box, robust_policy);
+ for(; it != end && detail::section::preceding<0>(dir, *it, section.bounding_box, other_bounding_box, robust_policy);
prev = it++, index++, ndi++)
{}
// Go back one step because we want to start completely preceding
@@ -418,6 +421,7 @@ struct section_visitor
{
if (! detail::disjoint::disjoint_box_box(sec1.bounding_box, sec2.bounding_box))
{
+ // false if interrupted
return get_turns_in_sections
<
Geometry1,
@@ -425,13 +429,12 @@ struct section_visitor
Reverse1, Reverse2,
Section, Section,
TurnPolicy
- >::apply(
- m_source_id1, m_geometry1, sec1,
- m_source_id2, m_geometry2, sec2,
- false,
- m_intersection_strategy,
- m_rescale_policy,
- m_turns, m_interrupt_policy);
+ >::apply(m_source_id1, m_geometry1, sec1,
+ m_source_id2, m_geometry2, sec2,
+ false,
+ m_intersection_strategy,
+ m_rescale_policy,
+ m_turns, m_interrupt_policy);
}
return true;
}
@@ -473,10 +476,13 @@ public:
sections_type sec1, sec2;
typedef boost::mpl::vector_c<std::size_t, 0, 1> dimensions;
+ typename IntersectionStrategy::envelope_strategy_type const
+ envelope_strategy = intersection_strategy.get_envelope_strategy();
+
geometry::sectionalize<Reverse1, dimensions>(geometry1, robust_policy,
- sec1, 0);
+ sec1, envelope_strategy, 0);
geometry::sectionalize<Reverse2, dimensions>(geometry2, robust_policy,
- sec2, 1);
+ sec2, envelope_strategy, 1);
// ... and then partition them, intersecting overlapping sections in visitor method
section_visitor
diff --git a/boost/geometry/algorithms/detail/overlay/handle_colocations.hpp b/boost/geometry/algorithms/detail/overlay/handle_colocations.hpp
index 400ed3b881..f3311b34e9 100644
--- a/boost/geometry/algorithms/detail/overlay/handle_colocations.hpp
+++ b/boost/geometry/algorithms/detail/overlay/handle_colocations.hpp
@@ -2,6 +2,11 @@
// Copyright (c) 2015 Barend Gehrels, Amsterdam, the Netherlands.
+// This file was modified by Oracle on 2017.
+// Modifications copyright (c) 2017 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
// 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)
@@ -262,15 +267,6 @@ inline void handle_colocation_cluster(Turns& turns,
add_cluster_id(other_op, cluster_per_segment, ref_id);
id = ref_id;
}
-
- // In case of colocated xx turns, all other turns may NOT be
- // followed at all. xx cannot be discarded (otherwise colocated
- // turns are followed).
- if (ref_turn.both(operation_blocked))
- {
- turn.discarded = true;
- // We can either set or not set colocated because it is not effective on blocked turns
- }
}
else
{
@@ -331,11 +327,7 @@ inline void assign_cluster_to_turns(Turns& turns,
}
}
-template
-<
- typename Turns,
- typename Clusters
->
+template <typename Turns, typename Clusters>
inline void remove_clusters(Turns& turns, Clusters& clusters)
{
typename Clusters::iterator it = clusters.begin();
@@ -350,17 +342,44 @@ inline void remove_clusters(Turns& turns, Clusters& clusters)
= current_it->second.turn_indices;
if (turn_indices.size() == 1)
{
- signed_size_type turn_index = *turn_indices.begin();
+ signed_size_type const turn_index = *turn_indices.begin();
turns[turn_index].cluster_id = -1;
clusters.erase(current_it);
}
}
}
+template <typename Turns, typename Clusters>
+inline void cleanup_clusters(Turns& turns, Clusters& clusters)
+{
+ // Removes discarded turns from clusters
+ for (typename Clusters::iterator mit = clusters.begin();
+ mit != clusters.end(); ++mit)
+ {
+ cluster_info& cinfo = mit->second;
+ std::set<signed_size_type>& ids = cinfo.turn_indices;
+ for (std::set<signed_size_type>::iterator sit = ids.begin();
+ sit != ids.end(); /* no increment */)
+ {
+ std::set<signed_size_type>::iterator current_it = sit;
+ ++sit;
+
+ signed_size_type const turn_index = *current_it;
+ if (turns[turn_index].discarded)
+ {
+ ids.erase(current_it);
+ }
+ }
+ }
+
+ remove_clusters(turns, clusters);
+}
+
template <typename Turn, typename IdSet>
inline void discard_ie_turn(Turn& turn, IdSet& ids, signed_size_type id)
{
turn.discarded = true;
+ // Set cluster id to -1, but don't clear colocated flags
turn.cluster_id = -1;
// To remove it later from clusters
ids.insert(id);
@@ -378,6 +397,13 @@ inline bool is_ie_turn(segment_identifier const& ext_seg_0,
segment_identifier const& int_seg_0,
segment_identifier const& other_seg_1)
{
+ if (ext_seg_0.source_index == ext_seg_1.source_index)
+ {
+ // External turn is a self-turn, dont discard internal turn for this
+ return false;
+ }
+
+
// Compares two segment identifiers from two turns (external / one internal)
// From first turn [0], both are from same polygon (multi_index),
@@ -411,6 +437,7 @@ inline bool is_ie_turn(segment_identifier const& ext_seg_0,
template
<
bool Reverse0, bool Reverse1, // Reverse interpretation interior/exterior
+ overlay_type OverlayType,
typename Turns,
typename Clusters
>
@@ -435,19 +462,6 @@ inline void discard_interior_exterior_turns(Turns& turns, Clusters& clusters)
segment_identifier const& seg_0 = turn.operations[0].seg_id;
segment_identifier const& seg_1 = turn.operations[1].seg_id;
- if (turn.both(operation_intersection)
- && Reverse0 == Reverse1)
- {
- if ( is_interior<Reverse0>(seg_0)
- && is_interior<Reverse1>(seg_1))
- {
- // ii touch with, two interior rings
- discard_ie_turn(turn, ids_to_remove, *it);
- }
-
- continue;
- }
-
if (! (turn.both(operation_union)
|| turn.combination(operation_union, operation_blocked)))
{
@@ -487,6 +501,53 @@ inline void discard_interior_exterior_turns(Turns& turns, Clusters& clusters)
}
}
+template
+<
+ typename Turns,
+ typename Clusters
+>
+inline void set_colocation(Turns& turns, Clusters const& clusters)
+{
+ typedef std::set<signed_size_type>::const_iterator set_iterator;
+ typedef typename boost::range_value<Turns>::type turn_type;
+
+ for (typename Clusters::const_iterator cit = clusters.begin();
+ cit != clusters.end(); ++cit)
+ {
+ cluster_info const& cinfo = cit->second;
+ std::set<signed_size_type> const& ids = cinfo.turn_indices;
+
+ bool has_ii = false;
+ bool has_uu = false;
+ for (set_iterator it = ids.begin(); it != ids.end(); ++it)
+ {
+ turn_type const& turn = turns[*it];
+ if (turn.both(operation_intersection))
+ {
+ has_ii = true;
+ }
+ if (turn.both(operation_union) || turn.combination(operation_union, operation_blocked))
+ {
+ has_uu = true;
+ }
+ }
+ if (has_ii || has_uu)
+ {
+ for (set_iterator it = ids.begin(); it != ids.end(); ++it)
+ {
+ turn_type& turn = turns[*it];
+ if (has_ii)
+ {
+ turn.colocated_ii = true;
+ }
+ if (has_uu)
+ {
+ turn.colocated_uu = true;
+ }
+ }
+ }
+ }
+}
// Checks colocated turns and flags combinations of uu/other, possibly a
// combination of a ring touching another geometry's interior ring which is
@@ -498,6 +559,7 @@ inline void discard_interior_exterior_turns(Turns& turns, Clusters& clusters)
template
<
bool Reverse1, bool Reverse2,
+ overlay_type OverlayType,
typename Turns,
typename Clusters,
typename Geometry1,
@@ -578,12 +640,13 @@ inline bool handle_colocations(Turns& turns, Clusters& clusters,
}
assign_cluster_to_turns(turns, clusters, cluster_per_segment);
+ set_colocation(turns, clusters);
discard_interior_exterior_turns
<
do_reverse<geometry::point_order<Geometry1>::value>::value != Reverse1,
- do_reverse<geometry::point_order<Geometry2>::value>::value != Reverse2
+ do_reverse<geometry::point_order<Geometry2>::value>::value != Reverse2,
+ OverlayType
>(turns, clusters);
- remove_clusters(turns, clusters);
#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_COLOCATIONS)
std::cout << "*** Colocations " << map.size() << std::endl;
@@ -598,7 +661,8 @@ inline bool handle_colocations(Turns& turns, Clusters& clusters,
std::cout << geometry::wkt(turns[toi.turn_index].point)
<< std::boolalpha
<< " discarded=" << turns[toi.turn_index].discarded
- << " colocated=" << turns[toi.turn_index].colocated
+ << " colocated(uu)=" << turns[toi.turn_index].colocated_uu
+ << " colocated(ii)=" << turns[toi.turn_index].colocated_ii
<< " " << operation_char(turns[toi.turn_index].operations[0].operation)
<< " " << turns[toi.turn_index].operations[0].seg_id
<< " " << turns[toi.turn_index].operations[0].fraction
@@ -634,14 +698,17 @@ struct is_turn_index
template
<
bool Reverse1, bool Reverse2,
+ overlay_type OverlayType,
typename Turns,
typename Clusters,
typename Geometry1,
- typename Geometry2
+ typename Geometry2,
+ typename SideStrategy
>
inline void gather_cluster_properties(Clusters& clusters, Turns& turns,
operation_type for_operation,
- Geometry1 const& geometry1, Geometry2 const& geometry2)
+ Geometry1 const& geometry1, Geometry2 const& geometry2,
+ SideStrategy const& strategy)
{
typedef typename boost::range_value<Turns>::type turn_type;
typedef typename turn_type::point_type point_type;
@@ -651,7 +718,7 @@ inline void gather_cluster_properties(Clusters& clusters, Turns& turns,
// right side
typedef sort_by_side::side_sorter
<
- Reverse1, Reverse2, point_type, std::less<int>
+ Reverse1, Reverse2, OverlayType, point_type, SideStrategy, std::less<int>
> sbs_type;
for (typename Clusters::iterator mit = clusters.begin();
@@ -664,11 +731,11 @@ inline void gather_cluster_properties(Clusters& clusters, Turns& turns,
continue;
}
- sbs_type sbs;
+ sbs_type sbs(strategy);
point_type turn_point; // should be all the same for all turns in cluster
bool first = true;
- for (typename std::set<signed_size_type>::const_iterator sit = ids.begin();
+ for (std::set<signed_size_type>::const_iterator sit = ids.begin();
sit != ids.end(); ++sit)
{
signed_size_type turn_index = *sit;
@@ -689,6 +756,8 @@ inline void gather_cluster_properties(Clusters& clusters, Turns& turns,
sbs.find_open();
sbs.assign_zones(for_operation);
+ cinfo.open_count = sbs.open_count(for_operation);
+
// Unset the startable flag for all 'closed' zones
for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++)
{
@@ -696,6 +765,11 @@ inline void gather_cluster_properties(Clusters& clusters, Turns& turns,
turn_type& turn = turns[ranked.turn_index];
turn_operation_type& op = turn.operations[ranked.operation_index];
+ if (for_operation == operation_union && cinfo.open_count == 0)
+ {
+ op.enriched.startable = false;
+ }
+
if (ranked.direction != sort_by_side::dir_to)
{
continue;
@@ -703,6 +777,7 @@ inline void gather_cluster_properties(Clusters& clusters, Turns& turns,
op.enriched.count_left = ranked.count_left;
op.enriched.count_right = ranked.count_right;
+ op.enriched.rank = ranked.rank;
op.enriched.zone = ranked.zone;
if ((for_operation == operation_union
@@ -714,7 +789,6 @@ inline void gather_cluster_properties(Clusters& clusters, Turns& turns,
}
}
- cinfo.open_count = sbs.open_count(for_operation);
}
}
diff --git a/boost/geometry/algorithms/detail/overlay/handle_self_turns.hpp b/boost/geometry/algorithms/detail/overlay/handle_self_turns.hpp
new file mode 100644
index 0000000000..39c55db759
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/handle_self_turns.hpp
@@ -0,0 +1,143 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2017 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_SELF_TURNS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_HANDLE_SELF_TURNS_HPP
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/algorithms/detail/overlay/is_self_turn.hpp>
+#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
+#include <boost/geometry/algorithms/within.hpp>
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+struct discard_turns
+{
+ template <typename Turns, typename Geometry0, typename Geometry1>
+ static inline
+ void apply(Turns& , Geometry0 const& , Geometry1 const& )
+ {}
+};
+
+template <overlay_type OverlayType, operation_type OperationType>
+struct discard_closed_turns : discard_turns {};
+
+// It is only implemented for operation_union, not in buffer
+template <>
+struct discard_closed_turns<overlay_union, operation_union>
+{
+
+ template <typename Turns, typename Geometry0, typename Geometry1>
+ static inline
+ void apply(Turns& turns,
+ Geometry0 const& geometry0, Geometry1 const& geometry1)
+ {
+ typedef typename boost::range_value<Turns>::type turn_type;
+
+ for (typename boost::range_iterator<Turns>::type
+ it = boost::begin(turns);
+ it != boost::end(turns);
+ ++it)
+ {
+ turn_type& turn = *it;
+
+ if (turn.cluster_id >= 0
+ || turn.discarded
+ || ! is_self_turn<overlay_union>(turn))
+ {
+ continue;
+ }
+
+ bool const within =
+ turn.operations[0].seg_id.source_index == 0
+ ? geometry::within(turn.point, geometry1)
+ : geometry::within(turn.point, geometry0);
+
+ if (within)
+ {
+ // It is in the interior of the other geometry
+ turn.discarded = true;
+ }
+ }
+ }
+};
+
+struct discard_self_intersection_turns
+{
+ template <typename Turns, typename Geometry0, typename Geometry1>
+ static inline
+ void apply(Turns& turns,
+ Geometry0 const& geometry0, Geometry1 const& geometry1)
+ {
+ typedef typename boost::range_value<Turns>::type turn_type;
+
+ for (typename boost::range_iterator<Turns>::type
+ it = boost::begin(turns);
+ it != boost::end(turns);
+ ++it)
+ {
+ turn_type& turn = *it;
+
+ if (turn.cluster_id >= 0
+ || turn.discarded
+ || ! is_self_turn<overlay_intersection>(turn))
+ {
+ continue;
+ }
+
+ segment_identifier const& id0 = turn.operations[0].seg_id;
+ segment_identifier const& id1 = turn.operations[1].seg_id;
+ if (id0.multi_index != id1.multi_index
+ || (id0.ring_index == -1 && id1.ring_index == -1)
+ || (id0.ring_index >= 0 && id1.ring_index >= 0))
+ {
+ // Not an ii ring (int/ext) on same ring
+ continue;
+ }
+
+ // It is a non co-located ii self-turn
+ // Check if it is within the other geometry
+ // If not, it can be ignored
+
+ bool const within =
+ turn.operations[0].seg_id.source_index == 0
+ ? geometry::within(turn.point, geometry1)
+ : geometry::within(turn.point, geometry0);
+
+ if (! within)
+ {
+ // It is not within another geometry, discard the turn
+ turn.discarded = true;
+ }
+ }
+ }
+};
+
+template <overlay_type OverlayType, operation_type OperationType>
+struct discard_open_turns : discard_turns {};
+
+// Handler it for intersection
+template <>
+struct discard_open_turns<overlay_intersection, operation_intersection>
+ : discard_self_intersection_turns {};
+
+// For difference, it should be done in a different way (TODO)
+
+}} // namespace detail::overlay
+#endif //DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_HANDLE_SELF_TURNS_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp b/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp
index 3244480f48..7106e7b480 100644
--- a/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp
+++ b/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp
@@ -30,10 +30,11 @@
#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/follow.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/algorithms/detail/overlay/range_in_geometry.hpp>
#include <boost/geometry/policies/robustness/robust_point_type.hpp>
#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
@@ -288,6 +289,27 @@ struct intersection_of_linestring_with_areal
>::apply(boost::begin(turns), boost::end(turns));
}
+ template <typename Turns>
+ static inline int inside_or_outside_turn(Turns const& turns)
+ {
+ using namespace overlay;
+ for (typename Turns::const_iterator it = turns.begin();
+ it != turns.end(); ++it)
+ {
+ operation_type op0 = it->operations[0].operation;
+ operation_type op1 = it->operations[1].operation;
+ if (op0 == operation_intersection && op1 == operation_intersection)
+ {
+ return 1; // inside
+ }
+ else if (op0 == operation_union && op1 == operation_union)
+ {
+ return -1; // outside
+ }
+ }
+ return 0;
+ }
+
template
<
typename LineString, typename Areal,
@@ -331,19 +353,21 @@ struct intersection_of_linestring_with_areal
if (no_crossing_turns_or_empty(turns))
{
- // No intersection points, it is either completely
+ // No intersection points, it is either
// inside (interior + borders)
- // or completely outside
+ // or outside (exterior + borders)
- // 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))
+ // analyse the turns
+ int inside_value = inside_or_outside_turn(turns);
+ if (inside_value == 0)
{
- return out;
+ // if needed analyse points of a linestring
+ // NOTE: range_in_geometry checks points of a linestring
+ // until a point inside/outside areal is found
+ inside_value = overlay::range_in_geometry(linestring, areal, strategy);
}
-
- if (follower::included(border_point, areal, robust_policy))
+ // add point to the output if conditions are met
+ if (inside_value != 0 && follower::included(inside_value))
{
LineStringOut copy;
geometry::convert(linestring, copy);
@@ -365,7 +389,7 @@ struct intersection_of_linestring_with_areal
(
linestring, areal,
geometry::detail::overlay::operation_intersection,
- turns, robust_policy, out
+ turns, robust_policy, out, strategy
);
}
};
diff --git a/boost/geometry/algorithms/detail/overlay/is_self_turn.hpp b/boost/geometry/algorithms/detail/overlay/is_self_turn.hpp
new file mode 100644
index 0000000000..9cb7a0fca9
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/is_self_turn.hpp
@@ -0,0 +1,68 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2017-2017 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_IS_SELF_TURN_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_IS_SELF_TURN_HPP
+
+#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+template <overlay_type OverlayType>
+struct is_self_turn_check
+{
+ template <typename Turn>
+ static inline bool apply(Turn const& turn)
+ {
+ return turn.operations[0].seg_id.source_index
+ == turn.operations[1].seg_id.source_index;
+ }
+};
+
+template <>
+struct is_self_turn_check<overlay_buffer>
+{
+ template <typename Turn>
+ static inline bool apply(Turn const& turn)
+ {
+ return false;
+ }
+};
+
+template <>
+struct is_self_turn_check<overlay_dissolve>
+{
+ template <typename Turn>
+ static inline bool apply(Turn const& turn)
+ {
+ return false;
+ }
+};
+
+
+template <overlay_type OverlayType, typename Turn>
+bool is_self_turn(Turn const& turn)
+{
+ return is_self_turn_check<OverlayType>::apply(turn);
+}
+
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_IS_SELF_TURN_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/less_by_segment_ratio.hpp b/boost/geometry/algorithms/detail/overlay/less_by_segment_ratio.hpp
index 21868a2939..dd30635ee2 100644
--- a/boost/geometry/algorithms/detail/overlay/less_by_segment_ratio.hpp
+++ b/boost/geometry/algorithms/detail/overlay/less_by_segment_ratio.hpp
@@ -2,6 +2,11 @@
// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
+// This file was modified by Oracle on 2017.
+// Modifications copyright (c) 2017 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
// 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)
@@ -60,6 +65,7 @@ template
typename Indexed,
typename Geometry1, typename Geometry2,
typename RobustPolicy,
+ typename SideStrategy,
bool Reverse1, bool Reverse2
>
struct less_by_segment_ratio
@@ -68,12 +74,14 @@ struct less_by_segment_ratio
, operation_type for_operation
, Geometry1 const& geometry1
, Geometry2 const& geometry2
- , RobustPolicy const& robust_policy)
+ , RobustPolicy const& robust_policy
+ , SideStrategy const& strategy)
: m_turns(turns)
, m_for_operation(for_operation)
, m_geometry1(geometry1)
, m_geometry2(geometry2)
, m_robust_policy(robust_policy)
+ , m_strategy(strategy)
{
}
@@ -84,6 +92,7 @@ private :
Geometry1 const& m_geometry1;
Geometry2 const& m_geometry2;
RobustPolicy const& m_robust_policy;
+ SideStrategy const& m_strategy;
typedef typename geometry::point_type<Geometry1>::type point_type;
@@ -108,13 +117,8 @@ private :
*right.other_seg_id,
si, sj);
- typedef typename strategy::side::services::default_strategy
- <
- typename cs_tag<point_type>::type
- >::type strategy;
-
- int const side_rj_p = strategy::apply(pi, pj, rj);
- int const side_sj_p = strategy::apply(pi, pj, sj);
+ int const side_rj_p = m_strategy.apply(pi, pj, rj);
+ int const side_sj_p = m_strategy.apply(pi, pj, sj);
// Put the one turning left (1; right == -1) as last
if (side_rj_p != side_sj_p)
@@ -122,8 +126,8 @@ private :
return side_rj_p < side_sj_p;
}
- int const side_sj_r = strategy::apply(ri, rj, sj);
- int const side_rj_s = strategy::apply(si, sj, rj);
+ int const side_sj_r = m_strategy.apply(ri, rj, sj);
+ int const side_rj_s = m_strategy.apply(si, sj, rj);
// If they both turn left: the most left as last
// If they both turn right: this is not relevant, but take also here most left
diff --git a/boost/geometry/algorithms/detail/overlay/linear_linear.hpp b/boost/geometry/algorithms/detail/overlay/linear_linear.hpp
index a74bb33ba1..21d079d95c 100644
--- a/boost/geometry/algorithms/detail/overlay/linear_linear.hpp
+++ b/boost/geometry/algorithms/detail/overlay/linear_linear.hpp
@@ -194,13 +194,15 @@ protected:
typename Turns,
typename LinearGeometry1,
typename LinearGeometry2,
- typename OutputIterator
+ typename OutputIterator,
+ typename IntersectionStrategy
>
static inline OutputIterator
sort_and_follow_turns(Turns& turns,
LinearGeometry1 const& linear1,
LinearGeometry2 const& linear2,
- OutputIterator oit)
+ OutputIterator oit,
+ IntersectionStrategy const& strategy)
{
// remove turns that have no added value
turns::filter_continue_turns
@@ -228,7 +230,7 @@ protected:
FollowIsolatedPoints,
!EnableFilterContinueTurns || OverlayType == overlay_intersection
>::apply(linear1, linear2, boost::begin(turns), boost::end(turns),
- oit);
+ oit, strategy.get_side_strategy());
}
public:
@@ -277,7 +279,7 @@ public:
OverlayType,
EnableFollowIsolatedPoints
&& OverlayType == overlay_intersection
- >(turns, linear1, linear2, oit);
+ >(turns, linear1, linear2, oit, strategy);
}
};
diff --git a/boost/geometry/algorithms/detail/overlay/overlay.hpp b/boost/geometry/algorithms/detail/overlay/overlay.hpp
index f1af2f1949..10829abd4f 100644
--- a/boost/geometry/algorithms/detail/overlay/overlay.hpp
+++ b/boost/geometry/algorithms/detail/overlay/overlay.hpp
@@ -28,9 +28,11 @@
#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/is_self_turn.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/self_turn_points.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
#include <boost/geometry/algorithms/detail/recalculate.hpp>
@@ -87,29 +89,58 @@ struct overlay_null_visitor
{}
};
-template <typename Turns, typename TurnInfoMap>
-inline void get_ring_turn_info(TurnInfoMap& turn_info_map, Turns const& turns)
+template
+<
+ overlay_type OverlayType,
+ typename TurnInfoMap,
+ typename Turns,
+ typename Clusters
+>
+inline void get_ring_turn_info(TurnInfoMap& turn_info_map, Turns const& turns, Clusters const& clusters)
{
typedef typename boost::range_value<Turns>::type turn_type;
typedef typename turn_type::container_type container_type;
+ static const operation_type target_operation
+ = operation_from_overlay<OverlayType>::value;
+ static const operation_type opposite_operation
+ = target_operation == operation_union ? operation_intersection : operation_union;
+
+ signed_size_type turn_index = 0;
for (typename boost::range_iterator<Turns const>::type
it = boost::begin(turns);
it != boost::end(turns);
- ++it)
+ ++it, turn_index++)
{
- typename boost::range_value<Turns>::type const& turn_info = *it;
-
- if (turn_info.discarded
- && ! turn_info.any_blocked()
- && ! turn_info.colocated)
+ typename boost::range_value<Turns>::type const& turn = *it;
+
+ bool const colocated_target = target_operation == operation_union
+ ? turn.colocated_uu : turn.colocated_ii;
+ bool const colocated_opp = target_operation == operation_union
+ ? turn.colocated_ii : turn.colocated_uu;
+ bool const both_opposite = turn.both(opposite_operation);
+
+ bool const traversed
+ = turn.operations[0].visited.finalized()
+ || turn.operations[0].visited.rejected()
+ || turn.operations[1].visited.finalized()
+ || turn.operations[1].visited.rejected()
+ || turn.both(operation_blocked)
+ || turn.combination(opposite_operation, operation_blocked);
+
+ bool is_closed = false;
+ if (turn.cluster_id >= 0 && target_operation == operation_union)
{
- continue;
+ typename Clusters::const_iterator mit = clusters.find(turn.cluster_id);
+ BOOST_ASSERT(mit != clusters.end());
+
+ cluster_info const& cinfo = mit->second;
+ is_closed = cinfo.open_count == 0;
}
for (typename boost::range_iterator<container_type const>::type
- op_it = boost::begin(turn_info.operations);
- op_it != boost::end(turn_info.operations);
+ op_it = boost::begin(turn.operations);
+ op_it != boost::end(turn.operations);
++op_it)
{
ring_identifier const ring_id
@@ -118,7 +149,34 @@ inline void get_ring_turn_info(TurnInfoMap& turn_info_map, Turns const& turns)
op_it->seg_id.multi_index,
op_it->seg_id.ring_index
);
- turn_info_map[ring_id].has_normal_turn = true;
+
+ if (traversed || is_closed || ! op_it->enriched.startable)
+ {
+ turn_info_map[ring_id].has_traversed_turn = true;
+ }
+ else if (both_opposite && colocated_target)
+ {
+ // For union: ii, colocated with a uu
+ // For example, two interior rings touch where two exterior rings also touch.
+ // The interior rings are not yet traversed, and should be taken from the input
+
+ // For intersection: uu, colocated with an ii
+ // unless it is two interior inner rings colocated with a uu
+
+ // So don't set has_traversed_turn here
+ }
+ else if (both_opposite && ! is_self_turn<OverlayType>(turn))
+ {
+ // For union, mark any ring with a ii turn as traversed
+ // For intersection, any uu - but not if it is a self-turn
+ turn_info_map[ring_id].has_traversed_turn = true;
+ }
+ else if (colocated_opp && ! colocated_target)
+ {
+ // For union, a turn colocated with ii and NOT with uu/ux
+ // For intersection v.v.
+ turn_info_map[ring_id].has_traversed_turn = true;
+ }
}
}
}
@@ -128,18 +186,27 @@ template
<
typename GeometryOut, overlay_type OverlayType, bool ReverseOut,
typename Geometry1, typename Geometry2,
- typename OutputIterator
+ typename OutputIterator, typename Strategy
>
inline OutputIterator return_if_one_input_is_empty(Geometry1 const& geometry1,
Geometry2 const& geometry2,
- OutputIterator out)
+ OutputIterator out, Strategy const& strategy)
{
typedef std::deque
<
typename geometry::ring_type<GeometryOut>::type
> ring_container_type;
- typedef ring_properties<typename geometry::point_type<Geometry1>::type> properties;
+ typedef typename geometry::point_type<Geometry1>::type point_type1;
+
+ typedef ring_properties
+ <
+ point_type1,
+ typename Strategy::template area_strategy
+ <
+ point_type1
+ >::type::return_type
+ > properties;
// Silence warning C4127: conditional expression is constant
#if defined(_MSC_VER)
@@ -164,9 +231,9 @@ inline OutputIterator return_if_one_input_is_empty(Geometry1 const& geometry1,
std::map<ring_identifier, ring_turn_info> empty;
std::map<ring_identifier, properties> all_of_one_of_them;
- select_rings<OverlayType>(geometry1, geometry2, empty, all_of_one_of_them);
+ select_rings<OverlayType>(geometry1, geometry2, empty, all_of_one_of_them, strategy);
ring_container_type rings;
- assign_parents(geometry1, geometry2, rings, all_of_one_of_them);
+ assign_parents(geometry1, geometry2, rings, all_of_one_of_them, strategy);
return add_rings<GeometryOut>(all_of_one_of_them, geometry1, geometry2, rings, out);
}
@@ -201,7 +268,7 @@ struct overlay
return return_if_one_input_is_empty
<
GeometryOut, OverlayType, ReverseOut
- >(geometry1, geometry2, out);
+ >(geometry1, geometry2, out, strategy);
}
typedef typename geometry::point_type<GeometryOut>::type point_type;
@@ -238,10 +305,20 @@ std::cout << "get turns" << std::endl;
visitor.visit_turns(1, turns);
+#ifdef BOOST_GEOMETRY_INCLUDE_SELF_TURNS
+ {
+ self_get_turn_points::self_turns<Reverse1, assign_null_policy>(geometry1,
+ strategy, robust_policy, turns, policy, 0);
+ self_get_turn_points::self_turns<Reverse2, assign_null_policy>(geometry2,
+ strategy, robust_policy, turns, policy, 1);
+ }
+#endif
+
+
#ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE
std::cout << "enrich" << std::endl;
#endif
- typename Strategy::side_strategy_type side_strategy;
+ typename Strategy::side_strategy_type side_strategy = strategy.get_side_strategy();
cluster_type clusters;
geometry::enrich_intersection_points<Reverse1, Reverse2, OverlayType>(turns,
@@ -271,33 +348,38 @@ std::cout << "traverse" << std::endl;
);
std::map<ring_identifier, ring_turn_info> turn_info_per_ring;
- get_ring_turn_info(turn_info_per_ring, turns);
+ get_ring_turn_info<OverlayType>(turn_info_per_ring, turns, clusters);
+
+ typedef typename Strategy::template area_strategy<point_type>::type area_strategy_type;
typedef ring_properties
- <
- typename geometry::point_type<GeometryOut>::type
- > properties;
+ <
+ point_type,
+ typename area_strategy_type::return_type
+ > properties;
// Select all rings which are NOT touched by any intersection point
std::map<ring_identifier, properties> selected_ring_properties;
select_rings<OverlayType>(geometry1, geometry2, turn_info_per_ring,
- selected_ring_properties);
+ selected_ring_properties, strategy);
// Add rings created during traversal
{
+ area_strategy_type const area_strategy = strategy.template get_area_strategy<point_type>();
+
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_ring_properties[id] = properties(*it);
+ selected_ring_properties[id] = properties(*it, area_strategy);
selected_ring_properties[id].reversed = ReverseOut;
id.multi_index++;
}
}
- assign_parents(geometry1, geometry2, rings, selected_ring_properties);
+ assign_parents(geometry1, geometry2, rings, selected_ring_properties, strategy);
return add_rings<GeometryOut>(selected_ring_properties, geometry1, geometry2, rings, out);
}
diff --git a/boost/geometry/algorithms/detail/overlay/pointlike_linear.hpp b/boost/geometry/algorithms/detail/overlay/pointlike_linear.hpp
index a26f54e008..0a7c3bc469 100644
--- a/boost/geometry/algorithms/detail/overlay/pointlike_linear.hpp
+++ b/boost/geometry/algorithms/detail/overlay/pointlike_linear.hpp
@@ -1,5 +1,7 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
+// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
+
// Copyright (c) 2015-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
@@ -127,25 +129,57 @@ class multipoint_linear_point
{
private:
// structs for partition -- start
- struct expand_box
+ struct expand_box_point
{
- template <typename Box, typename Geometry>
- static inline void apply(Box& total, Geometry const& geometry)
+ template <typename Box, typename Point>
+ static inline void apply(Box& total, Point const& point)
{
- geometry::expand(total, geometry::return_envelope<Box>(geometry));
+ geometry::expand(total, point);
}
+ };
+
+ template <typename EnvelopeStrategy>
+ struct expand_box_segment
+ {
+ explicit expand_box_segment(EnvelopeStrategy const& strategy)
+ : m_strategy(strategy)
+ {}
+ template <typename Box, typename Segment>
+ inline void apply(Box& total, Segment const& segment) const
+ {
+ geometry::expand(total,
+ geometry::return_envelope<Box>(segment, m_strategy));
+ }
+
+ EnvelopeStrategy const& m_strategy;
};
- struct overlaps_box
+ struct overlaps_box_point
{
- template <typename Box, typename Geometry>
- static inline bool apply(Box const& box, Geometry const& geometry)
+ template <typename Box, typename Point>
+ static inline bool apply(Box const& box, Point const& point)
{
- return ! geometry::disjoint(geometry, box);
+ return ! geometry::disjoint(point, box);
}
};
+ template <typename DisjointStrategy>
+ struct overlaps_box_segment
+ {
+ explicit overlaps_box_segment(DisjointStrategy const& strategy)
+ : m_strategy(strategy)
+ {}
+
+ template <typename Box, typename Segment>
+ inline bool apply(Box const& box, Segment const& segment) const
+ {
+ return ! geometry::disjoint(segment, box, m_strategy);
+ }
+
+ DisjointStrategy const& m_strategy;
+ };
+
template <typename OutputIterator, typename Strategy>
class item_visitor_type
{
@@ -156,12 +190,14 @@ private:
{}
template <typename Item1, typename Item2>
- inline void apply(Item1 const& item1, Item2 const& item2)
+ inline bool apply(Item1 const& item1, Item2 const& item2)
{
action_selector_pl_l
<
PointOut, overlay_intersection
>::apply(item1, Policy::apply(item1, item2, m_strategy), m_oit);
+
+ return true;
}
private:
@@ -202,16 +238,25 @@ private:
{
item_visitor_type<OutputIterator, Strategy> item_visitor(oit, strategy);
- segment_range rng(linear);
+ typedef typename Strategy::envelope_strategy_type envelope_strategy_type;
+ typedef typename Strategy::disjoint_strategy_type disjoint_strategy_type;
+ // TODO: disjoint Segment/Box may be called in partition multiple times
+ // possibly for non-cartesian segments which could be slow. We should consider
+ // passing a range of bounding boxes of segments after calculating them once.
+ // Alternatively instead of a range of segments a range of Segment/Envelope pairs
+ // should be passed, where envelope would be lazily calculated when needed the first time
geometry::partition
<
geometry::model::box
<
typename boost::range_value<MultiPoint>::type
>
- >::apply(multipoint, rng, item_visitor,
- expand_box(), overlaps_box());
+ >::apply(multipoint, segment_range(linear), item_visitor,
+ expand_box_point(),
+ overlaps_box_point(),
+ expand_box_segment<envelope_strategy_type>(strategy.get_envelope_strategy()),
+ overlaps_box_segment<disjoint_strategy_type>(strategy.get_disjoint_strategy()));
return oit;
}
diff --git a/boost/geometry/algorithms/detail/overlay/range_in_geometry.hpp b/boost/geometry/algorithms/detail/overlay/range_in_geometry.hpp
new file mode 100644
index 0000000000..d4a47abecf
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/range_in_geometry.hpp
@@ -0,0 +1,178 @@
+// Boost.Geometry
+
+// Copyright (c) 2017 Oracle and/or its affiliates.
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+// 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_RANGE_IN_GEOMETRY_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_RANGE_IN_GEOMETRY_HPP
+
+
+#include <boost/geometry/algorithms/covered_by.hpp>
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/iterators/point_iterator.hpp>
+
+#include <boost/range.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+
+template
+<
+ typename Geometry,
+ typename Tag = typename geometry::tag<Geometry>::type
+>
+struct points_range
+{
+ typedef geometry::point_iterator<Geometry const> iterator_type;
+
+ explicit points_range(Geometry const& geometry)
+ : m_geometry(geometry)
+ {}
+
+ iterator_type begin() const
+ {
+ return geometry::points_begin(m_geometry);
+ }
+
+ iterator_type end() const
+ {
+ return geometry::points_end(m_geometry);
+ }
+
+ Geometry const& m_geometry;
+};
+// Specialized because point_iterator doesn't support boxes
+template <typename Box>
+struct points_range<Box, box_tag>
+{
+ typedef typename geometry::point_type<Box>::type point_type;
+ typedef const point_type * iterator_type;
+
+ explicit points_range(Box const& box)
+ {
+ detail::assign_box_corners(box,
+ m_corners[0], m_corners[1], m_corners[2], m_corners[3]);
+ }
+
+ iterator_type begin() const
+ {
+ return m_corners;
+ }
+
+ iterator_type end() const
+ {
+ return m_corners + 4;
+ }
+
+ point_type m_corners[4];
+};
+
+template
+<
+ typename Geometry,
+ typename Tag = typename geometry::tag<Geometry>::type
+>
+struct point_in_geometry_helper
+{
+ template <typename Point, typename Strategy>
+ static inline int apply(Point const& point, Geometry const& geometry,
+ Strategy const& strategy)
+ {
+ return detail::within::point_in_geometry(point, geometry, strategy);
+ }
+};
+// Specialized because point_in_geometry doesn't support Boxes
+template <typename Box>
+struct point_in_geometry_helper<Box, box_tag>
+{
+ template <typename Point, typename Strategy>
+ static inline int apply(Point const& point, Box const& box,
+ Strategy const&)
+ {
+ return geometry::covered_by(point, box) ? 1 : -1;
+ }
+};
+
+// This function returns
+// when it finds a point of geometry1 inside or outside geometry2
+template <typename Geometry1, typename Geometry2, typename Strategy>
+static inline int range_in_geometry(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy,
+ bool skip_first = false)
+{
+ int result = 0;
+ points_range<Geometry1> points(geometry1);
+ typedef typename points_range<Geometry1>::iterator_type iterator_type;
+ iterator_type const end = points.end();
+ iterator_type it = points.begin();
+ if (it == end)
+ {
+ return result;
+ }
+ else if (skip_first)
+ {
+ ++it;
+ }
+
+ typename Strategy::template point_in_geometry_strategy
+ <
+ Geometry1, Geometry2
+ >::type const in_strategy
+ = strategy.template get_point_in_geometry_strategy<Geometry1, Geometry2>();
+
+ for ( ; it != end; ++it)
+ {
+ result = point_in_geometry_helper<Geometry2>::apply(*it, geometry2, in_strategy);
+ if (result != 0)
+ {
+ return result;
+ }
+ }
+ // all points contained entirely by the boundary
+ return result;
+}
+
+// This function returns if first_point1 is inside or outside geometry2 or
+// when it finds a point of geometry1 inside or outside geometry2
+template <typename Point1, typename Geometry1, typename Geometry2, typename Strategy>
+inline int range_in_geometry(Point1 const& first_point1,
+ Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+{
+ // check a point on border of geometry1 first
+ int result = point_in_geometry_helper<Geometry2>::apply(first_point1, geometry2,
+ strategy.template get_point_in_geometry_strategy<Point1, Geometry2>());
+ if (result == 0)
+ {
+ // if a point is on boundary of geometry2
+ // check points of geometry1 until point inside/outside is found
+ // NOTE: skip first point because it should be already tested above
+ result = range_in_geometry(geometry1, geometry2, strategy, true);
+ }
+ return result;
+}
+
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_RANGE_IN_GEOMETRY_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/ring_properties.hpp b/boost/geometry/algorithms/detail/overlay/ring_properties.hpp
index 0f2da67b62..7dbc5d5fab 100644
--- a/boost/geometry/algorithms/detail/overlay/ring_properties.hpp
+++ b/boost/geometry/algorithms/detail/overlay/ring_properties.hpp
@@ -2,6 +2,10 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// This file was modified by Oracle on 2017.
+// Modifications copyright (c) 2017 Oracle and/or its affiliates.
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
// 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)
@@ -23,11 +27,11 @@ namespace boost { namespace geometry
namespace detail { namespace overlay
{
-template <typename Point>
+template <typename Point, typename AreaType>
struct ring_properties
{
typedef Point point_type;
- typedef typename default_area_result<Point>::type area_type;
+ typedef AreaType area_type;
bool valid;
@@ -52,17 +56,14 @@ struct ring_properties
, parent_area(-1)
{}
- template <typename RingOrBox>
- inline ring_properties(RingOrBox const& ring_or_box)
+ template <typename RingOrBox, typename AreaStrategy>
+ inline ring_properties(RingOrBox const& ring_or_box, AreaStrategy const& strategy)
: reversed(false)
, discarded(false)
, parent_area(-1)
{
- this->area = geometry::area(ring_or_box);
- // We should take a point somewhere in the middle of the ring,
- // to avoid taking a point on a (self)tangency,
- // in cases where multiple points come together
- valid = geometry::point_on_border(this->point, ring_or_box, true);
+ this->area = geometry::area(ring_or_box, strategy);
+ valid = geometry::point_on_border(this->point, ring_or_box);
}
inline area_type get_area() const
diff --git a/boost/geometry/algorithms/detail/overlay/select_rings.hpp b/boost/geometry/algorithms/detail/overlay/select_rings.hpp
index de5eac8acb..67a4f4bb75 100644
--- a/boost/geometry/algorithms/detail/overlay/select_rings.hpp
+++ b/boost/geometry/algorithms/detail/overlay/select_rings.hpp
@@ -3,6 +3,10 @@
// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
+// This file was modified by Oracle on 2017.
+// Modifications copyright (c) 2017 Oracle and/or its affiliates.
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
// 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)
@@ -18,9 +22,10 @@
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/area.hpp>
-#include <boost/geometry/algorithms/within.hpp>
+#include <boost/geometry/algorithms/covered_by.hpp>
#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
+#include <boost/geometry/algorithms/detail/overlay/range_in_geometry.hpp>
#include <boost/geometry/algorithms/detail/overlay/ring_properties.hpp>
#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
@@ -35,11 +40,11 @@ namespace detail { namespace overlay
struct ring_turn_info
{
- bool has_normal_turn;
+ bool has_traversed_turn;
bool within_other;
ring_turn_info()
- : has_normal_turn(false)
+ : has_traversed_turn(false)
, within_other(false)
{}
};
@@ -54,41 +59,45 @@ namespace dispatch
template <typename Box>
struct select_rings<box_tag, Box>
{
- template <typename Geometry, typename RingPropertyMap>
+ template <typename Geometry, typename RingPropertyMap, typename AreaStrategy>
static inline void apply(Box const& box, Geometry const& ,
- ring_identifier const& id, RingPropertyMap& ring_properties)
+ ring_identifier const& id, RingPropertyMap& ring_properties,
+ AreaStrategy const& strategy)
{
- ring_properties[id] = typename RingPropertyMap::mapped_type(box);
+ ring_properties[id] = typename RingPropertyMap::mapped_type(box, strategy);
}
- template <typename RingPropertyMap>
+ template <typename RingPropertyMap, typename AreaStrategy>
static inline void apply(Box const& box,
- ring_identifier const& id, RingPropertyMap& ring_properties)
+ ring_identifier const& id, RingPropertyMap& ring_properties,
+ AreaStrategy const& strategy)
{
- ring_properties[id] = typename RingPropertyMap::mapped_type(box);
+ ring_properties[id] = typename RingPropertyMap::mapped_type(box, strategy);
}
};
template <typename Ring>
struct select_rings<ring_tag, Ring>
{
- template <typename Geometry, typename RingPropertyMap>
+ template <typename Geometry, typename RingPropertyMap, typename AreaStrategy>
static inline void apply(Ring const& ring, Geometry const& ,
- ring_identifier const& id, RingPropertyMap& ring_properties)
+ ring_identifier const& id, RingPropertyMap& ring_properties,
+ AreaStrategy const& strategy)
{
if (boost::size(ring) > 0)
{
- ring_properties[id] = typename RingPropertyMap::mapped_type(ring);
+ ring_properties[id] = typename RingPropertyMap::mapped_type(ring, strategy);
}
}
- template <typename RingPropertyMap>
+ template <typename RingPropertyMap, typename AreaStrategy>
static inline void apply(Ring const& ring,
- ring_identifier const& id, RingPropertyMap& ring_properties)
+ ring_identifier const& id, RingPropertyMap& ring_properties,
+ AreaStrategy const& strategy)
{
if (boost::size(ring) > 0)
{
- ring_properties[id] = typename RingPropertyMap::mapped_type(ring);
+ ring_properties[id] = typename RingPropertyMap::mapped_type(ring, strategy);
}
}
};
@@ -97,14 +106,15 @@ namespace dispatch
template <typename Polygon>
struct select_rings<polygon_tag, Polygon>
{
- template <typename Geometry, typename RingPropertyMap>
+ template <typename Geometry, typename RingPropertyMap, typename AreaStrategy>
static inline void apply(Polygon const& polygon, Geometry const& geometry,
- ring_identifier id, RingPropertyMap& ring_properties)
+ ring_identifier id, RingPropertyMap& ring_properties,
+ AreaStrategy const& strategy)
{
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, ring_properties);
+ per_ring::apply(exterior_ring(polygon), geometry, id, ring_properties, strategy);
typename interior_return_type<Polygon const>::type
rings = interior_rings(polygon);
@@ -112,18 +122,19 @@ namespace dispatch
it = boost::begin(rings); it != boost::end(rings); ++it)
{
id.ring_index++;
- per_ring::apply(*it, geometry, id, ring_properties);
+ per_ring::apply(*it, geometry, id, ring_properties, strategy);
}
}
- template <typename RingPropertyMap>
+ template <typename RingPropertyMap, typename AreaStrategy>
static inline void apply(Polygon const& polygon,
- ring_identifier id, RingPropertyMap& ring_properties)
+ ring_identifier id, RingPropertyMap& ring_properties,
+ AreaStrategy const& strategy)
{
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, ring_properties);
+ per_ring::apply(exterior_ring(polygon), id, ring_properties, strategy);
typename interior_return_type<Polygon const>::type
rings = interior_rings(polygon);
@@ -131,7 +142,7 @@ namespace dispatch
it = boost::begin(rings); it != boost::end(rings); ++it)
{
id.ring_index++;
- per_ring::apply(*it, id, ring_properties);
+ per_ring::apply(*it, id, ring_properties, strategy);
}
}
};
@@ -139,9 +150,10 @@ namespace dispatch
template <typename Multi>
struct select_rings<multi_polygon_tag, Multi>
{
- template <typename Geometry, typename RingPropertyMap>
+ template <typename Geometry, typename RingPropertyMap, typename AreaStrategy>
static inline void apply(Multi const& multi, Geometry const& geometry,
- ring_identifier id, RingPropertyMap& ring_properties)
+ ring_identifier id, RingPropertyMap& ring_properties,
+ AreaStrategy const& strategy)
{
typedef typename boost::range_iterator
<
@@ -154,7 +166,7 @@ namespace dispatch
for (iterator_type it = boost::begin(multi); it != boost::end(multi); ++it)
{
id.ring_index = -1;
- per_polygon::apply(*it, geometry, id, ring_properties);
+ per_polygon::apply(*it, geometry, id, ring_properties, strategy);
id.multi_index++;
}
}
@@ -221,20 +233,21 @@ struct decide<overlay_intersection>
}
};
-
template
<
overlay_type OverlayType,
typename Geometry1,
typename Geometry2,
typename TurnInfoMap,
- typename RingPropertyMap
+ typename RingPropertyMap,
+ typename Strategy
>
inline void update_ring_selection(Geometry1 const& geometry1,
Geometry2 const& geometry2,
TurnInfoMap const& turn_info_map,
RingPropertyMap const& all_ring_properties,
- RingPropertyMap& selected_ring_properties)
+ RingPropertyMap& selected_ring_properties,
+ Strategy const& strategy)
{
selected_ring_properties.clear();
@@ -252,9 +265,9 @@ inline void update_ring_selection(Geometry1 const& geometry1,
info = tcit->second; // Copy by value
}
- if (info.has_normal_turn)
+ if (info.has_traversed_turn)
{
- // There are normal turns on this ring. It should be traversed, we
+ // This turn is traversed (or blocked),
// don't include the original ring
continue;
}
@@ -263,11 +276,16 @@ inline void update_ring_selection(Geometry1 const& geometry1,
// a point lying on the ring
switch(id.source_index)
{
+ // within
case 0 :
- info.within_other = geometry::within(it->second.point, geometry2);
+ info.within_other = range_in_geometry(it->second.point,
+ geometry1, geometry2,
+ strategy) > 0;
break;
case 1 :
- info.within_other = geometry::within(it->second.point, geometry1);
+ info.within_other = range_in_geometry(it->second.point,
+ geometry2, geometry1,
+ strategy) > 0;
break;
}
@@ -290,23 +308,30 @@ template
typename Geometry1,
typename Geometry2,
typename RingTurnInfoMap,
- typename RingPropertyMap
+ typename RingPropertyMap,
+ typename Strategy
>
inline void select_rings(Geometry1 const& geometry1, Geometry2 const& geometry2,
RingTurnInfoMap const& turn_info_per_ring,
- RingPropertyMap& selected_ring_properties)
+ RingPropertyMap& selected_ring_properties,
+ Strategy const& strategy)
{
typedef typename geometry::tag<Geometry1>::type tag1;
typedef typename geometry::tag<Geometry2>::type tag2;
+ typedef typename geometry::point_type<Geometry1>::type point1_type;
+ typedef typename geometry::point_type<Geometry2>::type point2_type;
RingPropertyMap all_ring_properties;
dispatch::select_rings<tag1, Geometry1>::apply(geometry1, geometry2,
- ring_identifier(0, -1, -1), all_ring_properties);
+ ring_identifier(0, -1, -1), all_ring_properties,
+ strategy.template get_area_strategy<point1_type>());
dispatch::select_rings<tag2, Geometry2>::apply(geometry2, geometry1,
- ring_identifier(1, -1, -1), all_ring_properties);
+ ring_identifier(1, -1, -1), all_ring_properties,
+ strategy.template get_area_strategy<point2_type>());
update_ring_selection<OverlayType>(geometry1, geometry2, turn_info_per_ring,
- all_ring_properties, selected_ring_properties);
+ all_ring_properties, selected_ring_properties,
+ strategy);
}
template
@@ -314,20 +339,25 @@ template
overlay_type OverlayType,
typename Geometry,
typename RingTurnInfoMap,
- typename RingPropertyMap
+ typename RingPropertyMap,
+ typename Strategy
>
inline void select_rings(Geometry const& geometry,
RingTurnInfoMap const& turn_info_per_ring,
- RingPropertyMap& selected_ring_properties)
+ RingPropertyMap& selected_ring_properties,
+ Strategy const& strategy)
{
typedef typename geometry::tag<Geometry>::type tag;
+ typedef typename geometry::point_type<Geometry>::type point_type;
RingPropertyMap all_ring_properties;
dispatch::select_rings<tag, Geometry>::apply(geometry,
- ring_identifier(0, -1, -1), all_ring_properties);
+ ring_identifier(0, -1, -1), all_ring_properties,
+ strategy.template get_area_strategy<point_type>());
update_ring_selection<OverlayType>(geometry, geometry, turn_info_per_ring,
- all_ring_properties, selected_ring_properties);
+ all_ring_properties, selected_ring_properties,
+ strategy);
}
diff --git a/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp b/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp
index 8540ef98a0..5e9d8efa8e 100644
--- a/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp
+++ b/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp
@@ -1,6 +1,7 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2017.
// Modifications copyright (c) 2017 Oracle and/or its affiliates.
@@ -22,12 +23,14 @@
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
+#include <boost/geometry/core/point_order.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
#include <boost/geometry/algorithms/detail/partition.hpp>
+#include <boost/geometry/algorithms/detail/overlay/do_reverse.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
#include <boost/geometry/algorithms/detail/sections/section_box_policies.hpp>
@@ -57,12 +60,9 @@ struct no_interrupt_policy
};
-
-
-class self_ip_exception : public geometry::exception {};
-
template
<
+ bool Reverse,
typename Geometry,
typename Turns,
typename TurnPolicy,
@@ -77,17 +77,20 @@ struct self_section_visitor
RobustPolicy const& m_rescale_policy;
Turns& m_turns;
InterruptPolicy& m_interrupt_policy;
+ std::size_t m_source_index;
inline self_section_visitor(Geometry const& g,
IntersectionStrategy const& is,
RobustPolicy const& rp,
Turns& turns,
- InterruptPolicy& ip)
+ InterruptPolicy& ip,
+ std::size_t source_index)
: m_geometry(g)
, m_intersection_strategy(is)
, m_rescale_policy(rp)
, m_turns(turns)
, m_interrupt_policy(ip)
+ , m_source_index(source_index)
{}
template <typename Section>
@@ -97,26 +100,21 @@ struct self_section_visitor
&& ! sec1.duplicate
&& ! sec2.duplicate)
{
- detail::get_turns::get_turns_in_sections
+ // false if interrupted
+ return detail::get_turns::get_turns_in_sections
<
Geometry, Geometry,
- false, false,
+ Reverse, Reverse,
Section, Section,
TurnPolicy
- >::apply(
- 0, m_geometry, sec1,
- 0, m_geometry, sec2,
- false,
- m_intersection_strategy,
- m_rescale_policy,
- m_turns, m_interrupt_policy);
- }
- if (BOOST_GEOMETRY_CONDITION(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();
+ >::apply(m_source_index, m_geometry, sec1,
+ m_source_index, m_geometry, sec2,
+ false,
+ m_intersection_strategy,
+ m_rescale_policy,
+ m_turns, m_interrupt_policy);
}
+
return true;
}
@@ -124,7 +122,7 @@ struct self_section_visitor
-template<typename TurnPolicy>
+template <bool Reverse, typename TurnPolicy>
struct get_turns
{
template <typename Geometry, typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy>
@@ -133,7 +131,8 @@ struct get_turns
IntersectionStrategy const& intersection_strategy,
RobustPolicy const& robust_policy,
Turns& turns,
- InterruptPolicy& interrupt_policy)
+ InterruptPolicy& interrupt_policy,
+ std::size_t source_index)
{
typedef model::box
<
@@ -149,29 +148,24 @@ struct get_turns
typedef boost::mpl::vector_c<std::size_t, 0> dimensions;
sections_type sec;
- geometry::sectionalize<false, dimensions>(geometry, robust_policy, sec);
+ geometry::sectionalize<Reverse, dimensions>(geometry, robust_policy, sec,
+ intersection_strategy.get_envelope_strategy());
self_section_visitor
<
- Geometry,
+ Reverse, Geometry,
Turns, TurnPolicy, IntersectionStrategy, RobustPolicy, InterruptPolicy
- > visitor(geometry, intersection_strategy, robust_policy, turns, interrupt_policy);
+ > visitor(geometry, intersection_strategy, robust_policy, turns, interrupt_policy, source_index);
- try
- {
- geometry::partition
- <
- box_type
- >::apply(sec, visitor,
- detail::section::get_section_box(),
- detail::section::overlaps_section_box());
- }
- catch(self_ip_exception const& )
- {
- return false;
- }
+ // false if interrupted
+ geometry::partition
+ <
+ box_type
+ >::apply(sec, visitor,
+ detail::section::get_section_box(),
+ detail::section::overlaps_section_box());
- return true;
+ return ! interrupt_policy.has_intersections;
}
};
@@ -186,6 +180,7 @@ namespace dispatch
template
<
+ bool Reverse,
typename GeometryTag,
typename Geometry,
typename TurnPolicy
@@ -197,26 +192,28 @@ struct self_get_turn_points
template
<
+ bool Reverse,
typename Ring,
typename TurnPolicy
>
struct self_get_turn_points
<
- ring_tag, Ring,
+ Reverse, ring_tag, Ring,
TurnPolicy
>
- : detail::self_get_turn_points::get_turns<TurnPolicy>
+ : detail::self_get_turn_points::get_turns<Reverse, TurnPolicy>
{};
template
<
+ bool Reverse,
typename Box,
typename TurnPolicy
>
struct self_get_turn_points
<
- box_tag, Box,
+ Reverse, box_tag, Box,
TurnPolicy
>
{
@@ -226,7 +223,8 @@ struct self_get_turn_points
Strategy const& ,
RobustPolicy const& ,
Turns& ,
- InterruptPolicy& )
+ InterruptPolicy& ,
+ std::size_t)
{
return true;
}
@@ -235,29 +233,31 @@ struct self_get_turn_points
template
<
+ bool Reverse,
typename Polygon,
typename TurnPolicy
>
struct self_get_turn_points
<
- polygon_tag, Polygon,
+ Reverse, polygon_tag, Polygon,
TurnPolicy
>
- : detail::self_get_turn_points::get_turns<TurnPolicy>
+ : detail::self_get_turn_points::get_turns<Reverse, TurnPolicy>
{};
template
<
+ bool Reverse,
typename MultiPolygon,
typename TurnPolicy
>
struct self_get_turn_points
<
- multi_polygon_tag, MultiPolygon,
+ Reverse, multi_polygon_tag, MultiPolygon,
TurnPolicy
>
- : detail::self_get_turn_points::get_turns<TurnPolicy>
+ : detail::self_get_turn_points::get_turns<Reverse, TurnPolicy>
{};
@@ -265,6 +265,45 @@ struct self_get_turn_points
#endif // DOXYGEN_NO_DISPATCH
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace self_get_turn_points
+{
+
+// Version where Reverse can be specified manually. TODO:
+// can most probably be merged with self_get_turn_points::get_turn
+template
+<
+ bool Reverse,
+ typename AssignPolicy,
+ typename Geometry,
+ typename IntersectionStrategy,
+ typename RobustPolicy,
+ typename Turns,
+ typename InterruptPolicy
+>
+inline void self_turns(Geometry const& geometry,
+ IntersectionStrategy const& strategy,
+ RobustPolicy const& robust_policy,
+ Turns& turns,
+ InterruptPolicy& interrupt_policy,
+ std::size_t source_index = 0)
+{
+ concepts::check<Geometry const>();
+
+ typedef detail::overlay::get_turn_info<detail::overlay::assign_null_policy> turn_policy;
+
+ dispatch::self_get_turn_points
+ <
+ Reverse,
+ typename tag<Geometry>::type,
+ Geometry,
+ turn_policy
+ >::apply(geometry, strategy, robust_policy, turns, interrupt_policy, source_index);
+}
+
+}} // namespace detail::self_get_turn_points
+#endif // DOXYGEN_NO_DETAIL
+
/*!
\brief Calculate self intersections of a geometry
\ingroup overlay
@@ -290,18 +329,22 @@ template
inline void self_turns(Geometry const& geometry,
IntersectionStrategy const& strategy,
RobustPolicy const& robust_policy,
- Turns& turns, InterruptPolicy& interrupt_policy)
+ Turns& turns,
+ InterruptPolicy& interrupt_policy,
+ std::size_t source_index = 0)
{
concepts::check<Geometry const>();
- typedef detail::overlay::get_turn_info<detail::overlay::assign_null_policy> turn_policy;
+ static bool const reverse = detail::overlay::do_reverse
+ <
+ geometry::point_order<Geometry>::value
+ >::value;
- dispatch::self_get_turn_points
+ detail::self_get_turn_points::self_turns
<
- typename tag<Geometry>::type,
- Geometry,
- turn_policy
- >::apply(geometry, strategy, robust_policy, turns, interrupt_policy);
+ reverse,
+ AssignPolicy
+ >(geometry, strategy, robust_policy, turns, interrupt_policy, source_index);
}
diff --git a/boost/geometry/algorithms/detail/overlay/sort_by_side.hpp b/boost/geometry/algorithms/detail/overlay/sort_by_side.hpp
index bbba623eee..5ad2e41b12 100644
--- a/boost/geometry/algorithms/detail/overlay/sort_by_side.hpp
+++ b/boost/geometry/algorithms/detail/overlay/sort_by_side.hpp
@@ -2,6 +2,11 @@
// Copyright (c) 2015 Barend Gehrels, Amsterdam, the Netherlands.
+// This file was modified by Oracle on 2017.
+// Modifications copyright (c) 2017 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
// 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)
@@ -10,11 +15,14 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SORT_BY_SIDE_HPP
#include <algorithm>
+#include <map>
#include <vector>
+#include <boost/geometry/algorithms/num_points.hpp>
+#include <boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp>
+#include <boost/geometry/algorithms/detail/overlay/get_ring.hpp>
#include <boost/geometry/algorithms/detail/direction_code.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
-#include <boost/geometry/strategies/side.hpp>
namespace boost { namespace geometry
{
@@ -37,7 +45,6 @@ struct ranked_point
, count_left(0)
, count_right(0)
, operation(operation_none)
- , only_turn_on_ring(false)
{}
template <typename Op>
@@ -53,7 +60,6 @@ struct ranked_point
, count_right(0)
, operation(op.operation)
, seg_id(op.seg_id)
- , only_turn_on_ring(op.enriched.only_turn_on_ring)
{}
Point point;
@@ -66,7 +72,6 @@ struct ranked_point
std::size_t count_right;
operation_type operation;
segment_identifier seg_id;
- bool only_turn_on_ring;
};
struct less_by_turn_index
@@ -105,17 +110,13 @@ struct less_false
}
};
-template <typename Point, typename LessOnSame, typename Compare>
+template <typename Point, typename SideStrategy, typename LessOnSame, typename Compare>
struct less_by_side
{
- typedef typename strategy::side::services::default_strategy
- <
- typename cs_tag<Point>::type
- >::type side;
-
- less_by_side(const Point& p1, const Point& p2)
+ less_by_side(const Point& p1, const Point& p2, SideStrategy const& strategy)
: m_p1(p1)
, m_p2(p2)
+ , m_strategy(strategy)
{}
template <typename T>
@@ -124,8 +125,8 @@ struct less_by_side
LessOnSame on_same;
Compare compare;
- int const side_first = side::apply(m_p1, m_p2, first.point);
- int const side_second = side::apply(m_p1, m_p2, second.point);
+ int const side_first = m_strategy.apply(m_p1, m_p2, first.point);
+ int const side_second = m_strategy.apply(m_p1, m_p2, second.point);
if (side_first == 0 && side_second == 0)
{
@@ -165,7 +166,7 @@ struct less_by_side
// They are both left, both right, and/or both collinear (with each other and/or with p1,p2)
// Check mutual side
- int const side_second_wrt_first = side::apply(m_p2, first.point, second.point);
+ int const side_second_wrt_first = m_strategy.apply(m_p2, first.point, second.point);
if (side_second_wrt_first == 0)
{
@@ -183,10 +184,19 @@ struct less_by_side
private :
Point m_p1, m_p2;
+ SideStrategy const& m_strategy;
};
// Sorts vectors in counter clockwise order (by default)
-template <bool Reverse1, bool Reverse2, typename Point, typename Compare>
+template
+<
+ bool Reverse1,
+ bool Reverse2,
+ overlay_type OverlayType,
+ typename Point,
+ typename SideStrategy,
+ typename Compare
+>
struct side_sorter
{
typedef ranked_point<Point> rp;
@@ -215,13 +225,14 @@ private :
};
public :
- inline void set_origin(Point const& origin)
- {
- m_origin = origin;
- }
+ side_sorter(SideStrategy const& strategy)
+ : m_origin_count(0)
+ , m_origin_segment_distance(0)
+ , m_strategy(strategy)
+ {}
template <typename Operation, typename Geometry1, typename Geometry2>
- void add(Operation const& op, signed_size_type turn_index, signed_size_type op_index,
+ Point add(Operation const& op, signed_size_type turn_index, signed_size_type op_index,
Geometry1 const& geometry1,
Geometry2 const& geometry2,
bool is_origin)
@@ -233,11 +244,63 @@ public :
m_ranked_points.push_back(rp(point1, turn_index, op_index, dir_from, op));
m_ranked_points.push_back(rp(point_to, turn_index, op_index, dir_to, op));
-
if (is_origin)
{
m_origin = point1;
+ m_origin_count++;
}
+ return point1;
+ }
+
+ template <typename Operation, typename Geometry1, typename Geometry2>
+ void add(Operation const& op, signed_size_type turn_index, signed_size_type op_index,
+ segment_identifier const& departure_seg_id,
+ Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ bool check_origin)
+ {
+ Point const point1 = add(op, turn_index, op_index, geometry1, geometry2, false);
+
+ if (check_origin)
+ {
+ bool const is_origin
+ = op.seg_id.source_index == departure_seg_id.source_index
+ && op.seg_id.ring_index == departure_seg_id.ring_index
+ && op.seg_id.multi_index == departure_seg_id.multi_index;
+
+ if (is_origin)
+ {
+ int const segment_distance = calculate_segment_distance(op, departure_seg_id, geometry1, geometry2);
+ if (m_origin_count == 0 ||
+ segment_distance < m_origin_segment_distance)
+ {
+ m_origin = point1;
+ m_origin_segment_distance = segment_distance;
+ }
+ m_origin_count++;
+ }
+ }
+ }
+
+ template <typename Operation, typename Geometry1, typename Geometry2>
+ static int calculate_segment_distance(Operation const& op,
+ segment_identifier const& departure_seg_id,
+ Geometry1 const& geometry1,
+ Geometry2 const& geometry2)
+ {
+ if (op.seg_id.segment_index >= departure_seg_id.segment_index)
+ {
+ return op.seg_id.segment_index - departure_seg_id.segment_index;
+ }
+ // Take wrap into account
+ // Suppose ring_count=10 (10 points, 9 segments), dep.seg_id=7, op.seg_id=2, then distance=10-9+2
+ // Generic function (is this used somewhere else too?)
+ ring_identifier const rid(op.seg_id.source_index, op.seg_id.multi_index, op.seg_id.ring_index);
+ int const segment_count
+ (op.seg_id.source_index == 0
+ ? geometry::num_points(detail::overlay::get_ring<typename geometry::tag<Geometry1>::type>::apply(rid, geometry1))
+ : geometry::num_points(detail::overlay::get_ring<typename geometry::tag<Geometry2>::type>::apply(rid, geometry2)));
+ return ((segment_count - 1) - departure_seg_id.segment_index) + op.seg_id.segment_index;
}
void apply(Point const& turn_point)
@@ -249,8 +312,8 @@ public :
// to give colinear points
// Sort by side and assign rank
- less_by_side<Point, less_by_index, Compare> less_unique(m_origin, turn_point);
- less_by_side<Point, less_false, Compare> less_non_unique(m_origin, turn_point);
+ less_by_side<Point, SideStrategy, less_by_index, Compare> less_unique(m_origin, turn_point, m_strategy);
+ less_by_side<Point, SideStrategy, less_false, Compare> less_non_unique(m_origin, turn_point, m_strategy);
std::sort(m_ranked_points.begin(), m_ranked_points.end(), less_unique);
@@ -269,7 +332,7 @@ public :
}
template <signed_size_type segment_identifier::*Member, typename Map>
- void find_open_generic(Map& handled)
+ void find_open_generic(Map& handled, bool check)
{
for (std::size_t i = 0; i < m_ranked_points.size(); i++)
{
@@ -280,6 +343,11 @@ public :
}
signed_size_type const& index = ranked.seg_id.*Member;
+ if (check && (index < 0 || index > 1))
+ {
+ // Should not occur
+ continue;
+ }
if (! handled[index])
{
find_polygons_for_source<Member>(index, i);
@@ -290,36 +358,23 @@ public :
void find_open()
{
- // TODO: we might pass Buffer as overlay_type, instead on the fly below
- bool one_source = true;
- for (std::size_t i = 0; i < m_ranked_points.size(); i++)
- {
- const rp& ranked = m_ranked_points[i];
- signed_size_type const& src = ranked.seg_id.source_index;
- if (src != 0)
- {
- one_source = false;
- break;
- }
- }
-
- if (one_source)
+ if (OverlayType == overlay_buffer)
{
- // by multi index
+ // For buffers, use piece index
std::map<signed_size_type, bool> handled;
find_open_generic
<
&segment_identifier::piece_index
- >(handled);
+ >(handled, false);
}
else
{
- // by source (there should only source 0,1) TODO assert this
+ // For other operations, by source (there should only source 0,1)
bool handled[2] = {false, false};
find_open_generic
<
&segment_identifier::source_index
- >(handled);
+ >(handled, true);
}
}
@@ -361,11 +416,19 @@ public :
}
}
+ bool has_origin() const
+ {
+ return m_origin_count > 0;
+ }
+
//private :
typedef std::vector<rp> container_type;
container_type m_ranked_points;
Point m_origin;
+ std::size_t m_origin_count;
+ int m_origin_segment_distance;
+ SideStrategy m_strategy;
private :
@@ -439,9 +502,10 @@ private :
void find_polygons_for_source(signed_size_type the_index,
std::size_t start_index)
{
- int state = 1; // 'closed', because start_index is "from", arrives at the turn
- std::size_t last_from_rank = m_ranked_points[start_index].rank;
- std::size_t previous_rank = m_ranked_points[start_index].rank;
+ bool in_polygon = true; // Because start_index is "from", arrives at the turn
+ rp const& start_rp = m_ranked_points[start_index];
+ std::size_t last_from_rank = start_rp.rank;
+ std::size_t previous_rank = start_rp.rank;
for (std::size_t index = move<Member>(the_index, start_index);
;
@@ -449,7 +513,7 @@ private :
{
rp& ranked = m_ranked_points[index];
- if (ranked.rank != previous_rank && state == 0)
+ if (ranked.rank != previous_rank && ! in_polygon)
{
assign_ranks(last_from_rank, previous_rank - 1, 1);
assign_ranks(last_from_rank + 1, previous_rank, 2);
@@ -463,11 +527,11 @@ private :
if (ranked.direction == dir_from)
{
last_from_rank = ranked.rank;
- state++;
+ in_polygon = true;
}
else if (ranked.direction == dir_to)
{
- state--;
+ in_polygon = false;
}
previous_rank = ranked.rank;
diff --git a/boost/geometry/algorithms/detail/overlay/traversal.hpp b/boost/geometry/algorithms/detail/overlay/traversal.hpp
index bc828920e9..69d62b788b 100644
--- a/boost/geometry/algorithms/detail/overlay/traversal.hpp
+++ b/boost/geometry/algorithms/detail/overlay/traversal.hpp
@@ -2,6 +2,11 @@
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// This file was modified by Oracle on 2017.
+// Modifications copyright (c) 2017 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
// 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)
@@ -14,7 +19,9 @@
#include <boost/range.hpp>
#include <boost/geometry/algorithms/detail/overlay/aggregate_operations.hpp>
+#include <boost/geometry/algorithms/detail/overlay/is_self_turn.hpp>
#include <boost/geometry/algorithms/detail/overlay/sort_by_side.hpp>
+#include <boost/geometry/algorithms/detail/overlay/traversal_intersection_patterns.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/assert.hpp>
@@ -37,9 +44,13 @@ 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::string const& header, bool condition = true)
{
- std::cout << header
+ if (! condition)
+ {
+ return;
+ }
+ std::cout << " " << header
<< " at " << op.seg_id
<< " meth: " << method_char(turn.method)
<< " op: " << operation_char(op.operation)
@@ -55,7 +66,7 @@ inline void debug_traverse(Turn const& turn, Operation op,
}
}
#else
-inline void debug_traverse(Turn const& , Operation, const char*)
+inline void debug_traverse(Turn const& , Operation, const char*, bool = true)
{
}
#endif
@@ -88,6 +99,7 @@ template
typename Turns,
typename Clusters,
typename RobustPolicy,
+ typename SideStrategy,
typename Visitor
>
struct traversal
@@ -101,18 +113,20 @@ struct traversal
typedef typename geometry::point_type<Geometry1>::type point_type;
typedef sort_by_side::side_sorter
<
- Reverse1, Reverse2,
- point_type, side_compare_type
+ Reverse1, Reverse2, OverlayType,
+ point_type, SideStrategy, side_compare_type
> sbs_type;
inline traversal(Geometry1 const& geometry1, Geometry2 const& geometry2,
Turns& turns, Clusters const& clusters,
- RobustPolicy const& robust_policy, Visitor& visitor)
+ RobustPolicy const& robust_policy, SideStrategy const& strategy,
+ Visitor& visitor)
: m_geometry1(geometry1)
, m_geometry2(geometry2)
, m_turns(turns)
, m_clusters(clusters)
, m_robust_policy(robust_policy)
+ , m_strategy(strategy)
, m_visitor(visitor)
{
}
@@ -133,11 +147,38 @@ struct traversal
}
}
+ //! Sets visited for ALL turns traveling to the same turn
+ inline void set_visited_in_cluster(signed_size_type cluster_id,
+ signed_size_type rank)
+ {
+ typename Clusters::const_iterator mit = m_clusters.find(cluster_id);
+ BOOST_ASSERT(mit != m_clusters.end());
+
+ cluster_info const& cinfo = mit->second;
+ std::set<signed_size_type> const& ids = cinfo.turn_indices;
+
+ for (typename std::set<signed_size_type>::const_iterator it = ids.begin();
+ it != ids.end(); ++it)
+ {
+ signed_size_type const turn_index = *it;
+ turn_type& turn = m_turns[turn_index];
+
+ for (int i = 0; i < 2; i++)
+ {
+ turn_operation_type& op = turn.operations[i];
+ if (op.visited.none()
+ && op.enriched.rank == rank)
+ {
+ op.visited.set_visited();
+ }
+ }
+ }
+ }
inline void set_visited(turn_type& turn, turn_operation_type& op)
{
- // On "continue", set "visited" for ALL directions in this turn
if (op.operation == detail::overlay::operation_continue)
{
+ // On "continue", all go in same direction so set "visited" for ALL
for (int i = 0; i < 2; i++)
{
turn_operation_type& turn_op = turn.operations[i];
@@ -151,6 +192,10 @@ struct traversal
{
op.visited.set_visited();
}
+ if (turn.cluster_id >= 0)
+ {
+ set_visited_in_cluster(turn.cluster_id, op.enriched.rank);
+ }
}
inline bool is_visited(turn_type const& , turn_operation_type const& op,
@@ -160,8 +205,8 @@ struct traversal
}
inline bool select_source(signed_size_type turn_index,
- segment_identifier const& seg_id1,
- segment_identifier const& seg_id2) const
+ segment_identifier const& candidate_seg_id,
+ segment_identifier const& previous_seg_id) const
{
// For uu/ii, only switch sources if indicated
turn_type const& turn = m_turns[turn_index];
@@ -170,8 +215,16 @@ struct traversal
{
// Buffer does not use source_index (always 0)
return turn.switch_source
- ? seg_id1.multi_index != seg_id2.multi_index
- : seg_id1.multi_index == seg_id2.multi_index;
+ ? candidate_seg_id.multi_index != previous_seg_id.multi_index
+ : candidate_seg_id.multi_index == previous_seg_id.multi_index;
+ }
+
+ if (is_self_turn<OverlayType>(turn))
+ {
+ // Also, if it is a self-turn, stay on same ring (multi/ring)
+ return turn.switch_source
+ ? candidate_seg_id.multi_index != previous_seg_id.multi_index
+ : candidate_seg_id.multi_index == previous_seg_id.multi_index;
}
#if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR)
@@ -185,16 +238,8 @@ struct traversal
}
#endif
return turn.switch_source
- ? seg_id1.source_index != seg_id2.source_index
- : seg_id1.source_index == seg_id2.source_index;
- }
-
- inline
- signed_size_type get_next_turn_index(turn_operation_type const& op) const
- {
- return op.enriched.next_ip_index == -1
- ? op.enriched.travels_to_ip_index
- : op.enriched.next_ip_index;
+ ? candidate_seg_id.source_index != previous_seg_id.source_index
+ : candidate_seg_id.source_index == previous_seg_id.source_index;
}
inline bool traverse_possible(signed_size_type turn_index) const
@@ -220,39 +265,39 @@ struct traversal
{
// For "cc", take either one, but if there is a starting one,
// take that one. If next is dead end, skip that one.
+ // If both are valid candidates, take the one with minimal remaining
+ // distance (important for #mysql_23023665 in buffer).
- bool result = false;
-
+ // Initialize with 0, automatically assigned on first result
typename turn_operation_type::comparable_distance_type
- max_remaining_distance = 0;
+ min_remaining_distance = 0;
+
+ bool result = false;
for (int i = 0; i < 2; i++)
{
turn_operation_type const& op = turn.operations[i];
- signed_size_type const next_turn_index = get_next_turn_index(op);
+ signed_size_type const next_turn_index = op.enriched.get_next_turn_index();
- if (! result && traverse_possible(next_turn_index))
+ if (! traverse_possible(next_turn_index))
{
- max_remaining_distance = op.remaining_distance;
- selected_op_index = i;
- debug_traverse(turn, op, " Candidate");
- result = true;
+ continue;
}
- if (result)
+ if (! result
+ || next_turn_index == start_turn_index
+ || op.remaining_distance < min_remaining_distance)
{
- if (next_turn_index == start_turn_index)
- {
- selected_op_index = i;
- debug_traverse(turn, op, " Candidate cc override (start)");
- }
- else if (op.remaining_distance > max_remaining_distance)
- {
- max_remaining_distance = op.remaining_distance;
- selected_op_index = i;
- debug_traverse(turn, op, " Candidate cc override (remaining)");
- }
+ debug_traverse(turn, op, "First candidate cc", ! result);
+ debug_traverse(turn, op, "Candidate cc override (start)",
+ result && next_turn_index == start_turn_index);
+ debug_traverse(turn, op, "Candidate cc override (remaining)",
+ result && op.remaining_distance < min_remaining_distance);
+
+ selected_op_index = i;
+ min_remaining_distance = op.remaining_distance;
+ result = true;
}
}
@@ -262,7 +307,7 @@ struct traversal
inline
bool select_noncc_operation(turn_type const& turn,
signed_size_type turn_index,
- segment_identifier const& seg_id,
+ segment_identifier const& previous_seg_id,
int& selected_op_index) const
{
bool result = false;
@@ -273,10 +318,10 @@ struct traversal
if (op.operation == target_operation
&& ! op.visited.finished()
- && (! result || select_source(turn_index, op.seg_id, seg_id)))
+ && (! result || select_source(turn_index, op.seg_id, previous_seg_id)))
{
selected_op_index = i;
- debug_traverse(turn, op, " Candidate");
+ debug_traverse(turn, op, "Candidate");
result = true;
}
}
@@ -305,7 +350,7 @@ struct traversal
}
if (result)
{
- debug_traverse(turn, turn.operations[selected_op_index], " Accepted");
+ debug_traverse(turn, turn.operations[selected_op_index], "Accepted");
}
return result;
@@ -336,108 +381,164 @@ struct traversal
}
inline bool select_from_cluster_union(signed_size_type& turn_index,
- int& op_index, signed_size_type start_turn_index,
- sbs_type const& sbs, bool is_touching) const
+ int& op_index, sbs_type& sbs) const
{
+ std::vector<sort_by_side::rank_with_rings> aggregation;
+ sort_by_side::aggregate_operations(sbs, aggregation, m_turns, operation_union);
+
+
+ sort_by_side::rank_with_rings const& incoming = aggregation.front();
+
+ // Take the first one outgoing for the incoming region
std::size_t selected_rank = 0;
- std::size_t min_rank = 0;
- bool result = false;
- for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++)
+ for (std::size_t i = 1; i < aggregation.size(); i++)
+ {
+ sort_by_side::rank_with_rings const& rwr = aggregation[i];
+ if (rwr.all_to()
+ && rwr.region_id() == incoming.region_id())
+ {
+ selected_rank = rwr.rank;
+ break;
+ }
+ }
+
+ for (std::size_t i = 1; i < sbs.m_ranked_points.size(); i++)
{
typename sbs_type::rp const& ranked_point = sbs.m_ranked_points[i];
- if (result && ranked_point.rank > selected_rank)
+ if (ranked_point.rank == selected_rank
+ && ranked_point.direction == sort_by_side::dir_to)
{
- return result;
+ turn_index = ranked_point.turn_index;
+ op_index = ranked_point.operation_index;
+
+ turn_type const& turn = m_turns[turn_index];
+ turn_operation_type const& op = turn.operations[op_index];
+
+ if (op.enriched.count_left == 0
+ && op.enriched.count_right > 0
+ && ! op.visited.finalized())
+ {
+ // In some cases interior rings might be generated with polygons
+ // on both sides
+
+ // TODO: this should be finetuned such that checking
+ // finalized is not necessary
+ return true;
+ }
}
+ }
+ return false;
+ }
- turn_type const& ranked_turn = m_turns[ranked_point.turn_index];
- turn_operation_type const& ranked_op = ranked_turn.operations[ranked_point.operation_index];
- if (result && ranked_op.visited.finalized())
+ inline bool all_operations_of_type(sort_by_side::rank_with_rings const& rwr,
+ operation_type op_type,
+ sort_by_side::direction_type dir) const
+ {
+ typedef std::set<sort_by_side::ring_with_direction>::const_iterator sit_type;
+ for (sit_type it = rwr.rings.begin(); it != rwr.rings.end(); ++it)
+ {
+ sort_by_side::ring_with_direction const& rwd = *it;
+ if (rwd.direction != dir)
{
- // One of the arcs in the same direction as the selected result
- // is already traversed.
return false;
}
-
- if (! is_touching && ranked_op.visited.finalized())
+ turn_type const& turn = m_turns[rwd.turn_index];
+ if (! turn.both(op_type))
{
- // Skip this one, go to next
- min_rank = ranked_point.rank;
- continue;
+ return false;
}
- if (ranked_point.direction == sort_by_side::dir_to
- && (ranked_point.rank > min_rank
- || ranked_turn.both(operation_continue)))
+ // Check if this is not yet taken
+ turn_operation_type const& op = turn.operations[rwd.operation_index];
+ if (op.visited.finalized())
{
- if (ranked_op.enriched.count_left == 0
- && ranked_op.enriched.count_right > 0)
- {
- if (result && ranked_point.turn_index != start_turn_index)
- {
- // Don't override - only override if arrive at start
- continue;
- }
-
- turn_index = ranked_point.turn_index;
- op_index = ranked_point.operation_index;
-
- result = true;
- selected_rank = ranked_point.rank;
- }
- else if (! is_touching)
- {
- return result;
- }
+ return false;
}
+
}
- return result;
+ return true;
}
inline bool analyze_cluster_intersection(signed_size_type& turn_index,
- int& op_index,
- sbs_type const& sbs) const
+ int& op_index, sbs_type const& sbs) const
{
std::vector<sort_by_side::rank_with_rings> aggregation;
- sort_by_side::aggregate_operations(sbs, aggregation);
+ sort_by_side::aggregate_operations(sbs, aggregation, m_turns, operation_intersection);
std::size_t selected_rank = 0;
- for (std::size_t i = 0; i < aggregation.size(); i++)
+
+ // Detect specific pattern(s)
+ bool const detected
+ = intersection_pattern_common_interior1(selected_rank, aggregation)
+ || intersection_pattern_common_interior2(selected_rank, aggregation)
+ || intersection_pattern_common_interior3(selected_rank, aggregation)
+ || intersection_pattern_common_interior4(selected_rank, aggregation)
+ ;
+
+ if (! detected)
{
- sort_by_side::rank_with_rings const& rwr = aggregation[i];
+ int incoming_region_id = 0;
+ std::set<int> outgoing_region_ids;
- if (i > 1
- && i - 1 == selected_rank
- && rwr.rings.size() == 1)
+ for (std::size_t i = 0; i < aggregation.size(); i++)
{
- sort_by_side::ring_with_direction const& rwd = *rwr.rings.begin();
+ sort_by_side::rank_with_rings const& rwr = aggregation[i];
- if (rwd.only_turn_on_ring)
+ if (rwr.all_to()
+ && rwr.traversable(m_turns)
+ && selected_rank == 0)
{
- // Find if this arriving ring was leaving previously
- sort_by_side::ring_with_direction leaving = rwd;
- leaving.direction = sort_by_side::dir_to;
-
- sort_by_side::rank_with_rings const& previous = aggregation[i - 1];
+ // Take the first (= right) where segments leave,
+ // having the polygon on the right side
+ selected_rank = rwr.rank;
+ }
- if (previous.rings.size() == 1
- && previous.rings.count(leaving) == 1)
- {
- // It arrives back - if this is one of the selected, unselect it
- selected_rank = 0;
- }
+ if (rwr.all_from()
+ && selected_rank > 0
+ && outgoing_region_ids.empty())
+ {
+ // Incoming
+ break;
}
- }
- if (rwr.all_to())
- {
- if (selected_rank == 0)
+ if (incoming_region_id == 0)
{
- // Take the first (= right) where segments leave,
- // having the polygon on the right side
- selected_rank = rwr.rank;
+ sort_by_side::ring_with_direction const& rwd = *rwr.rings.begin();
+ turn_type const& turn = m_turns[rwd.turn_index];
+ incoming_region_id = turn.operations[rwd.operation_index].enriched.region_id;
+ }
+ else
+ {
+ if (rwr.rings.size() == 1)
+ {
+ sort_by_side::ring_with_direction const& rwd = *rwr.rings.begin();
+ turn_type const& turn = m_turns[rwd.turn_index];
+ if (rwd.direction == sort_by_side::dir_to
+ && turn.both(operation_intersection))
+ {
+
+ turn_operation_type const& op = turn.operations[rwd.operation_index];
+ if (op.enriched.region_id != incoming_region_id
+ && op.enriched.isolated)
+ {
+ outgoing_region_ids.insert(op.enriched.region_id);
+ }
+ }
+ else if (! outgoing_region_ids.empty())
+ {
+ for (int i = 0; i < 2; i++)
+ {
+ int const region_id = turn.operations[i].enriched.region_id;
+ if (outgoing_region_ids.count(region_id) == 1)
+ {
+ selected_rank = 0;
+ outgoing_region_ids.erase(region_id);
+ }
+ }
+ }
+ }
}
}
}
@@ -458,7 +559,7 @@ struct traversal
{
// This direction is already traveled before, the same
// cannot be traveled again
- return false;
+ continue;
}
// Take the last turn from this rank
@@ -479,10 +580,9 @@ struct traversal
}
inline bool select_turn_from_cluster(signed_size_type& turn_index,
- int& op_index, bool& is_touching,
+ int& op_index,
signed_size_type start_turn_index,
- segment_identifier const& previous_seg_id,
- bool is_start) const
+ segment_identifier const& previous_seg_id) const
{
bool const is_union = target_operation == operation_union;
@@ -495,15 +595,14 @@ struct traversal
cluster_info const& cinfo = mit->second;
std::set<signed_size_type> const& ids = cinfo.turn_indices;
- sbs_type sbs;
-
- bool has_origin = false;
+ sbs_type sbs(m_strategy);
for (typename std::set<signed_size_type>::const_iterator sit = ids.begin();
sit != ids.end(); ++sit)
{
signed_size_type cluster_turn_index = *sit;
turn_type const& cluster_turn = m_turns[cluster_turn_index];
+ bool const departure_turn = cluster_turn_index == turn_index;
if (cluster_turn.discarded)
{
// Defensive check, discarded turns should not be in cluster
@@ -512,79 +611,27 @@ struct traversal
for (int i = 0; i < 2; i++)
{
- turn_operation_type const& op = cluster_turn.operations[i];
- bool is_origin = false;
- if (cluster_turn_index == turn_index)
- {
- // Check if this is the origin
- if (OverlayType == overlay_buffer)
- {
- is_origin = op.seg_id.multi_index == previous_seg_id.multi_index;
- }
- else
- {
- is_origin = op.seg_id.source_index
- == previous_seg_id.source_index;
- }
- if (is_origin)
- {
- has_origin = true;
- }
- }
-
- sbs.add(op, cluster_turn_index, i, m_geometry1, m_geometry2,
- is_origin);
+ sbs.add(cluster_turn.operations[i],
+ cluster_turn_index, i, previous_seg_id,
+ m_geometry1, m_geometry2,
+ departure_turn);
}
}
- if (! has_origin)
+ if (! sbs.has_origin())
{
return false;
}
-
sbs.apply(turn.point);
bool result = false;
if (is_union)
{
- #if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR)
- is_touching = cinfo.open_count > 1;
- if (is_touching)
- {
- if (cinfo.switch_source)
- {
- is_touching = false;
- std::cout << "CLUSTER: SWITCH SOURCES at " << turn_index << std::endl;
- }
- else
- {
- std::cout << "CLUSTER: CONTINUE at " << turn_index << std::endl;
- }
- }
- #else
- is_touching = cinfo.open_count > 1 && ! cinfo.switch_source;
- #endif
-
- if (is_touching)
- {
- sbs.reverse();
- }
-
- result = select_from_cluster_union(turn_index, op_index, start_turn_index, sbs,
- is_touching);
+ result = select_from_cluster_union(turn_index, op_index, sbs);
}
else
{
- if (is_start
- && turn.both(operation_intersection)
- && turn.operations[op_index].enriched.only_turn_on_ring)
- {
- // For an ii (usually interior ring), only turn on ring,
- // reverse to take first exit
- sbs.reverse();
- }
-
result = analyze_cluster_intersection(turn_index, op_index, sbs);
}
return result;
@@ -594,26 +641,27 @@ struct traversal
turn_type const& current_turn,
segment_identifier const& previous_seg_id)
{
- sbs_type sbs;
+ sbs_type sbs(m_strategy);
// Add this turn to the sort-by-side sorter
- bool has_origin = false;
for (int i = 0; i < 2; i++)
{
- turn_operation_type const& op = current_turn.operations[i];
- bool const is_origin = op.seg_id.source_index
- == previous_seg_id.source_index;
- has_origin = has_origin || is_origin;
- sbs.add(op, turn_index, i, m_geometry1, m_geometry2, is_origin);
+ sbs.add(current_turn.operations[i],
+ turn_index, i, previous_seg_id,
+ m_geometry1, m_geometry2,
+ true);
}
- if (! has_origin)
+ if (! sbs.has_origin())
{
return false;
}
sbs.apply(current_turn.point);
- return analyze_cluster_intersection(turn_index, op_index, sbs);
+
+ bool result = analyze_cluster_intersection(turn_index, op_index, sbs);
+
+ return result;
}
inline void change_index_for_self_turn(signed_size_type& to_vertex_index,
@@ -712,7 +760,6 @@ struct traversal
bool select_turn(signed_size_type start_turn_index, int start_op_index,
signed_size_type& turn_index,
int& op_index,
- bool& is_touching,
int previous_op_index,
signed_size_type previous_turn_index,
segment_identifier const& previous_seg_id,
@@ -737,8 +784,8 @@ struct traversal
if (current_turn.cluster_id < 0
&& current_turn.both(operation_intersection))
{
- if (analyze_ii_intersection(turn_index, op_index, current_turn,
- previous_seg_id))
+ if (analyze_ii_intersection(turn_index, op_index,
+ current_turn, previous_seg_id))
{
return true;
}
@@ -747,8 +794,8 @@ struct traversal
if (current_turn.cluster_id >= 0)
{
- if (! select_turn_from_cluster(turn_index, op_index, is_touching,
- start_turn_index, previous_seg_id, is_start))
+ if (! select_turn_from_cluster(turn_index, op_index,
+ start_turn_index, previous_seg_id))
{
return false;
}
@@ -786,6 +833,7 @@ private :
Turns& m_turns;
Clusters const& m_clusters;
RobustPolicy const& m_robust_policy;
+ SideStrategy m_strategy;
Visitor& m_visitor;
};
diff --git a/boost/geometry/algorithms/detail/overlay/traversal_intersection_patterns.hpp b/boost/geometry/algorithms/detail/overlay/traversal_intersection_patterns.hpp
new file mode 100644
index 0000000000..12279d762f
--- /dev/null
+++ b/boost/geometry/algorithms/detail/overlay/traversal_intersection_patterns.hpp
@@ -0,0 +1,306 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2017 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_INTERSECTION_PATTERNS_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_INTERSECTION_PATTERNS_HPP
+
+#include <cstddef>
+#include <vector>
+
+#include <boost/geometry/algorithms/detail/overlay/aggregate_operations.hpp>
+#include <boost/geometry/algorithms/detail/overlay/sort_by_side.hpp>
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace overlay
+{
+
+inline bool check_pairs(std::vector<sort_by_side::rank_with_rings> const& aggregation,
+ signed_size_type incoming_region_id,
+ std::size_t first, std::size_t last)
+{
+ // Check if pairs 1,2 (and possibly 3,4 and 5,6 etc) satisfy
+
+ for (std::size_t i = first; i <= last; i += 2)
+ {
+ sort_by_side::rank_with_rings const& curr = aggregation[i];
+ sort_by_side::rank_with_rings const& next = aggregation[i + 1];
+ int const curr_id = curr.region_id();
+ int const next_id = next.region_id();
+
+ bool const possible =
+ curr.rings.size() == 2
+ && curr.is_isolated()
+ && curr.has_unique_region_id()
+ && next.rings.size() == 2
+ && next.is_isolated()
+ && next.has_unique_region_id()
+ && curr_id == next_id
+ && curr_id != incoming_region_id;
+
+ if (! possible)
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+inline bool intersection_pattern_common_interior1(std::size_t& selected_rank,
+ std::vector<sort_by_side::rank_with_rings> const& aggregation)
+{
+ // Pattern: coming from exterior ring, encountering an isolated
+ // parallel interior ring, which should be skipped, and the first
+ // left (normally intersection takes first right) should be taken.
+ // Solves cases #case_133_multi
+ // and #case_recursive_boxes_49
+
+ std::size_t const n = aggregation.size();
+ if (n < 4)
+ {
+ return false;
+ }
+
+ sort_by_side::rank_with_rings const& incoming = aggregation.front();
+ sort_by_side::rank_with_rings const& outgoing = aggregation.back();
+
+ bool const incoming_ok =
+ incoming.all_from()
+ && incoming.rings.size() == 1
+ && incoming.has_only(operation_intersection);
+
+ if (! incoming_ok)
+ {
+ return false;
+ }
+
+ bool const outgoing_ok =
+ outgoing.all_to()
+ && outgoing.rings.size() == 1
+ && outgoing.has_only(operation_intersection)
+ && outgoing.region_id() == incoming.region_id();
+
+ if (! outgoing_ok)
+ {
+ return false;
+ }
+
+ if (check_pairs(aggregation, incoming.region_id(), 1, n - 2))
+ {
+ selected_rank = n - 1;
+ return true;
+ }
+ return false;
+}
+
+inline bool intersection_pattern_common_interior2(std::size_t& selected_rank,
+ std::vector<sort_by_side::rank_with_rings> const& aggregation)
+{
+ // Pattern: coming from two exterior rings, encountering two isolated
+ // equal interior rings
+
+ // See (for example, for ii) #case_recursive_boxes_53:
+
+ // INCOMING:
+ // Rank 0 {11[0] (s:0, m:0) i F rgn: 1 ISO} {13[1] (s:1, m:0) i F rgn: 1 ISO}
+
+ // PAIR:
+ // Rank 1 {13[0] (s:0, r:1, m:0) i T rgn: 3 ISO ->16} {11[1] (s:1, r:5, m:0) i T rgn: 3 ISO ->16}
+ // Rank 2 {13[0] (s:0, r:1, m:0) i F rgn: 3 ISO} {11[1] (s:1, r:5, m:0) i F rgn: 3 ISO}
+
+ // LEAVING (in the same direction, take last one)
+ // Rank 3 {11[0] (s:0, m:0) i T rgn: 1 ISO ->10} {13[1] (s:1, m:0) i T rgn: 1 ISO ->10}
+
+
+ std::size_t const n = aggregation.size();
+ if (n < 4)
+ {
+ return false;
+ }
+
+ sort_by_side::rank_with_rings const& incoming = aggregation.front();
+ sort_by_side::rank_with_rings const& outgoing = aggregation.back();
+
+ bool const incoming_ok =
+ incoming.all_from()
+ && incoming.rings.size() == 2
+ && incoming.has_unique_region_id();
+
+ if (! incoming_ok)
+ {
+ return false;
+ }
+
+ bool const outgoing_ok =
+ outgoing.all_to()
+ && outgoing.rings.size() == 2
+ && outgoing.has_unique_region_id()
+ && outgoing.region_id() == incoming.region_id();
+
+ if (! outgoing_ok)
+ {
+ return false;
+ }
+
+ bool const operation_ok =
+ (incoming.has_only(operation_continue) && outgoing.has_only(operation_continue))
+ || (incoming.has_only(operation_intersection) && outgoing.has_only(operation_intersection));
+
+ if (! operation_ok)
+ {
+ return false;
+ }
+
+ // Check if pairs 1,2 (and possibly 3,4 and 5,6 etc) satisfy
+ if (check_pairs(aggregation, incoming.region_id(), 1, n - 2))
+ {
+ selected_rank = n - 1;
+ return true;
+ }
+ return false;
+}
+
+inline bool intersection_pattern_common_interior3(std::size_t& selected_rank,
+ std::vector<sort_by_side::rank_with_rings> const& aggregation)
+{
+ // Pattern: approaches colocated turn (exterior+interior) from two
+ // different directions, and both leaves in the same direction
+
+ // See #case_136_multi:
+ // INCOMING:
+ //Rank 0 {10[0] (s:0, m:0) c F rgn: 1 ISO}
+
+ // PAIR:
+ //Rank 1 {14[0] (s:0, r:0, m:0) i T rgn: 2 ISO ->16} {11[1] (s:1, r:1, m:0) i T rgn: 2 ISO ->16}
+ //Rank 2 {14[0] (s:0, r:0, m:0) i F rgn: 2 ISO} {11[1] (s:1, r:1, m:0) i F rgn: 2 ISO}
+
+ // LEAVING (select this one):
+ //Rank 3 {10[0] (s:0, m:0) c T rgn: 1 ISO ->12} {10[1] (s:1, m:0) c T rgn: 1 ISO ->12}
+
+ // ADDITIONALLY: (other polygon coming in)
+ //Rank 4 {10[1] (s:1, m:0) c F rgn: 1 ISO}
+
+ std::size_t const n = aggregation.size();
+ if (n < 4)
+ {
+ return false;
+ }
+
+ sort_by_side::rank_with_rings const& incoming = aggregation.front();
+ sort_by_side::rank_with_rings const& outgoing = aggregation[n - 2];
+ sort_by_side::rank_with_rings const& last = aggregation.back();
+
+ bool const incoming_ok =
+ incoming.all_from()
+ && incoming.rings.size() == 1
+ && incoming.has_only(operation_continue);
+
+ if (! incoming_ok)
+ {
+ return false;
+ }
+
+ bool const outgoing_ok =
+ outgoing.all_to()
+ && outgoing.rings.size() == 2
+ && outgoing.has_only(operation_continue)
+ && outgoing.has_unique_region_id()
+ && outgoing.region_id() == incoming.region_id()
+ && last.all_from()
+ && last.rings.size() == 1
+ && last.region_id() == incoming.region_id()
+ && last.all_from();
+
+ if (! outgoing_ok)
+ {
+ return false;
+ }
+
+ // Check if pairs 1,2 (and possibly 3,4 and 5,6 etc) satisfy
+ if (check_pairs(aggregation, incoming.region_id(), 1, n - 3))
+ {
+ selected_rank = n - 2;
+ return true;
+ }
+ return false;
+}
+
+
+inline bool intersection_pattern_common_interior4(std::size_t& selected_rank,
+ std::vector<sort_by_side::rank_with_rings> const& aggregation)
+{
+ // Pattern: approaches colocated turn (exterior+interior) from same
+ // direction, but leaves in two different directions
+
+ // See #case_137_multi:
+
+ // INCOMING:
+ //Rank 0 {11[0] (s:0, m:0) i F rgn: 1 ISO} {10[1] (s:1, m:0) i F rgn: 1 ISO}
+
+ // PAIR:
+ //Rank 1 {13[0] (s:0, r:0, m:0) i T rgn: 2 ISO ->15} {11[1] (s:1, r:1, m:0) i T rgn: 2 ISO ->15}
+ //Rank 2 {13[0] (s:0, r:0, m:0) i F rgn: 2 ISO} {11[1] (s:1, r:1, m:0) i F rgn: 2 ISO}
+
+ // LEAVING (in two different directions, take last one)
+ //Rank 3 {10[1] (s:1, m:0) i T rgn: 1 ISO ->0}
+ //Rank 4 {11[0] (s:0, m:0) i T rgn: 1 ISO ->12}
+
+ std::size_t const n = aggregation.size();
+ if (n < 4)
+ {
+ return false;
+ }
+
+ sort_by_side::rank_with_rings const& incoming = aggregation.front();
+ sort_by_side::rank_with_rings const& extra = aggregation[n - 2];
+ sort_by_side::rank_with_rings const& outgoing = aggregation.back();
+
+ bool const incoming_ok =
+ incoming.all_from()
+ && incoming.rings.size() == 2
+ && incoming.has_unique_region_id()
+ && incoming.has_only(operation_intersection);
+
+ if (! incoming_ok)
+ {
+ return false;
+ }
+
+ bool const outgoing_ok =
+ outgoing.all_to()
+ && outgoing.rings.size() == 1
+ && outgoing.has_only(operation_intersection)
+ && outgoing.region_id() == incoming.region_id()
+ && extra.all_to()
+ && extra.rings.size() == 1
+ && extra.has_only(operation_intersection)
+ && extra.region_id() == incoming.region_id();
+
+ if (! outgoing_ok)
+ {
+ return false;
+ }
+
+ // Check if pairs 1,2 (and possibly 3,4 and 5,6 etc) satisfy
+ if (check_pairs(aggregation, incoming.region_id(), 1, n - 3))
+ {
+ selected_rank = n - 1;
+ return true;
+ }
+ return false;
+}
+
+}} // namespace detail::overlay
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_INTERSECTION_PATTERNS_HPP
diff --git a/boost/geometry/algorithms/detail/overlay/traversal_ring_creator.hpp b/boost/geometry/algorithms/detail/overlay/traversal_ring_creator.hpp
index 9ab82a77c1..af643a822b 100644
--- a/boost/geometry/algorithms/detail/overlay/traversal_ring_creator.hpp
+++ b/boost/geometry/algorithms/detail/overlay/traversal_ring_creator.hpp
@@ -49,9 +49,13 @@ template
>
struct traversal_ring_creator
{
- typedef traversal<Reverse1, Reverse2, OverlayType,
- Geometry1, Geometry2, Turns, Clusters, RobustPolicy, Visitor>
- traversal_type;
+ typedef traversal
+ <
+ Reverse1, Reverse2, OverlayType,
+ Geometry1, Geometry2, Turns, Clusters,
+ RobustPolicy, typename IntersectionStrategy::side_strategy_type,
+ Visitor
+ > traversal_type;
typedef typename boost::range_value<Turns>::type turn_type;
typedef typename turn_type::turn_operation_type turn_operation_type;
@@ -63,7 +67,9 @@ struct traversal_ring_creator
Turns& turns, Clusters const& clusters,
IntersectionStrategy const& intersection_strategy,
RobustPolicy const& robust_policy, Visitor& visitor)
- : m_trav(geometry1, geometry2, turns, clusters, robust_policy,visitor)
+ : m_trav(geometry1, geometry2, turns, clusters,
+ robust_policy, intersection_strategy.get_side_strategy(),
+ visitor)
, m_geometry1(geometry1)
, m_geometry2(geometry2)
, m_turns(turns)
@@ -103,12 +109,14 @@ struct traversal_ring_creator
{
geometry::copy_segments<Reverse1>(m_geometry1,
previous_op.seg_id, to_vertex_index,
+ m_intersection_strategy.get_side_strategy(),
m_robust_policy, current_ring);
}
else
{
geometry::copy_segments<Reverse2>(m_geometry2,
previous_op.seg_id, to_vertex_index,
+ m_intersection_strategy.get_side_strategy(),
m_robust_policy, current_ring);
}
}
@@ -127,10 +135,8 @@ struct traversal_ring_creator
m_visitor.visit_traverse(m_turns, previous_turn, previous_op, "Start");
}
- bool is_touching = false;
if (! m_trav.select_turn(start_turn_index, start_op_index,
turn_index, op_index,
- is_touching,
previous_op_index, previous_turn_index, previous_seg_id,
is_start))
{
@@ -154,6 +160,7 @@ struct traversal_ring_creator
turn_type& current_turn = m_turns[turn_index];
turn_operation_type& op = current_turn.operations[op_index];
detail::overlay::append_no_dups_or_spikes(current_ring, current_turn.point,
+ m_intersection_strategy.get_side_strategy(),
m_robust_policy);
// Register the visit
@@ -171,6 +178,7 @@ struct traversal_ring_creator
turn_operation_type& start_op = m_turns[start_turn_index].operations[start_op_index];
detail::overlay::append_no_dups_or_spikes(ring, start_turn.point,
+ m_intersection_strategy.get_side_strategy(),
m_robust_policy);
signed_size_type current_turn_index = start_turn_index;
@@ -273,7 +281,9 @@ struct traversal_ring_creator
if (geometry::num_points(ring) >= min_num_points)
{
- clean_closing_dups_and_spikes(ring, m_robust_policy);
+ clean_closing_dups_and_spikes(ring,
+ m_intersection_strategy.get_side_strategy(),
+ m_robust_policy);
rings.push_back(ring);
m_trav.finalize_visit_info();
@@ -307,11 +317,27 @@ struct traversal_ring_creator
continue;
}
- for (int op_index = 0; op_index < 2; op_index++)
+ if (turn.both(operation_continue))
{
+ // Traverse only one turn, the one with the SMALLEST remaining distance
+ // to avoid skipping a turn in between, which can happen in rare cases
+ // (e.g. #130)
+ turn_operation_type const& op0 = turn.operations[0];
+ turn_operation_type const& op1 = turn.operations[1];
+ int const op_index
+ = op0.remaining_distance <= op1.remaining_distance ? 0 : 1;
+
traverse_with_operation(turn, turn_index, op_index,
rings, finalized_ring_size, state);
}
+ else
+ {
+ for (int op_index = 0; op_index < 2; op_index++)
+ {
+ traverse_with_operation(turn, turn_index, op_index,
+ rings, finalized_ring_size, state);
+ }
+ }
}
}
diff --git a/boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp b/boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp
index 183131c74b..0b4f393ef4 100644
--- a/boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp
+++ b/boost/geometry/algorithms/detail/overlay/traversal_switch_detector.hpp
@@ -16,6 +16,7 @@
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
#include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp>
#include <boost/geometry/algorithms/detail/overlay/cluster_info.hpp>
+#include <boost/geometry/algorithms/detail/overlay/is_self_turn.hpp>
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/assert.hpp>
@@ -47,10 +48,54 @@ template
>
struct traversal_switch_detector
{
+ enum isolation_type { isolation_unknown = -1, isolation_no = 0, isolation_yes = 1 };
+
typedef typename boost::range_value<Turns>::type turn_type;
typedef typename turn_type::turn_operation_type turn_operation_type;
- // For convenience
+ // Per ring, first turns are collected (in turn_indices), and later
+ // a region_id is assigned
+ struct merged_ring_properties
+ {
+ signed_size_type region_id;
+ std::set<signed_size_type> turn_indices;
+
+ merged_ring_properties()
+ : region_id(-1)
+ {}
+ };
+
+ struct connection_properties
+ {
+ std::size_t count;
+ std::set<signed_size_type> cluster_indices;
+ connection_properties()
+ : count(0)
+ {}
+ };
+
+ typedef std::map<signed_size_type, connection_properties> connection_map;
+
+ // Per region, a set of properties is maintained, including its connections
+ // to other regions
+ struct region_properties
+ {
+ signed_size_type region_id;
+ isolation_type isolated;
+
+ // Maps from connected region_id to their properties
+ connection_map connected_region_counts;
+
+ region_properties()
+ : region_id(-1)
+ , isolated(isolation_unknown)
+ {}
+ };
+
+ // Keeps turn indices per ring
+ typedef std::map<ring_identifier, merged_ring_properties > merge_map;
+ typedef std::map<signed_size_type, region_properties> region_connection_map;
+
typedef std::set<signed_size_type>::const_iterator set_iterator;
inline traversal_switch_detector(Geometry1 const& geometry1, Geometry2 const& geometry2,
@@ -62,135 +107,309 @@ struct traversal_switch_detector
, m_clusters(clusters)
, m_robust_policy(robust_policy)
, m_visitor(visitor)
- , m_region_id(0)
{
+ }
+
+ isolation_type get_isolation(region_properties const& properties,
+ signed_size_type parent_region_id,
+ const std::set<signed_size_type>& visited)
+ {
+ if (properties.isolated != isolation_unknown)
+ {
+ return properties.isolated;
+ }
+
+ bool all_colocated = true;
+ int unique_cluster_id = -1;
+ for (typename connection_map::const_iterator it = properties.connected_region_counts.begin();
+ all_colocated && it != properties.connected_region_counts.end(); ++it)
+ {
+ connection_properties const& cprop = it->second;
+ if (cprop.cluster_indices.size() != 1)
+ {
+ // Either no cluster (non colocated point), or more clusters
+ all_colocated = false;
+ }
+ int const cluster_id = *cprop.cluster_indices.begin();
+ if (cluster_id == -1)
+ {
+ all_colocated = false;
+ }
+ else if (unique_cluster_id == -1)
+ {
+ unique_cluster_id = cluster_id;
+ }
+ else if (unique_cluster_id != cluster_id)
+ {
+ all_colocated = false;
+ }
+ }
+ if (all_colocated)
+ {
+ return isolation_yes;
+ }
+
+
+ // It is isolated if there is only one connection, or if there are more connections but all
+ // of them are isolated themselves, or if there are more connections
+ // but they are all colocated
+ std::size_t non_isolation_count = 0;
+ bool child_not_isolated = false;
+ for (typename connection_map::const_iterator it = properties.connected_region_counts.begin();
+ it != properties.connected_region_counts.end(); ++it)
+ {
+ signed_size_type const region_id = it->first;
+ connection_properties const& cprop = it->second;
+
+ if (region_id == parent_region_id)
+ {
+ // Normal situation, skip its direct parent
+ continue;
+ }
+ if (visited.count(region_id) > 0)
+ {
+ // Find one of its ancestors again, this is a ring. Not isolated.
+ return isolation_no;
+ }
+ if (cprop.count > 1)
+ {
+ return isolation_no;
+ }
+
+ typename region_connection_map::iterator mit = m_connected_regions.find(region_id);
+ if (mit == m_connected_regions.end())
+ {
+ // Should not occur
+ continue;
+ }
+
+ std::set<signed_size_type> vis = visited;
+ vis.insert(parent_region_id);
+ region_properties& prop = mit->second;
+ if (prop.isolated == isolation_unknown)
+ {
+ isolation_type const iso = get_isolation(prop, properties.region_id, vis);
+ prop.isolated = iso;
+ if (iso == isolation_no)
+ {
+ child_not_isolated = true;
+ }
+ }
+ if (prop.isolated == isolation_no)
+ {
+ non_isolation_count++;
+ }
+ }
+
+ return child_not_isolated || non_isolation_count > 1 ? isolation_no : isolation_yes;
}
- static inline bool connects_same_zone(turn_type const& turn)
+ void get_isolated_regions()
{
+ for (typename region_connection_map::iterator it = m_connected_regions.begin();
+ it != m_connected_regions.end(); ++it)
+ {
+ region_properties& properties = it->second;
+ if (properties.isolated == isolation_unknown)
+ {
+ std::set<signed_size_type> visited;
+ properties.isolated = get_isolation(properties, properties.region_id, visited);
+ }
+ }
+ }
+
+ void assign_isolation()
+ {
+ for (std::size_t turn_index = 0; turn_index < m_turns.size(); ++turn_index)
+ {
+ turn_type& turn = m_turns[turn_index];
+
+ for (int op_index = 0; op_index < 2; op_index++)
+ {
+ turn_operation_type& op = turn.operations[op_index];
+ typename region_connection_map::const_iterator mit = m_connected_regions.find(op.enriched.region_id);
+ if (mit != m_connected_regions.end())
+ {
+ region_properties const& prop = mit->second;
+ op.enriched.isolated = prop.isolated == isolation_yes;
+ }
+ }
+ }
+ }
+
+ void assign_regions()
+ {
+ for (typename merge_map::const_iterator it
+ = m_turns_per_ring.begin(); it != m_turns_per_ring.end(); ++it)
+ {
+ ring_identifier const& ring_id = it->first;
+ merged_ring_properties const& properties = it->second;
+
+ for (set_iterator sit = properties.turn_indices.begin();
+ sit != properties.turn_indices.end(); ++sit)
+ {
+ turn_type& turn = m_turns[*sit];
+
+ for (int i = 0; i < 2; i++)
+ {
+ turn_operation_type& op = turn.operations[i];
+ if (ring_id_by_seg_id(op.seg_id) == ring_id)
+ {
+ op.enriched.region_id = properties.region_id;
+ }
+ }
+ signed_size_type const& id0 = turn.operations[0].enriched.region_id;
+ signed_size_type const& id1 = turn.operations[1].enriched.region_id;
+ if (id0 != id1 && id0 != -1 && id1 != -1)
+ {
+ // Force insertion
+ m_connected_regions[id0].region_id = id0;
+ m_connected_regions[id1].region_id = id1;
+
+ connection_properties& prop0 = m_connected_regions[id0].connected_region_counts[id1];
+ connection_properties& prop1 = m_connected_regions[id1].connected_region_counts[id0];
+
+ if (turn.cluster_id < 0)
+ {
+ // Turn is not colocated, add reference to connection
+ prop0.count++;
+ prop1.count++;
+ }
+ else
+ {
+ // Turn is colocated, only add region reference if it was not yet registered
+ if (prop0.cluster_indices.count(turn.cluster_id) == 0)
+ {
+ prop0.count++;
+ }
+ if (prop1.cluster_indices.count(turn.cluster_id) == 0)
+ {
+ prop1.count++;
+ }
+ }
+ // Insert cluster-id (also -1 is inserted - reinsertion of
+ // same cluster id is OK)
+ prop0.cluster_indices.insert(turn.cluster_id);
+ prop1.cluster_indices.insert(turn.cluster_id);
+ }
+ }
+ }
+ }
+
+ inline bool connects_same_region(turn_type const& turn) const
+ {
+ if (turn.discarded)
+ {
+ // Discarded turns don't connect same region (otherwise discarded colocated uu turn
+ // could make a connection)
+ return false;
+ }
+
if (turn.cluster_id == -1)
{
- // If it is a uu/ii-turn (non clustered), it is never same zone
+ // If it is a uu/ii-turn (non clustered), it is never same region
return ! (turn.both(operation_union) || turn.both(operation_intersection));
}
- // It is a cluster, check zones of both operations
- return turn.operations[0].enriched.zone
- == turn.operations[1].enriched.zone;
+ if (operation_from_overlay<OverlayType>::value == operation_union)
+ {
+ // It is a cluster, check zones
+ // (assigned by sort_by_side/handle colocations) of both operations
+ return turn.operations[0].enriched.zone
+ == turn.operations[1].enriched.zone;
+ }
+
+ // If a cluster contains an ii/cc it is not same region (for intersection)
+ typename Clusters::const_iterator it = m_clusters.find(turn.cluster_id);
+ if (it == m_clusters.end())
+ {
+ // Should not occur
+ return true;
+ }
+
+ cluster_info const& cinfo = it->second;
+ for (set_iterator sit = cinfo.turn_indices.begin();
+ sit != cinfo.turn_indices.end(); ++sit)
+ {
+ turn_type const& cluster_turn = m_turns[*sit];
+ if (cluster_turn.both(operation_union)
+ || cluster_turn.both(operation_intersection))
+ {
+ return false;
+ }
+ }
+
+ // It is the same region
+ return false;
}
+
inline int get_region_id(turn_operation_type const& op) const
{
- std::map<ring_identifier, int>::const_iterator it
- = m_regions.find(ring_id_by_seg_id(op.seg_id));
- return it == m_regions.end() ? -1 : it->second;
+ return op.enriched.region_id;
}
- void create_region(ring_identifier const& ring_id, std::set<signed_size_type> const& ring_turn_indices, int region_id = -1)
+
+ void create_region(signed_size_type& new_region_id, ring_identifier const& ring_id,
+ merged_ring_properties& properties, int region_id = -1)
{
- std::map<ring_identifier, int>::const_iterator it = m_regions.find(ring_id);
- if (it != m_regions.end())
+ if (properties.region_id > 0)
{
- // The ring is already gathered in a region, quit
+ // Already handled
return;
}
+
+ // Assign new id if this is a new region
if (region_id == -1)
{
- region_id = m_region_id++;
+ region_id = new_region_id++;
}
// Assign this ring to specified region
- m_regions[ring_id] = region_id;
+ properties.region_id = region_id;
+
#if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR)
std::cout << " ADD " << ring_id << " TO REGION " << region_id << std::endl;
#endif
// Find connecting rings, recursively
- for (set_iterator sit = ring_turn_indices.begin();
- sit != ring_turn_indices.end(); ++sit)
+ for (set_iterator sit = properties.turn_indices.begin();
+ sit != properties.turn_indices.end(); ++sit)
{
signed_size_type const turn_index = *sit;
turn_type const& turn = m_turns[turn_index];
- if (! connects_same_zone(turn))
+ if (! connects_same_region(turn))
{
// This is a non clustered uu/ii-turn, or a cluster connecting different 'zones'
continue;
}
- // This turn connects two rings (interior connected), create the
- // same region
+ // Union: This turn connects two rings (interior connected), create the region
+ // Intersection: This turn connects two rings, set same regions for these two rings
for (int op_index = 0; op_index < 2; op_index++)
{
turn_operation_type const& op = turn.operations[op_index];
ring_identifier connected_ring_id = ring_id_by_seg_id(op.seg_id);
if (connected_ring_id != ring_id)
{
- propagate_region(connected_ring_id, region_id);
+ propagate_region(new_region_id, connected_ring_id, region_id);
}
}
}
}
- void check_turns_per_ring(ring_identifier const& ring_id,
- std::set<signed_size_type> const& ring_turn_indices)
+ void propagate_region(signed_size_type& new_region_id,
+ ring_identifier const& ring_id, int region_id)
{
- bool only_turn_on_ring = true;
- if (ring_turn_indices.size() > 1)
- {
- // More turns on this ring. Only leave only_turn_on_ring true
- // if they are all of the same cluster
- int cluster_id = -1;
- for (set_iterator sit = ring_turn_indices.begin();
- sit != ring_turn_indices.end(); ++sit)
- {
- turn_type const& turn = m_turns[*sit];
- if (turn.cluster_id == -1)
- {
- // Unclustered turn - and there are 2 or more turns
- // so the ring has different turns
- only_turn_on_ring = false;
- break;
- }
-
- // Clustered turn, check if it is the first or same as previous
- if (cluster_id == -1)
- {
- cluster_id = turn.cluster_id;
- }
- else if (turn.cluster_id != cluster_id)
- {
- only_turn_on_ring = false;
- break;
- }
- }
- }
-
- // Assign result to matching operation (a turn is always on two rings)
- for (set_iterator sit = ring_turn_indices.begin();
- sit != ring_turn_indices.end(); ++sit)
- {
- turn_type& turn = m_turns[*sit];
- for (int i = 0; i < 2; i++)
- {
- turn_operation_type& op = turn.operations[i];
- if (ring_id_by_seg_id(op.seg_id) == ring_id)
- {
- op.enriched.only_turn_on_ring = only_turn_on_ring;
- }
- }
- }
- }
-
- void propagate_region(ring_identifier const& ring_id, int region_id)
- {
- std::map<ring_identifier, std::set<signed_size_type> >::const_iterator it = m_turns_per_ring.find(ring_id);
+ typename merge_map::iterator it = m_turns_per_ring.find(ring_id);
if (it != m_turns_per_ring.end())
{
- create_region(ring_id, it->second, region_id);
+ create_region(new_region_id, ring_id, it->second, region_id);
}
}
+
void iterate()
{
#if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR)
@@ -199,26 +418,38 @@ struct traversal_switch_detector
// Collect turns per ring
m_turns_per_ring.clear();
- m_regions.clear();
- m_region_id = 1;
+ m_connected_regions.clear();
for (std::size_t turn_index = 0; turn_index < m_turns.size(); ++turn_index)
{
turn_type const& turn = m_turns[turn_index];
+ if (turn.discarded
+ && operation_from_overlay<OverlayType>::value == operation_intersection)
+ {
+ // Discarded turn (union currently still needs it to determine regions)
+ continue;
+ }
+
for (int op_index = 0; op_index < 2; op_index++)
{
turn_operation_type const& op = turn.operations[op_index];
- m_turns_per_ring[ring_id_by_seg_id(op.seg_id)].insert(turn_index);
+ m_turns_per_ring[ring_id_by_seg_id(op.seg_id)].turn_indices.insert(turn_index);
}
}
// All rings having turns are in the map. Now iterate them
- for (std::map<ring_identifier, std::set<signed_size_type> >::const_iterator it
- = m_turns_per_ring.begin(); it != m_turns_per_ring.end(); ++it)
{
- create_region(it->first, it->second);
- check_turns_per_ring(it->first, it->second);
+ signed_size_type new_region_id = 1;
+ for (typename merge_map::iterator it
+ = m_turns_per_ring.begin(); it != m_turns_per_ring.end(); ++it)
+ {
+ create_region(new_region_id, it->first, it->second);
+ }
+
+ assign_regions();
+ get_isolated_regions();
+ assign_isolation();
}
// Now that all regions are filled, assign switch_source property
@@ -245,6 +476,10 @@ struct traversal_switch_detector
{
signed_size_type turn_index = *sit;
turn_type const& turn = m_turns[turn_index];
+ if (turn.colocated_ii && ! turn.colocated_uu)
+ {
+ continue;
+ }
for (int oi = 0; oi < 2; oi++)
{
int const region = get_region_id(turn.operations[oi]);
@@ -252,7 +487,7 @@ struct traversal_switch_detector
}
}
// Switch source if this cluster connects the same region
- cinfo.switch_source = regions.size() == 1;
+ cinfo.switch_source = regions.size() <= 1;
}
// Iterate through all uu/ii turns (non-clustered)
@@ -326,13 +561,10 @@ private:
Geometry2 const& m_geometry2;
Turns& m_turns;
Clusters& m_clusters;
+ merge_map m_turns_per_ring;
+ region_connection_map m_connected_regions;
RobustPolicy const& m_robust_policy;
Visitor& m_visitor;
-
- std::map<ring_identifier, int> m_regions;
- std::map<ring_identifier, std::set<signed_size_type> > m_turns_per_ring;
- int m_region_id;
-
};
}} // namespace detail::overlay
diff --git a/boost/geometry/algorithms/detail/overlay/turn_info.hpp b/boost/geometry/algorithms/detail/overlay/turn_info.hpp
index e09af126c6..3a4c2e94a1 100644
--- a/boost/geometry/algorithms/detail/overlay/turn_info.hpp
+++ b/boost/geometry/algorithms/detail/overlay/turn_info.hpp
@@ -89,18 +89,24 @@ struct turn_info
Point point;
method_type method;
+ bool touch_only; // True in case of method touch(interior) and lines do not cross
signed_size_type cluster_id; // For multiple turns on same location, >= 0. Else -1
bool discarded;
- bool colocated;
+
+ // TODO: move this to enriched
+ bool colocated_ii; // Colocated with a ii turn (TODO: or a ix turn)
+ bool colocated_uu; // Colocated with a uu turn or a ux turn
bool switch_source; // For u/u turns which can either switch or not
Container operations;
inline turn_info()
: method(method_none)
+ , touch_only(false)
, cluster_id(-1)
, discarded(false)
- , colocated(false)
+ , colocated_ii(false)
+ , colocated_uu(false)
, switch_source(false)
{}
@@ -133,7 +139,6 @@ struct turn_info
return has(operation_blocked);
}
-
private :
inline bool has12(operation_type type1, operation_type type2) const
{
diff --git a/boost/geometry/algorithms/detail/partition.hpp b/boost/geometry/algorithms/detail/partition.hpp
index 12c6a54661..db134d548d 100644
--- a/boost/geometry/algorithms/detail/partition.hpp
+++ b/boost/geometry/algorithms/detail/partition.hpp
@@ -1,6 +1,7 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2011-2015 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
// This file was modified by Oracle on 2015, 2017.
// Modifications copyright (c) 2015-2017 Oracle and/or its affiliates.
@@ -106,11 +107,11 @@ inline void expand_with_elements(Box& total, IteratorVector const& input,
// Match forward_range with itself
template <typename IteratorVector, typename VisitPolicy>
-inline void handle_one(IteratorVector const& input, VisitPolicy& visitor)
+inline bool handle_one(IteratorVector const& input, VisitPolicy& visitor)
{
- if (boost::size(input) == 0)
+ if (boost::empty(input))
{
- return;
+ return true;
}
typedef typename boost::range_iterator<IteratorVector const>::type it_type;
@@ -121,9 +122,14 @@ inline void handle_one(IteratorVector const& input, VisitPolicy& visitor)
it_type it2 = it1;
for (++it2; it2 != boost::end(input); ++it2)
{
- visitor.apply(**it1, **it2);
+ if (! visitor.apply(**it1, **it2))
+ {
+ return false; // interrupt
+ }
}
}
+
+ return true;
}
// Match forward range 1 with forward range 2
@@ -133,7 +139,7 @@ template
typename IteratorVector2,
typename VisitPolicy
>
-inline void handle_two(IteratorVector1 const& input1,
+inline bool handle_two(IteratorVector1 const& input1,
IteratorVector2 const& input2,
VisitPolicy& visitor)
{
@@ -147,9 +153,9 @@ inline void handle_two(IteratorVector1 const& input1,
IteratorVector2 const
>::type iterator_type2;
- if (boost::size(input1) == 0 || boost::size(input2) == 0)
+ if (boost::empty(input1) || boost::empty(input2))
{
- return;
+ return true;
}
for(iterator_type1 it1 = boost::begin(input1);
@@ -160,9 +166,14 @@ inline void handle_two(IteratorVector1 const& input1,
it2 != boost::end(input2);
++it2)
{
- visitor.apply(**it1, **it2);
+ if (! visitor.apply(**it1, **it2))
+ {
+ return false; // interrupt
+ }
}
}
+
+ return true;
}
template <typename IteratorVector>
@@ -223,7 +234,7 @@ class partition_one_range
typename OverlapsPolicy,
typename VisitBoxPolicy
>
- static inline void next_level(Box const& box,
+ static inline bool next_level(Box const& box,
IteratorVector const& input,
std::size_t level, std::size_t min_elements,
VisitPolicy& visitor,
@@ -233,7 +244,7 @@ class partition_one_range
{
if (recurse_ok(input, min_elements, level))
{
- partition_one_range
+ return partition_one_range
<
1 - Dimension,
Box
@@ -242,7 +253,7 @@ class partition_one_range
}
else
{
- handle_one(input, visitor);
+ return handle_one(input, visitor);
}
}
@@ -256,18 +267,18 @@ class partition_one_range
typename OverlapsPolicy,
typename VisitBoxPolicy
>
- static inline void next_level2(Box const& box,
- IteratorVector const& input1,
- IteratorVector const& input2,
- std::size_t level, std::size_t min_elements,
- VisitPolicy& visitor,
- ExpandPolicy const& expand_policy,
- OverlapsPolicy const& overlaps_policy,
- VisitBoxPolicy& box_policy)
+ static inline bool next_level2(Box const& box,
+ IteratorVector const& input1,
+ IteratorVector const& input2,
+ std::size_t level, std::size_t min_elements,
+ VisitPolicy& visitor,
+ ExpandPolicy const& expand_policy,
+ OverlapsPolicy const& overlaps_policy,
+ VisitBoxPolicy& box_policy)
{
if (recurse_ok(input1, input2, min_elements, level))
{
- partition_two_ranges
+ return partition_two_ranges
<
1 - Dimension, Box
>::apply(box, input1, input2, level + 1, min_elements,
@@ -276,7 +287,7 @@ class partition_one_range
}
else
{
- handle_two(input1, input2, visitor);
+ return handle_two(input1, input2, visitor);
}
}
@@ -289,7 +300,7 @@ public :
typename OverlapsPolicy,
typename VisitBoxPolicy
>
- static inline void apply(Box const& box,
+ static inline bool apply(Box const& box,
IteratorVector const& input,
std::size_t level,
std::size_t min_elements,
@@ -308,29 +319,31 @@ public :
input, lower, upper, exceeding,
overlaps_policy);
- if (boost::size(exceeding) > 0)
+ if (! boost::empty(exceeding))
{
// Get the box of exceeding-only
Box exceeding_box = get_new_box(exceeding, expand_policy);
- // Recursively do exceeding elements only, in next dimension they
- // will probably be less exceeding within the new box
- next_level(exceeding_box, exceeding, level, min_elements,
- visitor, expand_policy, overlaps_policy, box_policy);
-
- // Switch to two forward ranges, combine exceeding with
- // lower resp upper, but not lower/lower, upper/upper
- next_level2(exceeding_box, exceeding, lower, level, min_elements,
- visitor, expand_policy, overlaps_policy, box_policy);
- next_level2(exceeding_box, exceeding, upper, level, min_elements,
- visitor, expand_policy, overlaps_policy, box_policy);
+ // Recursively do exceeding elements only, in next dimension they
+ // will probably be less exceeding within the new box
+ if (! (next_level(exceeding_box, exceeding, level, min_elements,
+ visitor, expand_policy, overlaps_policy, box_policy)
+ // Switch to two forward ranges, combine exceeding with
+ // lower resp upper, but not lower/lower, upper/upper
+ && next_level2(exceeding_box, exceeding, lower, level, min_elements,
+ visitor, expand_policy, overlaps_policy, box_policy)
+ && next_level2(exceeding_box, exceeding, upper, level, min_elements,
+ visitor, expand_policy, overlaps_policy, box_policy)) )
+ {
+ return false; // interrupt
+ }
}
// Recursively call operation both parts
- next_level(lower_box, lower, level, min_elements,
- visitor, expand_policy, overlaps_policy, box_policy);
- next_level(upper_box, upper, level, min_elements,
- visitor, expand_policy, overlaps_policy, box_policy);
+ return next_level(lower_box, lower, level, min_elements,
+ visitor, expand_policy, overlaps_policy, box_policy)
+ && next_level(upper_box, upper, level, min_elements,
+ visitor, expand_policy, overlaps_policy, box_policy);
}
};
@@ -352,23 +365,23 @@ class partition_two_ranges
typename OverlapsPolicy2,
typename VisitBoxPolicy
>
- static inline void next_level(Box const& box,
- IteratorVector1 const& input1,
- IteratorVector2 const& input2,
- std::size_t level, std::size_t min_elements,
- VisitPolicy& visitor,
- ExpandPolicy1 const& expand_policy1,
- OverlapsPolicy1 const& overlaps_policy1,
- ExpandPolicy2 const& expand_policy2,
- OverlapsPolicy2 const& overlaps_policy2,
- VisitBoxPolicy& box_policy)
+ static inline bool next_level(Box const& box,
+ IteratorVector1 const& input1,
+ IteratorVector2 const& input2,
+ std::size_t level, std::size_t min_elements,
+ VisitPolicy& visitor,
+ ExpandPolicy1 const& expand_policy1,
+ OverlapsPolicy1 const& overlaps_policy1,
+ ExpandPolicy2 const& expand_policy2,
+ OverlapsPolicy2 const& overlaps_policy2,
+ VisitBoxPolicy& box_policy)
{
- partition_two_ranges
- <
- 1 - Dimension, Box
- >::apply(box, input1, input2, level + 1, min_elements,
- visitor, expand_policy1, overlaps_policy1,
- expand_policy2, overlaps_policy2, box_policy);
+ return partition_two_ranges
+ <
+ 1 - Dimension, Box
+ >::apply(box, input1, input2, level + 1, min_elements,
+ visitor, expand_policy1, overlaps_policy1,
+ expand_policy2, overlaps_policy2, box_policy);
}
template <typename IteratorVector, typename ExpandPolicy>
@@ -408,17 +421,17 @@ public :
typename OverlapsPolicy2,
typename VisitBoxPolicy
>
- static inline void apply(Box const& box,
- IteratorVector1 const& input1,
- IteratorVector2 const& input2,
- std::size_t level,
- std::size_t min_elements,
- VisitPolicy& visitor,
- ExpandPolicy1 const& expand_policy1,
- OverlapsPolicy1 const& overlaps_policy1,
- ExpandPolicy2 const& expand_policy2,
- OverlapsPolicy2 const& overlaps_policy2,
- VisitBoxPolicy& box_policy)
+ static inline bool apply(Box const& box,
+ IteratorVector1 const& input1,
+ IteratorVector2 const& input2,
+ std::size_t level,
+ std::size_t min_elements,
+ VisitPolicy& visitor,
+ ExpandPolicy1 const& expand_policy1,
+ OverlapsPolicy1 const& overlaps_policy1,
+ ExpandPolicy2 const& expand_policy2,
+ OverlapsPolicy2 const& overlaps_policy2,
+ VisitBoxPolicy& box_policy)
{
box_policy.apply(box, level);
@@ -434,7 +447,7 @@ public :
input2, lower2, upper2, exceeding2,
overlaps_policy2);
- if (boost::size(exceeding1) > 0)
+ if (! boost::empty(exceeding1))
{
// All exceeding from 1 with 2:
@@ -442,13 +455,19 @@ public :
{
Box exceeding_box = get_new_box(exceeding1, exceeding2,
expand_policy1, expand_policy2);
- next_level(exceeding_box, exceeding1, exceeding2, level,
- min_elements, visitor, expand_policy1, overlaps_policy1,
- expand_policy2, overlaps_policy2, box_policy);
+ if (! next_level(exceeding_box, exceeding1, exceeding2, level,
+ min_elements, visitor, expand_policy1, overlaps_policy1,
+ expand_policy2, overlaps_policy2, box_policy))
+ {
+ return false; // interrupt
+ }
}
else
{
- handle_two(exceeding1, exceeding2, visitor);
+ if (! handle_two(exceeding1, exceeding2, visitor))
+ {
+ return false; // interrupt
+ }
}
// All exceeding from 1 with lower and upper of 2:
@@ -458,60 +477,87 @@ public :
if (recurse_ok(lower2, upper2, exceeding1, min_elements, level))
{
Box exceeding_box = get_new_box(exceeding1, expand_policy1);
- next_level(exceeding_box, exceeding1, lower2, level,
- min_elements, visitor, expand_policy1, overlaps_policy1,
- expand_policy2, overlaps_policy2, box_policy);
- next_level(exceeding_box, exceeding1, upper2, level,
- min_elements, visitor, expand_policy1, overlaps_policy1,
- expand_policy2, overlaps_policy2, box_policy);
+ if (! (next_level(exceeding_box, exceeding1, lower2, level,
+ min_elements, visitor, expand_policy1, overlaps_policy1,
+ expand_policy2, overlaps_policy2, box_policy)
+ && next_level(exceeding_box, exceeding1, upper2, level,
+ min_elements, visitor, expand_policy1, overlaps_policy1,
+ expand_policy2, overlaps_policy2, box_policy)) )
+ {
+ return false; // interrupt
+ }
}
else
{
- handle_two(exceeding1, lower2, visitor);
- handle_two(exceeding1, upper2, visitor);
+ if (! (handle_two(exceeding1, lower2, visitor)
+ && handle_two(exceeding1, upper2, visitor)) )
+ {
+ return false; // interrupt
+ }
}
}
- if (boost::size(exceeding2) > 0)
+ if (! boost::empty(exceeding2))
{
// All exceeding from 2 with lower and upper of 1:
if (recurse_ok(lower1, upper1, exceeding2, min_elements, level))
{
Box exceeding_box = get_new_box(exceeding2, expand_policy2);
- next_level(exceeding_box, lower1, exceeding2, level,
- min_elements, visitor, expand_policy1, overlaps_policy1,
- expand_policy2, overlaps_policy2, box_policy);
- next_level(exceeding_box, upper1, exceeding2, level,
- min_elements, visitor, expand_policy1, overlaps_policy1,
- expand_policy2, overlaps_policy2, box_policy);
+ if (! (next_level(exceeding_box, lower1, exceeding2, level,
+ min_elements, visitor, expand_policy1, overlaps_policy1,
+ expand_policy2, overlaps_policy2, box_policy)
+ && next_level(exceeding_box, upper1, exceeding2, level,
+ min_elements, visitor, expand_policy1, overlaps_policy1,
+ expand_policy2, overlaps_policy2, box_policy)) )
+ {
+ return false; // interrupt
+ }
}
else
{
- handle_two(lower1, exceeding2, visitor);
- handle_two(upper1, exceeding2, visitor);
+ if (! (handle_two(lower1, exceeding2, visitor)
+ && handle_two(upper1, exceeding2, visitor)) )
+ {
+ return false; // interrupt
+ }
}
}
if (recurse_ok(lower1, lower2, min_elements, level))
{
- next_level(lower_box, lower1, lower2, level,
- min_elements, visitor, expand_policy1, overlaps_policy1,
- expand_policy2, overlaps_policy2, box_policy);
+ if (! next_level(lower_box, lower1, lower2, level,
+ min_elements, visitor, expand_policy1, overlaps_policy1,
+ expand_policy2, overlaps_policy2, box_policy) )
+ {
+ return false; // interrupt
+ }
}
else
{
- handle_two(lower1, lower2, visitor);
+ if (! handle_two(lower1, lower2, visitor))
+ {
+ return false; // interrupt
+ }
}
+
if (recurse_ok(upper1, upper2, min_elements, level))
{
- next_level(upper_box, upper1, upper2, level,
- min_elements, visitor, expand_policy1, overlaps_policy1,
- expand_policy2, overlaps_policy2, box_policy);
+ if (! next_level(upper_box, upper1, upper2, level,
+ min_elements, visitor, expand_policy1, overlaps_policy1,
+ expand_policy2, overlaps_policy2, box_policy) )
+ {
+ return false; // interrupt
+ }
}
else
{
- handle_two(upper1, upper2, visitor);
+ if (! handle_two(upper1, upper2, visitor))
+ {
+ return false; // interrupt
+ }
}
+
+ return true;
}
};
@@ -577,13 +623,13 @@ public:
typename ExpandPolicy,
typename OverlapsPolicy
>
- static inline void apply(ForwardRange const& forward_range,
+ static inline bool apply(ForwardRange const& forward_range,
VisitPolicy& visitor,
ExpandPolicy const& expand_policy,
OverlapsPolicy const& overlaps_policy)
{
- apply(forward_range, visitor, expand_policy, overlaps_policy,
- default_min_elements, detail::partition::visit_no_policy());
+ return apply(forward_range, visitor, expand_policy, overlaps_policy,
+ default_min_elements, detail::partition::visit_no_policy());
}
template
@@ -593,14 +639,14 @@ public:
typename ExpandPolicy,
typename OverlapsPolicy
>
- static inline void apply(ForwardRange const& forward_range,
+ static inline bool apply(ForwardRange const& forward_range,
VisitPolicy& visitor,
ExpandPolicy const& expand_policy,
OverlapsPolicy const& overlaps_policy,
std::size_t min_elements)
{
- apply(forward_range, visitor, expand_policy, overlaps_policy,
- min_elements, detail::partition::visit_no_policy());
+ return apply(forward_range, visitor, expand_policy, overlaps_policy,
+ min_elements, detail::partition::visit_no_policy());
}
template
@@ -611,7 +657,7 @@ public:
typename OverlapsPolicy,
typename VisitBoxPolicy
>
- static inline void apply(ForwardRange const& forward_range,
+ static inline bool apply(ForwardRange const& forward_range,
VisitPolicy& visitor,
ExpandPolicy const& expand_policy,
OverlapsPolicy const& overlaps_policy,
@@ -631,7 +677,7 @@ public:
expand_to_range<IncludePolicy1>(forward_range, total,
iterator_vector, expand_policy);
- detail::partition::partition_one_range
+ return detail::partition::partition_one_range
<
0, Box
>::apply(total, iterator_vector, 0, min_elements,
@@ -646,10 +692,15 @@ public:
iterator_type it2 = it1;
for(++it2; it2 != boost::end(forward_range); ++it2)
{
- visitor.apply(*it1, *it2);
+ if (! visitor.apply(*it1, *it2))
+ {
+ return false; // interrupt
+ }
}
}
}
+
+ return true;
}
template
@@ -660,15 +711,15 @@ public:
typename ExpandPolicy1,
typename OverlapsPolicy1
>
- static inline void apply(ForwardRange1 const& forward_range1,
+ static inline bool apply(ForwardRange1 const& forward_range1,
ForwardRange2 const& forward_range2,
VisitPolicy& visitor,
ExpandPolicy1 const& expand_policy1,
OverlapsPolicy1 const& overlaps_policy1)
{
- apply(forward_range1, forward_range2, visitor,
- expand_policy1, overlaps_policy1, expand_policy1, overlaps_policy1,
- default_min_elements, detail::partition::visit_no_policy());
+ return apply(forward_range1, forward_range2, visitor,
+ expand_policy1, overlaps_policy1, expand_policy1, overlaps_policy1,
+ default_min_elements, detail::partition::visit_no_policy());
}
template
@@ -681,7 +732,7 @@ public:
typename ExpandPolicy2,
typename OverlapsPolicy2
>
- static inline void apply(ForwardRange1 const& forward_range1,
+ static inline bool apply(ForwardRange1 const& forward_range1,
ForwardRange2 const& forward_range2,
VisitPolicy& visitor,
ExpandPolicy1 const& expand_policy1,
@@ -689,9 +740,9 @@ public:
ExpandPolicy2 const& expand_policy2,
OverlapsPolicy2 const& overlaps_policy2)
{
- apply(forward_range1, forward_range2, visitor,
- expand_policy1, overlaps_policy1, expand_policy2, overlaps_policy2,
- default_min_elements, detail::partition::visit_no_policy());
+ return apply(forward_range1, forward_range2, visitor,
+ expand_policy1, overlaps_policy1, expand_policy2, overlaps_policy2,
+ default_min_elements, detail::partition::visit_no_policy());
}
template
@@ -704,7 +755,7 @@ public:
typename ExpandPolicy2,
typename OverlapsPolicy2
>
- static inline void apply(ForwardRange1 const& forward_range1,
+ static inline bool apply(ForwardRange1 const& forward_range1,
ForwardRange2 const& forward_range2,
VisitPolicy& visitor,
ExpandPolicy1 const& expand_policy1,
@@ -713,9 +764,9 @@ public:
OverlapsPolicy2 const& overlaps_policy2,
std::size_t min_elements)
{
- apply(forward_range1, forward_range2, visitor,
- expand_policy1, overlaps_policy1, expand_policy2, overlaps_policy1,
- min_elements, detail::partition::visit_no_policy());
+ return apply(forward_range1, forward_range2, visitor,
+ expand_policy1, overlaps_policy1, expand_policy2, overlaps_policy1,
+ min_elements, detail::partition::visit_no_policy());
}
template
@@ -729,7 +780,7 @@ public:
typename OverlapsPolicy2,
typename VisitBoxPolicy
>
- static inline void apply(ForwardRange1 const& forward_range1,
+ static inline bool apply(ForwardRange1 const& forward_range1,
ForwardRange2 const& forward_range2,
VisitPolicy& visitor,
ExpandPolicy1 const& expand_policy1,
@@ -761,7 +812,7 @@ public:
expand_to_range<IncludePolicy2>(forward_range2, total,
iterator_vector2, expand_policy2);
- detail::partition::partition_two_ranges
+ return detail::partition::partition_two_ranges
<
0, Box
>::apply(total, iterator_vector1, iterator_vector2,
@@ -779,10 +830,15 @@ public:
it2 != boost::end(forward_range2);
++it2)
{
- visitor.apply(*it1, *it2);
+ if (! visitor.apply(*it1, *it2))
+ {
+ return false; // interrupt
+ }
}
}
}
+
+ return true;
}
};
diff --git a/boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp b/boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp
index 607ba81531..b8ea5e30e6 100644
--- a/boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp
+++ b/boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp
@@ -5,10 +5,11 @@
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// Copyright (c) 2013-2015 Adam Wulkiewicz, Lodz, Poland.
-// This file was modified by Oracle on 2015.
-// Modifications copyright (c) 2015 Oracle and/or its affiliates.
+// This file was modified by Oracle on 2015, 2017.
+// Modifications copyright (c) 2015-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -19,11 +20,13 @@
#include <boost/geometry/algorithms/detail/direction_code.hpp>
#include <boost/geometry/algorithms/detail/recalculate.hpp>
+#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/policies/robustness/robust_point_type.hpp>
#include <boost/geometry/strategies/side.hpp>
#include <boost/geometry/util/condition.hpp>
#include <boost/geometry/util/math.hpp>
+
namespace boost { namespace geometry
{
@@ -32,6 +35,26 @@ namespace boost { namespace geometry
namespace detail
{
+template <typename Point1, typename Point2, typename Point3>
+inline bool collinear_point_is_spike_or_equal(Point1 const& last_point,
+ Point2 const& segment_a,
+ Point3 const& segment_b)
+{
+ // Check if segment is equal
+ int const sgn_x1 = sign_of_difference<0>(last_point, segment_b);
+ int const sgn_y1 = sign_of_difference<1>(last_point, segment_b);
+ if (sgn_x1 == 0 && sgn_y1 == 0)
+ {
+ return true;
+ }
+
+ // Check if segment moves forward
+ int const sgn_x2 = sign_of_difference<0>(segment_b, segment_a);
+ int const sgn_y2 = sign_of_difference<1>(segment_b, segment_a);
+
+ return sgn_x1 != sgn_x2 || sgn_y1 != sgn_y2;
+}
+
// Checks if a point ("last_point") causes a spike w.r.t.
// the specified two other points (segment_a, segment_b)
//
@@ -42,33 +65,29 @@ namespace detail
// So specify last point first, then (a,b)
// The segment's orientation does matter: if lp is to the right of b
// no spike is reported
-template <typename Point1, typename Point2, typename Point3>
-static inline bool point_is_spike_or_equal(Point1 const& last_point,
- Point2 const& segment_a,
- Point3 const& segment_b)
+template
+<
+ typename Point1, typename Point2, typename Point3,
+ typename SideStrategy
+>
+static inline bool point_is_spike_or_equal(Point1 const& last_point, // prev | back
+ Point2 const& segment_a, // next | back - 2
+ Point3 const& segment_b, // curr | back - 1 | spike's vertex
+ SideStrategy const& strategy)
{
- typedef typename strategy::side::services::default_strategy
- <
- typename cs_tag<Point1>::type
- >::type side_strategy;
-
- int const side = side_strategy::apply(last_point, segment_a, segment_b);
+ int const side = strategy.apply(segment_a, segment_b, last_point);
if (side == 0)
{
// Last point is collinear w.r.t previous segment.
- // Check if it is equal
- int const sgn_x1 = sign_of_difference<0>(last_point, segment_b);
- int const sgn_y1 = sign_of_difference<1>(last_point, segment_b);
- if (sgn_x1 == 0 && sgn_y1 == 0)
- {
- return true;
- }
-
- // Check if it moves forward
- int const sgn_x2 = sign_of_difference<0>(segment_b, segment_a);
- int const sgn_y2 = sign_of_difference<1>(segment_b, segment_a);
-
- return sgn_x1 != sgn_x2 || sgn_y1 != sgn_y2;
+#ifdef BOOST_GEOMETRY_ENABLE_POINT_IS_SPIKE_OR_EQUAL_TEST
+ bool r1 = collinear_point_is_spike_or_equal(last_point, segment_a, segment_b);
+ bool r2 = direction_code(segment_a, segment_b, last_point) < 1;
+ if (r1 != r2)
+ std::cout << "spike detection failure with: " << r1 << " " << r2 << std::endl;
+ return r2;
+#else
+ return direction_code(segment_a, segment_b, last_point) < 1;
+#endif
}
return false;
}
@@ -78,14 +97,16 @@ template
typename Point1,
typename Point2,
typename Point3,
+ typename SideStrategy,
typename RobustPolicy
>
static inline bool point_is_spike_or_equal(Point1 const& last_point,
Point2 const& segment_a,
Point3 const& segment_b,
+ SideStrategy const& strategy,
RobustPolicy const& robust_policy)
{
- if (point_is_spike_or_equal(last_point, segment_a, segment_b))
+ if (point_is_spike_or_equal(last_point, segment_a, segment_b, strategy))
{
return true;
}
@@ -111,7 +132,8 @@ static inline bool point_is_spike_or_equal(Point1 const& last_point,
(
last_point_rob,
segment_a_rob,
- segment_b_rob
+ segment_b_rob,
+ strategy
);
}
diff --git a/boost/geometry/algorithms/detail/point_on_border.hpp b/boost/geometry/algorithms/detail/point_on_border.hpp
index 1c751c23e4..831081aa69 100644
--- a/boost/geometry/algorithms/detail/point_on_border.hpp
+++ b/boost/geometry/algorithms/detail/point_on_border.hpp
@@ -4,6 +4,10 @@
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// This file was modified by Oracle on 2017.
+// Modifications copyright (c) 2017 Oracle and/or its affiliates.
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
@@ -18,6 +22,7 @@
#include <cstddef>
#include <boost/range.hpp>
+#include <boost/static_assert.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/point_type.hpp>
@@ -29,6 +34,8 @@
#include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
+#include <boost/geometry/util/condition.hpp>
+
namespace boost { namespace geometry
{
@@ -39,10 +46,10 @@ namespace detail { namespace point_on_border
{
-template<typename Point>
struct get_point
{
- static inline bool apply(Point& destination, Point const& source, bool)
+ template <typename Point>
+ static inline bool apply(Point& destination, Point const& source)
{
destination = source;
return true;
@@ -74,66 +81,77 @@ struct midpoint_helper<Point, DimensionCount, DimensionCount>
};
-template<typename Point, typename Range>
+template <bool Midpoint>
struct point_on_range
{
- static inline bool apply(Point& point, Range const& range, bool midpoint)
+ // Version with iterator
+ template<typename Point, typename Iterator>
+ static inline bool apply(Point& point, Iterator begin, Iterator end)
{
- const std::size_t n = boost::size(range);
- if (midpoint && n > 1)
+ Iterator it = begin;
+ if (it == end)
{
- 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);
- }
+ return false;
}
- if (n > 0)
+ if (! Midpoint)
{
- geometry::detail::conversion::convert_point_to_point(*boost::begin(range), point);
+ geometry::detail::conversion::convert_point_to_point(*it, point);
return true;
}
+
+ Iterator prev = it++;
+
+ // Go to next non-duplicate point
+ while (it != end
+ && detail::equals::equals_point_point(*it, *prev))
+ {
+ prev = it++;
+ }
+ if (it != end)
+ {
+ return midpoint_helper
+ <
+ Point,
+ 0, dimension<Point>::value
+ >::apply(point, *prev, *it);
+ }
return false;
}
+
+ // Version with range
+ template<typename Point, typename Range>
+ static inline bool apply(Point& point, Range const& range)
+ {
+ typedef typename geometry::cs_tag<Point>::type cs_tag;
+ BOOST_STATIC_ASSERT((! Midpoint || boost::is_same<cs_tag, cartesian_tag>::value));
+
+ return apply(point, boost::begin(range), boost::end(range));
+ }
};
-template<typename Point, typename Polygon>
+template <bool Midpoint>
struct point_on_polygon
{
- static inline bool apply(Point& point, Polygon const& polygon, bool midpoint)
+ template<typename Point, typename Polygon>
+ static inline bool apply(Point& point, Polygon const& polygon)
{
return point_on_range
<
- Point,
- typename ring_type<Polygon>::type
- >::apply(point, exterior_ring(polygon), midpoint);
+ Midpoint
+ >::apply(point, exterior_ring(polygon));
}
};
-template<typename Point, typename Box>
+template <bool Midpoint>
struct point_on_box
{
- static inline bool apply(Point& point, Box const& box, bool midpoint)
+ template<typename Point, typename Box>
+ static inline bool apply(Point& point, Box const& box)
{
- if (midpoint)
+ if (BOOST_GEOMETRY_CONDITION(Midpoint))
{
Point p1, p2;
detail::assign::assign_box_2d_corner<min_corner, min_corner>(box, p1);
@@ -154,15 +172,11 @@ struct point_on_box
};
-template
-<
- typename Point,
- typename MultiGeometry,
- typename Policy
->
+template <typename Policy>
struct point_on_multi
{
- static inline bool apply(Point& point, MultiGeometry const& multi, bool midpoint)
+ template<typename Point, typename MultiGeometry>
+ static inline bool apply(Point& point, MultiGeometry const& multi)
{
// Take a point on the first multi-geometry
// (i.e. the first that is not empty)
@@ -173,7 +187,7 @@ struct point_on_multi
it != boost::end(multi);
++it)
{
- if (Policy::apply(point, *it, midpoint))
+ if (Policy::apply(point, *it))
{
return true;
}
@@ -195,70 +209,57 @@ namespace dispatch
template
<
typename GeometryTag,
- typename Point,
- typename Geometry
+ bool Midpoint
>
struct point_on_border
{};
-template<typename Point>
-struct point_on_border<point_tag, Point, Point>
- : detail::point_on_border::get_point<Point>
+template <bool Midpoint>
+struct point_on_border<point_tag, Midpoint>
+ : detail::point_on_border::get_point
{};
-template<typename Point, typename Linestring>
-struct point_on_border<linestring_tag, Point, Linestring>
- : detail::point_on_border::point_on_range<Point, Linestring>
+template <bool Midpoint>
+struct point_on_border<linestring_tag, Midpoint>
+ : detail::point_on_border::point_on_range<Midpoint>
{};
-template<typename Point, typename Ring>
-struct point_on_border<ring_tag, Point, Ring>
- : detail::point_on_border::point_on_range<Point, Ring>
+template <bool Midpoint>
+struct point_on_border<ring_tag, Midpoint>
+ : detail::point_on_border::point_on_range<Midpoint>
{};
-template<typename Point, typename Polygon>
-struct point_on_border<polygon_tag, Point, Polygon>
- : detail::point_on_border::point_on_polygon<Point, Polygon>
+template <bool Midpoint>
+struct point_on_border<polygon_tag, Midpoint>
+ : detail::point_on_border::point_on_polygon<Midpoint>
{};
-template<typename Point, typename Box>
-struct point_on_border<box_tag, Point, Box>
- : detail::point_on_border::point_on_box<Point, Box>
+template <bool Midpoint>
+struct point_on_border<box_tag, Midpoint>
+ : detail::point_on_border::point_on_box<Midpoint>
{};
-template<typename Point, typename Multi>
-struct point_on_border<multi_polygon_tag, Point, Multi>
+template <bool Midpoint>
+struct point_on_border<multi_polygon_tag, Midpoint>
: detail::point_on_border::point_on_multi
<
- Point,
- Multi,
- detail::point_on_border::point_on_polygon
- <
- Point,
- typename boost::range_value<Multi>::type
- >
+ detail::point_on_border::point_on_polygon<Midpoint>
>
{};
-template<typename Point, typename Multi>
-struct point_on_border<multi_linestring_tag, Point, Multi>
+template <bool Midpoint>
+struct point_on_border<multi_linestring_tag, Midpoint>
: detail::point_on_border::point_on_multi
<
- Point,
- Multi,
- detail::point_on_border::point_on_range
- <
- Point,
- typename boost::range_value<Multi>::type
- >
+ detail::point_on_border::point_on_range<Midpoint>
>
{};
@@ -273,18 +274,12 @@ struct point_on_border<multi_linestring_tag, Point, Multi>
\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)
+inline bool point_on_border(Point& point, Geometry const& geometry)
{
concepts::check<Point>();
concepts::check<Geometry const>();
@@ -292,12 +287,32 @@ inline bool point_on_border(Point& point,
return dispatch::point_on_border
<
typename tag<Geometry>::type,
- Point,
- Geometry
- >::apply(point, geometry, midpoint);
+ false
+ >::apply(point, geometry);
}
+/*!
+\tparam Midpoint boolean flag, true if the point should not be a vertex, but some point
+ in between of two vertices
+\note for Midpoint, it is not taken from two consecutive duplicate vertices,
+ (unless there are no other).
+ */
+/*
+template <bool Midpoint, typename Point, typename Geometry>
+inline bool point_on_border(Point& point, Geometry const& geometry)
+{
+ concepts::check<Point>();
+ concepts::check<Geometry const>();
+
+ return dispatch::point_on_border
+ <
+ typename tag<Geometry>::type,
+ Midpoint
+ >::apply(point, geometry);
+}
+*/
+
}} // namespace boost::geometry
diff --git a/boost/geometry/algorithms/detail/relate/implementation.hpp b/boost/geometry/algorithms/detail/relate/implementation.hpp
index 3bd0f806c1..8f7942d46e 100644
--- a/boost/geometry/algorithms/detail/relate/implementation.hpp
+++ b/boost/geometry/algorithms/detail/relate/implementation.hpp
@@ -23,6 +23,7 @@
#include <boost/geometry/algorithms/detail/relate/point_geometry.hpp>
#include <boost/geometry/algorithms/detail/relate/linear_linear.hpp>
#include <boost/geometry/algorithms/detail/relate/linear_areal.hpp>
+#include <boost/geometry/algorithms/detail/relate/multi_point_geometry.hpp>
#include <boost/geometry/algorithms/detail/relate/areal_areal.hpp>
#include <boost/geometry/strategies/intersection.hpp>
@@ -81,6 +82,16 @@ struct relate<Geometry, Point, Tag1, point_tag, TopDim1, 0, true>
: detail::relate::geometry_point<Geometry, Point>
{};
+template <typename MultiPoint, typename Geometry, typename Tag2, int TopDim2>
+struct relate<MultiPoint, Geometry, multi_point_tag, Tag2, 0, TopDim2, false>
+ : detail::relate::multi_point_geometry<MultiPoint, Geometry>
+{};
+
+template <typename Geometry, typename MultiPoint, typename Tag1, int TopDim1>
+struct relate<Geometry, MultiPoint, Tag1, multi_point_tag, TopDim1, 0, false>
+ : detail::relate::geometry_multi_point<Geometry, MultiPoint>
+{};
+
template <typename Linear1, typename Linear2, typename Tag1, typename Tag2>
struct relate<Linear1, Linear2, Tag1, Tag2, 1, 1, true>
diff --git a/boost/geometry/algorithms/detail/relate/multi_point_geometry.hpp b/boost/geometry/algorithms/detail/relate/multi_point_geometry.hpp
new file mode 100644
index 0000000000..47c6963b87
--- /dev/null
+++ b/boost/geometry/algorithms/detail/relate/multi_point_geometry.hpp
@@ -0,0 +1,568 @@
+// Boost.Geometry
+
+// Copyright (c) 2017 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+// 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_RELATE_MULTI_POINT_GEOMETRY_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_MULTI_POINT_GEOMETRY_HPP
+
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/point_box.hpp>
+#include <boost/geometry/algorithms/detail/expand_by_epsilon.hpp>
+#include <boost/geometry/algorithms/detail/relate/result.hpp>
+#include <boost/geometry/algorithms/detail/relate/topology_check.hpp>
+#include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp>
+#include <boost/geometry/algorithms/envelope.hpp>
+
+#include <boost/geometry/core/is_areal.hpp>
+#include <boost/geometry/core/point_type.hpp>
+
+#include <boost/geometry/geometries/box.hpp>
+
+#include <boost/geometry/index/rtree.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace relate
+{
+
+template
+<
+ typename Geometry,
+ typename Tag = typename tag<Geometry>::type
+>
+struct multi_point_geometry_eb
+{
+ template <typename MultiPoint>
+ static inline bool apply(MultiPoint const& ,
+ detail::relate::topology_check<Geometry> const& )
+ {
+ return true;
+ }
+};
+
+template <typename Geometry>
+struct multi_point_geometry_eb<Geometry, linestring_tag>
+{
+ template <typename Points>
+ struct boundary_visitor
+ {
+ boundary_visitor(Points const& points)
+ : m_points(points)
+ , m_boundary_found(false)
+ {}
+
+ template <typename Point>
+ struct find_pred
+ {
+ find_pred(Point const& point)
+ : m_point(point)
+ {}
+
+ template <typename Pt>
+ bool operator()(Pt const& pt) const
+ {
+ return detail::equals::equals_point_point(pt, m_point);
+ }
+
+ Point const& m_point;
+ };
+
+ template <typename Point>
+ bool apply(Point const& boundary_point)
+ {
+ if (std::find_if(m_points.begin(), m_points.end(), find_pred<Point>(boundary_point)) == m_points.end())
+ {
+ m_boundary_found = true;
+ return false;
+ }
+ return true;
+ }
+
+ bool result() const { return m_boundary_found; }
+
+ private:
+ Points const& m_points;
+ bool m_boundary_found;
+ };
+
+ template <typename MultiPoint>
+ static inline bool apply(MultiPoint const& multi_point,
+ detail::relate::topology_check<Geometry> const& tc)
+ {
+ boundary_visitor<MultiPoint> visitor(multi_point);
+ tc.for_each_boundary_point(visitor);
+ return visitor.result();
+ }
+};
+
+template <typename Geometry>
+struct multi_point_geometry_eb<Geometry, multi_linestring_tag>
+{
+ template <typename Points>
+ struct boundary_visitor
+ {
+ boundary_visitor(Points const& points)
+ : m_points(points)
+ , m_boundary_found(false)
+ {}
+
+ template <typename Point>
+ bool apply(Point const& boundary_point)
+ {
+ if (! std::binary_search(m_points.begin(), m_points.end(), boundary_point, relate::less()))
+ {
+ m_boundary_found = true;
+ return false;
+ }
+ return true;
+ }
+
+ bool result() const { return m_boundary_found; }
+
+ private:
+ Points const& m_points;
+ bool m_boundary_found;
+ };
+
+ template <typename MultiPoint>
+ static inline bool apply(MultiPoint const& multi_point,
+ detail::relate::topology_check<Geometry> const& tc)
+ {
+ typedef typename boost::range_value<MultiPoint>::type point_type;
+ typedef std::vector<point_type> points_type;
+ points_type points(boost::begin(multi_point), boost::end(multi_point));
+ std::sort(points.begin(), points.end(), relate::less());
+
+ boundary_visitor<points_type> visitor(points);
+ tc.for_each_boundary_point(visitor);
+ return visitor.result();
+ }
+};
+
+// SingleGeometry - Linear or Areal
+template <typename MultiPoint, typename SingleGeometry, bool Transpose = false>
+struct multi_point_single_geometry
+{
+ static const bool interruption_enabled = true;
+
+ template <typename Result, typename Strategy>
+ static inline void apply(MultiPoint const& multi_point,
+ SingleGeometry const& single_geometry,
+ Result & result,
+ Strategy const& strategy)
+ {
+ typedef typename point_type<SingleGeometry>::type point2_type;
+ typedef model::box<point2_type> box2_type;
+
+ box2_type box2;
+ geometry::envelope(single_geometry, box2, strategy.get_envelope_strategy());
+ geometry::detail::expand_by_epsilon(box2);
+
+ typedef typename boost::range_const_iterator<MultiPoint>::type iterator;
+ for ( iterator it = boost::begin(multi_point) ; it != boost::end(multi_point) ; ++it )
+ {
+ if (! (relate::may_update<interior, interior, '0', Transpose>(result)
+ || relate::may_update<interior, boundary, '0', Transpose>(result)
+ || relate::may_update<interior, exterior, '0', Transpose>(result) ) )
+ {
+ break;
+ }
+
+ // The default strategy is enough for Point/Box
+ if (detail::disjoint::disjoint_point_box(*it, box2))
+ {
+ relate::set<interior, exterior, '0', Transpose>(result);
+ }
+ else
+ {
+ int in_val = detail::within::point_in_geometry(*it, single_geometry, strategy);
+
+ if (in_val > 0) // within
+ {
+ relate::set<interior, interior, '0', Transpose>(result);
+ }
+ else if (in_val == 0)
+ {
+ relate::set<interior, boundary, '0', Transpose>(result);
+ }
+ else // in_val < 0 - not within
+ {
+ relate::set<interior, exterior, '0', Transpose>(result);
+ }
+ }
+
+ if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
+ {
+ return;
+ }
+ }
+
+ typedef detail::relate::topology_check<SingleGeometry> tc_t;
+ if ( relate::may_update<exterior, interior, tc_t::interior, Transpose>(result)
+ || relate::may_update<exterior, boundary, tc_t::boundary, Transpose>(result) )
+ {
+ tc_t tc(single_geometry);
+
+ if ( relate::may_update<exterior, interior, tc_t::interior, Transpose>(result)
+ && tc.has_interior() )
+ {
+ // TODO: this is not true if a linestring is degenerated to a point
+ // then the interior has topological dimension = 0, not 1
+ relate::set<exterior, interior, tc_t::interior, Transpose>(result);
+ }
+
+ if ( relate::may_update<exterior, boundary, tc_t::boundary, Transpose>(result)
+ && tc.has_boundary() )
+ {
+ if (multi_point_geometry_eb<SingleGeometry>::apply(multi_point, tc))
+ relate::set<exterior, boundary, tc_t::boundary, Transpose>(result);
+ }
+ }
+
+ relate::set<exterior, exterior, result_dimension<MultiPoint>::value, Transpose>(result);
+ }
+};
+
+
+// MultiGeometry - Linear or Areal
+// part of the algorithm calculating II and IB when no IE has to be calculated
+// using partition()
+template <typename MultiPoint, typename MultiGeometry, bool Transpose>
+class multi_point_multi_geometry_ii_ib
+{
+ struct expand_box_point
+ {
+ template <typename Box, typename Point>
+ static inline void apply(Box& total, Point const& point)
+ {
+ geometry::expand(total, point);
+ }
+ };
+
+ struct expand_box_box_pair
+ {
+ template <typename Box, typename BoxPair>
+ static inline void apply(Box& total, BoxPair const& box_pair)
+ {
+ geometry::expand(total, box_pair.first);
+ }
+ };
+
+ struct overlaps_box_point
+ {
+ template <typename Box, typename Point>
+ static inline bool apply(Box const& box, Point const& point)
+ {
+ // The default strategy is enough for Point/Box
+ return ! detail::disjoint::disjoint_point_box(point, box);
+ }
+ };
+
+ struct overlaps_box_box_pair
+ {
+ template <typename Box, typename BoxPair>
+ static inline bool apply(Box const& box, BoxPair const& box_pair)
+ {
+ // The default strategy is enough for Box/Box
+ return ! detail::disjoint::disjoint_box_box(box_pair.first, box);
+ }
+ };
+
+ template <typename Result, typename PtSegStrategy>
+ class item_visitor_type
+ {
+ public:
+ item_visitor_type(MultiGeometry const& multi_geometry,
+ detail::relate::topology_check<MultiGeometry> const& tc,
+ Result & result,
+ PtSegStrategy const& strategy)
+ : m_multi_geometry(multi_geometry)
+ , m_tc(tc)
+ , m_result(result)
+ , m_strategy(strategy)
+ {}
+
+ template <typename Point, typename BoxPair>
+ inline bool apply(Point const& point, BoxPair const& box_pair)
+ {
+ // The default strategy is enough for Point/Box
+ if (! detail::disjoint::disjoint_point_box(point, box_pair.first))
+ {
+ typename boost::range_value<MultiGeometry>::type const&
+ single = range::at(m_multi_geometry, box_pair.second);
+
+ int in_val = detail::within::point_in_geometry(point, single, m_strategy);
+
+ if (in_val > 0) // within
+ {
+ relate::set<interior, interior, '0', Transpose>(m_result);
+ }
+ else if (in_val == 0)
+ {
+ if (m_tc.check_boundary_point(point))
+ relate::set<interior, boundary, '0', Transpose>(m_result);
+ else
+ relate::set<interior, interior, '0', Transpose>(m_result);
+ }
+ }
+
+ if ( BOOST_GEOMETRY_CONDITION(m_result.interrupt) )
+ {
+ return false;
+ }
+
+ if (! (relate::may_update<interior, interior, '0', Transpose>(m_result)
+ || relate::may_update<interior, boundary, '0', Transpose>(m_result) ) )
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+
+ private:
+ MultiGeometry const& m_multi_geometry;
+ detail::relate::topology_check<MultiGeometry> const& m_tc;
+ Result & m_result;
+ PtSegStrategy const& m_strategy;
+ };
+
+public:
+ typedef typename point_type<MultiPoint>::type point1_type;
+ typedef typename point_type<MultiGeometry>::type point2_type;
+ typedef model::box<point1_type> box1_type;
+ typedef model::box<point2_type> box2_type;
+ typedef std::pair<box2_type, std::size_t> box_pair_type;
+
+ template <typename Result, typename Strategy>
+ static inline void apply(MultiPoint const& multi_point,
+ MultiGeometry const& multi_geometry,
+ std::vector<box_pair_type> const& boxes,
+ detail::relate::topology_check<MultiGeometry> const& tc,
+ Result & result,
+ Strategy const& strategy)
+ {
+ item_visitor_type<Result, Strategy> visitor(multi_geometry, tc, result, strategy);
+
+ geometry::partition
+ <
+ box1_type
+ >::apply(multi_point, boxes, visitor,
+ expand_box_point(),
+ overlaps_box_point(),
+ expand_box_box_pair(),
+ overlaps_box_box_pair());
+ }
+
+};
+
+// MultiGeometry - Linear or Areal
+// part of the algorithm calculating II, IB and IE
+// using rtree
+template <typename MultiPoint, typename MultiGeometry, bool Transpose>
+struct multi_point_multi_geometry_ii_ib_ie
+{
+ typedef typename point_type<MultiPoint>::type point1_type;
+ typedef typename point_type<MultiGeometry>::type point2_type;
+ typedef model::box<point1_type> box1_type;
+ typedef model::box<point2_type> box2_type;
+ typedef std::pair<box2_type, std::size_t> box_pair_type;
+ typedef std::vector<box_pair_type> boxes_type;
+ typedef typename boxes_type::const_iterator boxes_iterator;
+
+ template <typename Result, typename Strategy>
+ static inline void apply(MultiPoint const& multi_point,
+ MultiGeometry const& multi_geometry,
+ std::vector<box_pair_type> const& boxes,
+ detail::relate::topology_check<MultiGeometry> const& tc,
+ Result & result,
+ Strategy const& strategy)
+ {
+ index::rtree<box_pair_type, index::rstar<4> > rt(boxes.begin(), boxes.end());
+
+ typedef typename boost::range_const_iterator<MultiPoint>::type iterator;
+ for ( iterator it = boost::begin(multi_point) ; it != boost::end(multi_point) ; ++it )
+ {
+ if (! (relate::may_update<interior, interior, '0', Transpose>(result)
+ || relate::may_update<interior, boundary, '0', Transpose>(result)
+ || relate::may_update<interior, exterior, '0', Transpose>(result) ) )
+ {
+ return;
+ }
+
+ typename boost::range_value<MultiPoint>::type const& point = *it;
+
+ boxes_type boxes_found;
+ rt.query(index::intersects(point), std::back_inserter(boxes_found));
+
+ bool found_ii_or_ib = false;
+ for (boxes_iterator bi = boxes_found.begin() ; bi != boxes_found.end() ; ++bi)
+ {
+ typename boost::range_value<MultiGeometry>::type const&
+ single = range::at(multi_geometry, bi->second);
+
+ int in_val = detail::within::point_in_geometry(point, single, strategy);
+
+ if (in_val > 0) // within
+ {
+ relate::set<interior, interior, '0', Transpose>(result);
+ found_ii_or_ib = true;
+ }
+ else if (in_val == 0) // on boundary of single
+ {
+ if (tc.check_boundary_point(point))
+ relate::set<interior, boundary, '0', Transpose>(result);
+ else
+ relate::set<interior, interior, '0', Transpose>(result);
+ found_ii_or_ib = true;
+ }
+ }
+
+ // neither interior nor boundary found -> exterior
+ if (found_ii_or_ib == false)
+ {
+ relate::set<interior, exterior, '0', Transpose>(result);
+ }
+
+ if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
+ {
+ return;
+ }
+ }
+ }
+};
+
+// MultiGeometry - Linear or Areal
+template <typename MultiPoint, typename MultiGeometry, bool Transpose = false>
+struct multi_point_multi_geometry
+{
+ static const bool interruption_enabled = true;
+
+ template <typename Result, typename Strategy>
+ static inline void apply(MultiPoint const& multi_point,
+ MultiGeometry const& multi_geometry,
+ Result & result,
+ Strategy const& strategy)
+ {
+ typedef typename point_type<MultiGeometry>::type point2_type;
+ typedef model::box<point2_type> box2_type;
+ typedef std::pair<box2_type, std::size_t> box_pair_type;
+
+ typename Strategy::envelope_strategy_type const
+ envelope_strategy = strategy.get_envelope_strategy();
+
+ std::size_t count2 = boost::size(multi_geometry);
+ std::vector<box_pair_type> boxes(count2);
+ for (std::size_t i = 0 ; i < count2 ; ++i)
+ {
+ geometry::envelope(range::at(multi_geometry, i), boxes[i].first, envelope_strategy);
+ geometry::detail::expand_by_epsilon(boxes[i].first);
+ boxes[i].second = i;
+ }
+
+ typedef detail::relate::topology_check<MultiGeometry> tc_t;
+ tc_t tc(multi_geometry);
+
+ if ( relate::may_update<interior, interior, '0', Transpose>(result)
+ || relate::may_update<interior, boundary, '0', Transpose>(result)
+ || relate::may_update<interior, exterior, '0', Transpose>(result) )
+ {
+ // If there is no need to calculate IE, use partition
+ if (! relate::may_update<interior, exterior, '0', Transpose>(result) )
+ {
+ multi_point_multi_geometry_ii_ib<MultiPoint, MultiGeometry, Transpose>
+ ::apply(multi_point, multi_geometry, boxes, tc, result, strategy);
+ }
+ else // otherwise use rtree
+ {
+ multi_point_multi_geometry_ii_ib_ie<MultiPoint, MultiGeometry, Transpose>
+ ::apply(multi_point, multi_geometry, boxes, tc, result, strategy);
+ }
+ }
+
+ if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
+ {
+ return;
+ }
+
+ if ( relate::may_update<exterior, interior, tc_t::interior, Transpose>(result)
+ || relate::may_update<exterior, boundary, tc_t::boundary, Transpose>(result) )
+ {
+ if ( relate::may_update<exterior, interior, tc_t::interior, Transpose>(result)
+ && tc.has_interior() )
+ {
+ // TODO: this is not true if a linestring is degenerated to a point
+ // then the interior has topological dimension = 0, not 1
+ relate::set<exterior, interior, tc_t::interior, Transpose>(result);
+ }
+
+ if ( relate::may_update<exterior, boundary, tc_t::boundary, Transpose>(result)
+ && tc.has_boundary() )
+ {
+ if (multi_point_geometry_eb<MultiGeometry>::apply(multi_point, tc))
+ relate::set<exterior, boundary, tc_t::boundary, Transpose>(result);
+ }
+ }
+
+ relate::set<exterior, exterior, result_dimension<MultiPoint>::value, Transpose>(result);
+ }
+
+};
+
+
+template
+<
+ typename MultiPoint, typename Geometry,
+ bool Transpose = false,
+ bool isMulti = boost::is_same
+ <
+ typename tag_cast
+ <
+ typename tag<Geometry>::type, multi_tag
+ >::type,
+ multi_tag
+ >::value
+>
+struct multi_point_geometry
+ : multi_point_single_geometry<MultiPoint, Geometry, Transpose>
+{};
+
+template <typename MultiPoint, typename Geometry, bool Transpose>
+struct multi_point_geometry<MultiPoint, Geometry, Transpose, true>
+ : multi_point_multi_geometry<MultiPoint, Geometry, Transpose>
+{};
+
+
+// transposed result of multi_point_geometry
+template <typename Geometry, typename MultiPoint>
+struct geometry_multi_point
+{
+ static const bool interruption_enabled = true;
+
+ template <typename Result, typename Strategy>
+ static inline void apply(Geometry const& geometry, MultiPoint const& multi_point,
+ Result & result, Strategy const& strategy)
+ {
+ multi_point_geometry<MultiPoint, Geometry, true>::apply(multi_point, geometry, result, strategy);
+ }
+};
+
+}} // namespace detail::relate
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_MULTI_POINT_GEOMETRY_HPP
diff --git a/boost/geometry/algorithms/detail/relate/point_geometry.hpp b/boost/geometry/algorithms/detail/relate/point_geometry.hpp
index a0c6c0d49b..e78a404b21 100644
--- a/boost/geometry/algorithms/detail/relate/point_geometry.hpp
+++ b/boost/geometry/algorithms/detail/relate/point_geometry.hpp
@@ -60,29 +60,27 @@ struct point_geometry
if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
return;
- // the point is on the boundary
- if ( pig == 0 )
+ typedef detail::relate::topology_check<Geometry> tc_t;
+ if ( relate::may_update<exterior, interior, tc_t::interior, Transpose>(result)
+ || relate::may_update<exterior, boundary, tc_t::boundary, Transpose>(result) )
{
- // NOTE: even for MLs, if there is at least one boundary point,
- // somewhere there must be another one
-
- // check if there are other boundaries outside
- typedef detail::relate::topology_check<Geometry> tc_t;
- //tc_t tc(geometry, point);
- //if ( tc.has_interior )
- relate::set<exterior, interior, tc_t::interior, Transpose>(result);
- //if ( tc.has_boundary )
- relate::set<exterior, boundary, tc_t::boundary, Transpose>(result);
- }
- else
- {
- // check if there is a boundary in Geometry
- typedef detail::relate::topology_check<Geometry> tc_t;
- tc_t tc(geometry);
- if ( tc.has_interior )
+ // the point is on the boundary
+ if ( pig == 0 )
+ {
+ // NOTE: even for MLs, if there is at least one boundary point,
+ // somewhere there must be another one
relate::set<exterior, interior, tc_t::interior, Transpose>(result);
- if ( tc.has_boundary )
relate::set<exterior, boundary, tc_t::boundary, Transpose>(result);
+ }
+ else
+ {
+ // check if there is a boundary in Geometry
+ tc_t tc(geometry);
+ if ( tc.has_interior() )
+ relate::set<exterior, interior, tc_t::interior, Transpose>(result);
+ if ( tc.has_boundary() )
+ relate::set<exterior, boundary, tc_t::boundary, Transpose>(result);
+ }
}
}
};
diff --git a/boost/geometry/algorithms/detail/relate/point_point.hpp b/boost/geometry/algorithms/detail/relate/point_point.hpp
index b41d346f0b..68d8be031e 100644
--- a/boost/geometry/algorithms/detail/relate/point_point.hpp
+++ b/boost/geometry/algorithms/detail/relate/point_point.hpp
@@ -165,22 +165,41 @@ struct multipoint_multipoint
}
}
-// TODO: ADD A CHECK TO THE RESULT INDICATING IF THE FIRST AND/OR SECOND GEOMETRY MUST BE ANALYSED
+ // The geometry containing smaller number of points will be analysed first
+ if ( boost::size(multi_point1) < boost::size(multi_point2) )
+ {
+ search_both<false>(multi_point1, multi_point2, result);
+ }
+ else
+ {
+ search_both<true>(multi_point2, multi_point1, result);
+ }
-// TODO: if I/I is set for one MPt, this won't be changed when the other one in analysed
-// so if e.g. only I/I must be analysed we musn't check the other MPt
+ relate::set<exterior, exterior, result_dimension<MultiPoint1>::value>(result);
+ }
-// TODO: Also, the geometry with the smaller number of points may be analysed first
- //if ( boost::size(multi_point1) < boost::size(multi_point2) )
+ template <bool Transpose, typename MPt1, typename MPt2, typename Result>
+ static inline void search_both(MPt1 const& first_sorted_mpt, MPt2 const& first_iterated_mpt,
+ Result & result)
+ {
+ if ( relate::may_update<interior, interior, '0'>(result)
+ || relate::may_update<interior, exterior, '0'>(result)
+ || relate::may_update<exterior, interior, '0'>(result) )
+ {
+ // NlogN + MlogN
+ bool is_disjoint = search<Transpose>(first_sorted_mpt, first_iterated_mpt, result);
- // NlogN + MlogN
- bool all_handled = search<false>(multi_point1, multi_point2, result);
-
- if ( BOOST_GEOMETRY_CONDITION(all_handled || result.interrupt) )
- return;
+ if ( BOOST_GEOMETRY_CONDITION(is_disjoint || result.interrupt) )
+ return;
+ }
- // MlogM + NlogM
- search<true>(multi_point2, multi_point1, result);
+ if ( relate::may_update<interior, interior, '0'>(result)
+ || relate::may_update<interior, exterior, '0'>(result)
+ || relate::may_update<exterior, interior, '0'>(result) )
+ {
+ // MlogM + NlogM
+ search<! Transpose>(first_iterated_mpt, first_sorted_mpt, result);
+ }
}
template <bool Transpose,
@@ -215,9 +234,6 @@ struct multipoint_multipoint
break;
}
- // an optimization
- bool all_handled = false;
-
if ( found_inside ) // some point of MP2 is equal to some of MP1
{
// TODO: if I/I is set for one MPt, this won't be changed when the other one in analysed
@@ -234,14 +250,10 @@ struct multipoint_multipoint
{
relate::set<interior, exterior, '0', Transpose>(result);
relate::set<exterior, interior, '0', Transpose>(result);
-
- // if no point is intersecting the other MPt then we musn't analyse the reversed case
- all_handled = true;
}
- relate::set<exterior, exterior, result_dimension<point_type>::value, Transpose>(result);
-
- return all_handled;
+ // if no point is intersecting the other MPt then we musn't analyse the reversed case
+ return ! found_inside;
}
};
diff --git a/boost/geometry/algorithms/detail/relate/topology_check.hpp b/boost/geometry/algorithms/detail/relate/topology_check.hpp
index caa8a3c22d..654999d8fb 100644
--- a/boost/geometry/algorithms/detail/relate/topology_check.hpp
+++ b/boost/geometry/algorithms/detail/relate/topology_check.hpp
@@ -1,22 +1,23 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2014, Oracle and/or its affiliates.
+// Copyright (c) 2014-2017, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// 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)
-// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
-
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TOPOLOGY_CHECK_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TOPOLOGY_CHECK_HPP
-#include <boost/geometry/util/range.hpp>
#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
-#include <boost/geometry/policies/compare.hpp>
+#include <boost/geometry/algorithms/detail/relate/less.hpp>
#include <boost/geometry/util/has_nan_coordinate.hpp>
+#include <boost/geometry/util/range.hpp>
+
namespace boost { namespace geometry {
@@ -51,31 +52,63 @@ struct topology_check<Linestring, linestring_tag>
static const char interior = '1';
static const char boundary = '0';
- bool has_interior;
- bool has_boundary;
-
topology_check(Linestring const& ls)
+ : m_ls(ls)
+ , m_is_initialized(false)
+ {}
+
+ bool has_interior() const
{
- init(ls, 0); /*dummy param*/
+ init();
+ return m_has_interior;
}
- template <typename IgnoreBoundaryPoint>
- topology_check(Linestring const& ls, IgnoreBoundaryPoint const& ibp)
+ bool has_boundary() const
{
- init(ls, ibp); /*dummy param, won't be used*/
+ init();
+ return m_has_boundary;
}
- // Even if some point is on the boundary, if the Linestring has the boundary,
- // there will be second boundary point different than IgnoreBoundaryPoint
- template <typename IgnoreBoundaryPoint>
- void init(Linestring const& ls, IgnoreBoundaryPoint const&)
+ /*template <typename Point>
+ bool check_boundary_point(Point const& point) const
{
- std::size_t count = boost::size(ls);
- has_interior = count > 0;
+ init();
+ return m_has_boundary
+ && ( equals::equals_point_point(point, range::front(m_ls))
+ || equals::equals_point_point(point, range::back(m_ls)) );
+ }*/
+
+ template <typename Visitor>
+ void for_each_boundary_point(Visitor & visitor) const
+ {
+ init();
+ if (m_has_boundary)
+ {
+ if (visitor.apply(range::front(m_ls)))
+ visitor.apply(range::back(m_ls));
+ }
+ }
+
+private:
+ void init() const
+ {
+ if (m_is_initialized)
+ return;
+
+ std::size_t count = boost::size(m_ls);
+ m_has_interior = count > 0;
// NOTE: Linestring with all points equal is treated as 1d linear ring
- has_boundary = count > 1
- && ! detail::equals::equals_point_point(range::front(ls), range::back(ls));
+ m_has_boundary = count > 1
+ && ! detail::equals::equals_point_point(range::front(m_ls), range::back(m_ls));
+
+ m_is_initialized = true;
}
+
+ Linestring const& m_ls;
+ mutable bool m_is_initialized;
+
+ mutable bool m_has_interior;
+ mutable bool m_has_boundary;
};
template <typename MultiLinestring>
@@ -84,29 +117,58 @@ struct topology_check<MultiLinestring, multi_linestring_tag>
static const char interior = '1';
static const char boundary = '0';
- bool has_interior;
- bool has_boundary;
-
topology_check(MultiLinestring const& mls)
+ : m_mls(mls)
+ , m_is_initialized(false)
+ {}
+
+ bool has_interior() const
{
- init(mls, not_ignoring_counter());
+ init();
+ return m_has_interior;
}
- template <typename IgnoreBoundaryPoint>
- topology_check(MultiLinestring const& mls, IgnoreBoundaryPoint const& ibp)
+ bool has_boundary() const
{
- init(mls, ignoring_counter<IgnoreBoundaryPoint>(ibp));
+ init();
+ return m_has_boundary;
}
- template <typename OddCounter>
- void init(MultiLinestring const& mls, OddCounter const& odd_counter)
+ template <typename Point>
+ bool check_boundary_point(Point const& point) const
{
- typedef typename geometry::point_type<MultiLinestring>::type point_type;
- std::vector<point_type> endpoints;
- endpoints.reserve(boost::size(mls) * 2);
+ init();
+
+ if (! m_has_boundary)
+ return false;
+
+ std::size_t count = count_equal(m_endpoints.begin(), m_endpoints.end(), point);
+
+ return count % 2 != 0; // odd count -> boundary
+ }
+
+ template <typename Visitor>
+ void for_each_boundary_point(Visitor & visitor) const
+ {
+ init();
+ if (m_has_boundary)
+ {
+ for_each_boundary_point(m_endpoints.begin(), m_endpoints.end(), visitor);
+ }
+ }
+
+private:
+ void init() const
+ {
+ if (m_is_initialized)
+ return;
+
+ m_endpoints.reserve(boost::size(m_mls) * 2);
+
+ m_has_interior = false;
typedef typename boost::range_iterator<MultiLinestring const>::type ls_iterator;
- for ( ls_iterator it = boost::begin(mls) ; it != boost::end(mls) ; ++it )
+ for ( ls_iterator it = boost::begin(m_mls) ; it != boost::end(m_mls) ; ++it )
{
typename boost::range_reference<MultiLinestring const>::type
ls = *it;
@@ -115,7 +177,7 @@ struct topology_check<MultiLinestring, multi_linestring_tag>
if (count > 0)
{
- has_interior = true;
+ m_has_interior = true;
}
if (count > 1)
@@ -138,62 +200,59 @@ struct topology_check<MultiLinestring, multi_linestring_tag>
// is not used anywhere in the code, still it's safer this way
if (! geometry::has_nan_coordinate(front_pt))
{
- endpoints.push_back(front_pt);
+ m_endpoints.push_back(front_pt);
}
if (! geometry::has_nan_coordinate(back_pt))
{
- endpoints.push_back(back_pt);
+ m_endpoints.push_back(back_pt);
}
}
}
}
- has_boundary = false;
+ m_has_boundary = false;
- if ( !endpoints.empty() )
+ if (! m_endpoints.empty() )
{
- std::sort(endpoints.begin(), endpoints.end(), geometry::less<point_type>());
- has_boundary = odd_counter(endpoints.begin(), endpoints.end());
+ std::sort(m_endpoints.begin(), m_endpoints.end(), relate::less());
+ m_has_boundary = find_odd_count(m_endpoints.begin(), m_endpoints.end());
}
+
+ m_is_initialized = true;
}
- struct not_ignoring_counter
+ template <typename It, typename Point>
+ static inline std::size_t count_equal(It first, It last, Point const& point)
{
- template <typename It>
- bool operator()(It first, It last) const
- {
- return find_odd_count(first, last);
- }
- };
+ std::pair<It, It> rng = std::equal_range(first, last, point, relate::less());
+ return (std::size_t)std::distance(rng.first, rng.second);
+ }
- template <typename Point>
- struct ignoring_counter
+ template <typename It>
+ static inline bool find_odd_count(It first, It last)
{
- ignoring_counter(Point const& pt) : m_pt(pt) {}
+ interrupting_visitor visitor;
+ for_each_boundary_point(first, last, visitor);
+ return visitor.found;
+ }
- template <typename It>
- bool operator()(It first, It last) const
+ struct interrupting_visitor
+ {
+ bool found;
+ interrupting_visitor() : found(false) {}
+ template <typename Point>
+ bool apply(Point const&)
{
- typedef typename std::iterator_traits<It>::value_type point_type;
-
- std::pair<It, It> ignore_range
- = std::equal_range(first, last, m_pt,
- geometry::less<point_type>());
-
- if ( find_odd_count(first, ignore_range.first) )
- return true;
-
- return find_odd_count(ignore_range.second, last);
+ found = true;
+ return false;
}
-
- Point const& m_pt;
};
- template <typename It>
- static inline bool find_odd_count(It first, It last)
+ template <typename It, typename Visitor>
+ static void for_each_boundary_point(It first, It last, Visitor& visitor)
{
if ( first == last )
- return false;
+ return;
std::size_t count = 1;
It prev = first;
@@ -203,8 +262,14 @@ struct topology_check<MultiLinestring, multi_linestring_tag>
// the end of the equal points subrange
if ( ! equals::equals_point_point(*first, *prev) )
{
+ // odd count -> boundary
if ( count % 2 != 0 )
- return true;
+ {
+ if (! visitor.apply(*prev))
+ {
+ return;
+ }
+ }
count = 1;
}
@@ -214,8 +279,22 @@ struct topology_check<MultiLinestring, multi_linestring_tag>
}
}
- return count % 2 != 0;
+ // odd count -> boundary
+ if ( count % 2 != 0 )
+ {
+ visitor.apply(*prev);
+ }
}
+
+private:
+ MultiLinestring const& m_mls;
+ mutable bool m_is_initialized;
+
+ mutable bool m_has_interior;
+ mutable bool m_has_boundary;
+
+ typedef typename geometry::point_type<MultiLinestring>::type point_type;
+ mutable std::vector<point_type> m_endpoints;
};
template <typename Ring>
@@ -223,12 +302,11 @@ struct topology_check<Ring, ring_tag>
{
static const char interior = '2';
static const char boundary = '1';
- static const bool has_interior = true;
- static const bool has_boundary = true;
topology_check(Ring const&) {}
- template <typename P>
- topology_check(Ring const&, P const&) {}
+
+ static bool has_interior() { return true; }
+ static bool has_boundary() { return true; }
};
template <typename Polygon>
@@ -236,12 +314,11 @@ struct topology_check<Polygon, polygon_tag>
{
static const char interior = '2';
static const char boundary = '1';
- static const bool has_interior = true;
- static const bool has_boundary = true;
-
+
topology_check(Polygon const&) {}
- template <typename P>
- topology_check(Polygon const&, P const&) {}
+
+ static bool has_interior() { return true; }
+ static bool has_boundary() { return true; }
};
template <typename MultiPolygon>
@@ -249,12 +326,13 @@ struct topology_check<MultiPolygon, multi_polygon_tag>
{
static const char interior = '2';
static const char boundary = '1';
- static const bool has_interior = true;
- static const bool has_boundary = true;
-
+
topology_check(MultiPolygon const&) {}
- template <typename P>
- topology_check(MultiPolygon const&, P const&) {}
+
+ static bool has_interior() { return true; }
+ static bool has_boundary() { return true; }
+ template <typename Point>
+ static bool check_boundary_point(Point const& ) { return true; }
};
}} // namespace detail::relate
diff --git a/boost/geometry/algorithms/detail/sections/section_functions.hpp b/boost/geometry/algorithms/detail/sections/section_functions.hpp
index 7bc5c08046..67df3060c4 100644
--- a/boost/geometry/algorithms/detail/sections/section_functions.hpp
+++ b/boost/geometry/algorithms/detail/sections/section_functions.hpp
@@ -2,8 +2,8 @@
// Copyright (c) 2015 Barend Gehrels, Amsterdam, the Netherlands.
-// This file was modified by Oracle on 2015.
-// Modifications copyright (c) 2015, Oracle and/or its affiliates.
+// This file was modified by Oracle on 2015, 2017.
+// Modifications copyright (c) 2015-2017, Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -30,18 +30,87 @@ namespace detail { namespace section
template
<
std::size_t Dimension,
+ typename Geometry,
+ typename CastedCSTag = typename tag_cast
+ <
+ typename cs_tag<Geometry>::type,
+ spherical_tag
+ >::type
+>
+struct preceding_check
+{
+ template <typename Point, typename Box>
+ static inline bool apply(int dir, Point const& point, Box const& /*point_box*/, Box const& other_box)
+ {
+ return (dir == 1 && get<Dimension>(point) < get<min_corner, Dimension>(other_box))
+ || (dir == -1 && get<Dimension>(point) > get<max_corner, Dimension>(other_box));
+ }
+};
+
+template <typename Geometry>
+struct preceding_check<0, Geometry, spherical_tag>
+{
+ template <typename Point, typename Box>
+ static inline bool apply(int dir, Point const& point, Box const& point_box, Box const& other_box)
+ {
+ typedef typename select_coordinate_type
+ <
+ Point, Box
+ >::type calc_t;
+ typedef typename coordinate_system<Point>::type::units units_t;
+
+ calc_t const c0 = 0;
+
+ if (dir == 1)
+ {
+ calc_t const diff_min = math::longitude_distance_signed
+ <
+ units_t, calc_t
+ >(get<min_corner, 0>(other_box), get<0>(point));
+
+ calc_t const diff_min_min = math::longitude_distance_signed
+ <
+ units_t, calc_t
+ >(get<min_corner, 0>(other_box), get<min_corner, 0>(point_box));
+
+ return diff_min < c0 && diff_min_min <= c0 && diff_min_min <= diff_min;
+ }
+ else if (dir == -1)
+ {
+ calc_t const diff_max = math::longitude_distance_signed
+ <
+ units_t, calc_t
+ >(get<max_corner, 0>(other_box), get<0>(point));
+
+ calc_t const diff_max_max = math::longitude_distance_signed
+ <
+ units_t, calc_t
+ >(get<max_corner, 0>(other_box), get<max_corner, 0>(point_box));
+
+ return diff_max > c0 && diff_max_max >= c0 && diff_max <= diff_max_max;
+ }
+
+ return false;
+ }
+};
+
+
+template
+<
+ std::size_t Dimension,
typename Point,
typename RobustBox,
typename RobustPolicy
>
-static inline bool preceding(int dir, Point const& point,
- RobustBox const& robust_box,
- RobustPolicy const& robust_policy)
+static inline bool preceding(int dir,
+ Point const& point,
+ RobustBox const& point_robust_box,
+ RobustBox const& other_robust_box,
+ RobustPolicy const& robust_policy)
{
typename geometry::robust_point_type<Point, RobustPolicy>::type robust_point;
geometry::recalculate(robust_point, point, robust_policy);
- return (dir == 1 && get<Dimension>(robust_point) < get<min_corner, Dimension>(robust_box))
- || (dir == -1 && get<Dimension>(robust_point) > get<max_corner, Dimension>(robust_box));
+ return preceding_check<Dimension, Point>::apply(dir, robust_point, point_robust_box, other_robust_box);
}
template
@@ -51,14 +120,13 @@ template
typename RobustBox,
typename RobustPolicy
>
-static inline bool exceeding(int dir, Point const& point,
- RobustBox const& robust_box,
- RobustPolicy const& robust_policy)
+static inline bool exceeding(int dir,
+ Point const& point,
+ RobustBox const& point_robust_box,
+ RobustBox const& other_robust_box,
+ RobustPolicy const& robust_policy)
{
- typename geometry::robust_point_type<Point, RobustPolicy>::type robust_point;
- geometry::recalculate(robust_point, point, robust_policy);
- return (dir == 1 && get<Dimension>(robust_point) > get<max_corner, Dimension>(robust_box))
- || (dir == -1 && get<Dimension>(robust_point) < get<min_corner, Dimension>(robust_box));
+ return preceding<Dimension>(-dir, point, point_robust_box, other_robust_box, robust_policy);
}
diff --git a/boost/geometry/algorithms/detail/sections/sectionalize.hpp b/boost/geometry/algorithms/detail/sections/sectionalize.hpp
index 3ed5b8db07..f1d8e7d231 100644
--- a/boost/geometry/algorithms/detail/sections/sectionalize.hpp
+++ b/boost/geometry/algorithms/detail/sections/sectionalize.hpp
@@ -5,8 +5,8 @@
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// Copyright (c) 2014-2015 Adam Wulkiewicz, Lodz, Poland.
-// This file was modified by Oracle on 2013, 2014, 2015.
-// Modifications copyright (c) 2013-2015 Oracle and/or its affiliates.
+// This file was modified by Oracle on 2013, 2014, 2015, 2017.
+// Modifications copyright (c) 2013-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
@@ -29,6 +29,8 @@
#include <boost/mpl/vector_c.hpp>
#include <boost/range.hpp>
#include <boost/static_assert.hpp>
+#include <boost/type_traits/is_same.hpp>
+#include <boost/type_traits/is_fundamental.hpp>
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/algorithms/envelope.hpp>
@@ -54,6 +56,7 @@
#include <boost/geometry/geometries/segment.hpp>
#include <boost/geometry/algorithms/detail/expand_by_epsilon.hpp>
+#include <boost/geometry/strategies/envelope.hpp>
namespace boost { namespace geometry
{
@@ -133,11 +136,21 @@ struct sections : std::vector<section<Box, DimensionCount> >
namespace detail { namespace sectionalize
{
+// NOTE: This utility will NOT work for latitudes, dimension 1 in spherical
+// and geographic coordinate system because in these coordinate systems
+// e.g. a segment on northern hemisphere may go towards greater latitude
+// and then towards lesser latitude.
template
<
+ typename Point,
typename DimensionVector,
std::size_t Index,
- std::size_t Count
+ std::size_t Count,
+ typename CastedCSTag = typename tag_cast
+ <
+ typename cs_tag<Point>::type,
+ spherical_tag
+ >::type
>
struct get_direction_loop
{
@@ -158,21 +171,67 @@ struct get_direction_loop
get_direction_loop
<
+ Point,
DimensionVector,
Index + 1,
- Count
+ Count,
+ CastedCSTag
+ >::apply(seg, directions);
+ }
+};
+
+template
+<
+ typename Point,
+ typename DimensionVector,
+ std::size_t Count
+>
+struct get_direction_loop<Point, DimensionVector, 0, Count, spherical_tag>
+{
+ typedef typename boost::mpl::at_c<DimensionVector, 0>::type dimension;
+
+ template <typename Segment>
+ static inline void apply(Segment const& seg,
+ int directions[Count])
+ {
+ typedef typename coordinate_type<Segment>::type coordinate_type;
+ typedef typename coordinate_system<Point>::type::units units_t;
+
+ coordinate_type const diff = math::longitude_distance_signed
+ <
+ units_t, coordinate_type
+ >(geometry::get<0, 0>(seg),
+ geometry::get<1, 0>(seg));
+
+ coordinate_type zero = coordinate_type();
+ directions[0] = diff > zero ? 1 : diff < zero ? -1 : 0;
+
+ get_direction_loop
+ <
+ Point,
+ DimensionVector,
+ 1,
+ Count,
+ spherical_tag
>::apply(seg, directions);
}
};
-template <typename DimensionVector, std::size_t Count>
-struct get_direction_loop<DimensionVector, Count, Count>
+template
+<
+ typename Point,
+ typename DimensionVector,
+ std::size_t Count,
+ typename CastedCSTag
+>
+struct get_direction_loop<Point, DimensionVector, Count, Count, CastedCSTag>
{
template <typename Segment>
static inline void apply(Segment const&, int [Count])
{}
};
+
//! Copy one static array to another
template <typename T, std::size_t Index, std::size_t Count>
struct copy_loop
@@ -272,19 +331,21 @@ struct assign_loop<T, Count, Count>
template <typename CSTag>
struct box_first_in_section
{
- template <typename Box, typename Point>
- static inline void apply(Box & box, Point const& prev, Point const& curr)
+ template <typename Box, typename Point, typename Strategy>
+ static inline void apply(Box & box, Point const& prev, Point const& curr,
+ Strategy const& strategy)
{
geometry::model::referring_segment<Point const> seg(prev, curr);
- geometry::envelope(seg, box);
+ geometry::envelope(seg, box, strategy);
}
};
template <>
struct box_first_in_section<cartesian_tag>
{
- template <typename Box, typename Point>
- static inline void apply(Box & box, Point const& prev, Point const& curr)
+ template <typename Box, typename Point, typename Strategy>
+ static inline void apply(Box & box, Point const& prev, Point const& curr,
+ Strategy const& )
{
geometry::envelope(prev, box);
geometry::expand(box, curr);
@@ -294,19 +355,21 @@ struct box_first_in_section<cartesian_tag>
template <typename CSTag>
struct box_next_in_section
{
- template <typename Box, typename Point>
- static inline void apply(Box & box, Point const& prev, Point const& curr)
+ template <typename Box, typename Point, typename Strategy>
+ static inline void apply(Box & box, Point const& prev, Point const& curr,
+ Strategy const& strategy)
{
geometry::model::referring_segment<Point const> seg(prev, curr);
- geometry::expand(box, seg);
+ geometry::expand(box, seg, strategy);
}
};
template <>
struct box_next_in_section<cartesian_tag>
{
- template <typename Box, typename Point>
- static inline void apply(Box & box, Point const& , Point const& curr)
+ template <typename Box, typename Point, typename Strategy>
+ static inline void apply(Box & box, Point const& , Point const& curr,
+ Strategy const& )
{
geometry::expand(box, curr);
}
@@ -335,6 +398,30 @@ struct sectionalize_part
ring_identifier ring_id,
std::size_t max_count)
{
+ typedef typename strategy::envelope::services::default_strategy
+ <
+ typename cs_tag<typename Sections::box_type>::type
+ >::type envelope_strategy_type;
+
+ apply(sections, begin, end,
+ robust_policy, envelope_strategy_type(),
+ ring_id, max_count);
+ }
+
+ template
+ <
+ typename Iterator,
+ typename RobustPolicy,
+ typename Sections,
+ typename EnvelopeStrategy
+ >
+ static inline void apply(Sections& sections,
+ Iterator begin, Iterator end,
+ RobustPolicy const& robust_policy,
+ EnvelopeStrategy const& strategy,
+ ring_identifier ring_id,
+ std::size_t max_count)
+ {
boost::ignore_unused_variable_warning(robust_policy);
typedef typename boost::range_value<Sections>::type section_type;
@@ -379,7 +466,7 @@ struct sectionalize_part
int direction_classes[dimension_count] = {0};
get_direction_loop
<
- DimensionVector, 0, dimension_count
+ Point, DimensionVector, 0, dimension_count
>::apply(robust_segment, direction_classes);
// if "dir" == 0 for all point-dimensions, it is duplicate.
@@ -449,14 +536,14 @@ struct sectionalize_part
// In cartesian this is envelope of previous point expanded with current point
// in non-cartesian this is envelope of a segment
box_first_in_section<typename cs_tag<robust_point_type>::type>
- ::apply(section.bounding_box, previous_robust_point, current_robust_point);
+ ::apply(section.bounding_box, previous_robust_point, current_robust_point, strategy);
}
else
{
// In cartesian this is expand with current point
// in non-cartesian this is expand with a segment
box_next_in_section<typename cs_tag<robust_point_type>::type>
- ::apply(section.bounding_box, previous_robust_point, current_robust_point);
+ ::apply(section.bounding_box, previous_robust_point, current_robust_point, strategy);
}
section.end_index = index + 1;
@@ -501,11 +588,13 @@ struct sectionalize_range
<
typename Range,
typename RobustPolicy,
- typename Sections
+ typename Sections,
+ typename EnvelopeStrategy
>
static inline void apply(Range const& range,
RobustPolicy const& robust_policy,
Sections& sections,
+ EnvelopeStrategy const& strategy,
ring_identifier ring_id,
std::size_t max_count)
{
@@ -534,7 +623,7 @@ struct sectionalize_range
sectionalize_part<Point, DimensionVector>::apply(sections,
boost::begin(view), boost::end(view),
- robust_policy, ring_id, max_count);
+ robust_policy, strategy, ring_id, max_count);
}
};
@@ -549,12 +638,15 @@ struct sectionalize_polygon
<
typename Polygon,
typename RobustPolicy,
- typename Sections
+ typename Sections,
+ typename EnvelopeStrategy
>
static inline void apply(Polygon const& poly,
RobustPolicy const& robust_policy,
Sections& sections,
- ring_identifier ring_id, std::size_t max_count)
+ EnvelopeStrategy const& strategy,
+ ring_identifier ring_id,
+ std::size_t max_count)
{
typedef typename point_type<Polygon>::type point_type;
typedef sectionalize_range
@@ -564,7 +656,7 @@ struct sectionalize_polygon
> per_range;
ring_id.ring_index = -1;
- per_range::apply(exterior_ring(poly), robust_policy, sections, ring_id, max_count);
+ per_range::apply(exterior_ring(poly), robust_policy, sections, strategy, ring_id, max_count);
ring_id.ring_index++;
typename interior_return_type<Polygon const>::type
@@ -572,7 +664,7 @@ struct sectionalize_polygon
for (typename detail::interior_iterator<Polygon const>::type
it = boost::begin(rings); it != boost::end(rings); ++it, ++ring_id.ring_index)
{
- per_range::apply(*it, robust_policy, sections, ring_id, max_count);
+ per_range::apply(*it, robust_policy, sections, strategy, ring_id, max_count);
}
}
};
@@ -584,11 +676,13 @@ struct sectionalize_box
<
typename Box,
typename RobustPolicy,
- typename Sections
+ typename Sections,
+ typename EnvelopeStrategy
>
static inline void apply(Box const& box,
RobustPolicy const& robust_policy,
Sections& sections,
+ EnvelopeStrategy const& ,
ring_identifier const& ring_id, std::size_t max_count)
{
typedef typename point_type<Box>::type point_type;
@@ -613,12 +707,15 @@ struct sectionalize_box
points.push_back(lr);
points.push_back(ll);
+ // NOTE: Use cartesian envelope strategy in all coordinate systems
+ // because edges of a box are not geodesic segments
sectionalize_range
<
closed, false,
point_type,
DimensionVector
>::apply(points, robust_policy, sections,
+ strategy::envelope::cartesian_segment<>(),
ring_id, max_count);
}
};
@@ -630,11 +727,15 @@ struct sectionalize_multi
<
typename MultiGeometry,
typename RobustPolicy,
- typename Sections
+ typename Sections,
+ typename EnvelopeStrategy
>
static inline void apply(MultiGeometry const& multi,
RobustPolicy const& robust_policy,
- Sections& sections, ring_identifier ring_id, std::size_t max_count)
+ Sections& sections,
+ EnvelopeStrategy const& strategy,
+ ring_identifier ring_id,
+ std::size_t max_count)
{
ring_id.multi_index = 0;
for (typename boost::range_iterator<MultiGeometry const>::type
@@ -642,7 +743,7 @@ struct sectionalize_multi
it != boost::end(multi);
++it, ++ring_id.multi_index)
{
- Policy::apply(*it, robust_policy, sections, ring_id, max_count);
+ Policy::apply(*it, robust_policy, sections, strategy, ring_id, max_count);
}
}
};
@@ -814,14 +915,18 @@ template
typename DimensionVector,
typename Geometry,
typename Sections,
- typename RobustPolicy
+ typename RobustPolicy,
+ typename EnvelopeStrategy
>
inline void sectionalize(Geometry const& geometry,
RobustPolicy const& robust_policy,
Sections& sections,
+ EnvelopeStrategy const& strategy,
int source_index = 0,
std::size_t max_count = 10)
{
+ BOOST_STATIC_ASSERT((! boost::is_fundamental<EnvelopeStrategy>::value));
+
concepts::check<Geometry const>();
typedef typename boost::range_value<Sections>::type section_type;
@@ -855,12 +960,39 @@ inline void sectionalize(Geometry const& geometry,
Geometry,
Reverse,
DimensionVector
- >::apply(geometry, robust_policy, sections, ring_id, max_count);
+ >::apply(geometry, robust_policy, sections, strategy, ring_id, max_count);
detail::sectionalize::enlarge_sections(sections);
}
+template
+<
+ bool Reverse,
+ typename DimensionVector,
+ typename Geometry,
+ typename Sections,
+ typename RobustPolicy
+>
+inline void sectionalize(Geometry const& geometry,
+ RobustPolicy const& robust_policy,
+ Sections& sections,
+ int source_index = 0,
+ std::size_t max_count = 10)
+{
+ typedef typename strategy::envelope::services::default_strategy
+ <
+ typename cs_tag<Geometry>::type
+ >::type envelope_strategy_type;
+
+ boost::geometry::sectionalize
+ <
+ Reverse, DimensionVector
+ >(geometry, robust_policy, sections,
+ envelope_strategy_type(),
+ source_index, max_count);
+}
+
}} // namespace boost::geometry
diff --git a/boost/geometry/algorithms/detail/touches/implementation.hpp b/boost/geometry/algorithms/detail/touches/implementation.hpp
new file mode 100644
index 0000000000..94f1fba581
--- /dev/null
+++ b/boost/geometry/algorithms/detail/touches/implementation.hpp
@@ -0,0 +1,459 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
+// Copyright (c) 2013-2015 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2013, 2014, 2015, 2017.
+// Modifications copyright (c) 2013-2017, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+// 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_TOUCHES_IMPLEMENTATION_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_TOUCHES_IMPLEMENTATION_HPP
+
+
+#include <boost/geometry/algorithms/detail/for_each_range.hpp>
+#include <boost/geometry/algorithms/detail/overlay/overlay.hpp>
+#include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp>
+#include <boost/geometry/algorithms/detail/sub_range.hpp>
+#include <boost/geometry/algorithms/detail/relate/relate_impl.hpp>
+#include <boost/geometry/algorithms/detail/touches/interface.hpp>
+#include <boost/geometry/algorithms/disjoint.hpp>
+#include <boost/geometry/algorithms/intersects.hpp>
+#include <boost/geometry/algorithms/num_geometries.hpp>
+#include <boost/geometry/algorithms/relate.hpp>
+
+#include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace touches
+{
+
+// Box/Box
+
+template
+<
+ std::size_t Dimension,
+ std::size_t DimensionCount
+>
+struct box_box_loop
+{
+ template <typename Box1, typename Box2>
+ static inline bool apply(Box1 const& b1, Box2 const& b2, bool & touch)
+ {
+ typedef typename coordinate_type<Box1>::type coordinate_type1;
+ typedef typename coordinate_type<Box2>::type coordinate_type2;
+
+ coordinate_type1 const& min1 = get<min_corner, Dimension>(b1);
+ coordinate_type1 const& max1 = get<max_corner, Dimension>(b1);
+ coordinate_type2 const& min2 = get<min_corner, Dimension>(b2);
+ coordinate_type2 const& max2 = get<max_corner, Dimension>(b2);
+
+ // TODO assert or exception?
+ //BOOST_GEOMETRY_ASSERT(min1 <= max1 && min2 <= max2);
+
+ if (max1 < min2 || max2 < min1)
+ {
+ return false;
+ }
+
+ if (max1 == min2 || max2 == min1)
+ {
+ touch = true;
+ }
+
+ return box_box_loop
+ <
+ Dimension + 1,
+ DimensionCount
+ >::apply(b1, b2, touch);
+ }
+};
+
+template
+<
+ std::size_t DimensionCount
+>
+struct box_box_loop<DimensionCount, DimensionCount>
+{
+ template <typename Box1, typename Box2>
+ static inline bool apply(Box1 const& , Box2 const&, bool &)
+ {
+ return true;
+ }
+};
+
+struct box_box
+{
+ template <typename Box1, typename Box2, typename Strategy>
+ static inline bool apply(Box1 const& b1, Box2 const& b2, Strategy const& /*strategy*/)
+ {
+ BOOST_STATIC_ASSERT((boost::is_same
+ <
+ typename geometry::coordinate_system<Box1>::type,
+ typename geometry::coordinate_system<Box2>::type
+ >::value
+ ));
+ assert_dimension_equal<Box1, Box2>();
+
+ bool touches = false;
+ bool ok = box_box_loop
+ <
+ 0,
+ dimension<Box1>::type::value
+ >::apply(b1, b2, touches);
+
+ return ok && touches;
+ }
+};
+
+// Areal/Areal
+
+struct areal_interrupt_policy
+{
+ static bool const enabled = true;
+ bool found_touch;
+ bool found_not_touch;
+
+ // dummy variable required by self_get_turn_points::get_turns
+ static bool const has_intersections = false;
+
+ inline bool result()
+ {
+ return found_touch && !found_not_touch;
+ }
+
+ inline areal_interrupt_policy()
+ : found_touch(false), found_not_touch(false)
+ {}
+
+ template <typename Range>
+ inline bool apply(Range const& range)
+ {
+ // if already rejected (temp workaround?)
+ if ( found_not_touch )
+ return true;
+
+ typedef typename boost::range_iterator<Range const>::type iterator;
+ for ( iterator it = boost::begin(range) ; it != boost::end(range) ; ++it )
+ {
+ if ( it->has(overlay::operation_intersection) )
+ {
+ found_not_touch = true;
+ return true;
+ }
+
+ switch(it->method)
+ {
+ case overlay::method_crosses:
+ found_not_touch = true;
+ return true;
+ case overlay::method_equal:
+ // Segment spatially equal means: at the right side
+ // the polygon internally overlaps. So return false.
+ found_not_touch = true;
+ return true;
+ case overlay::method_touch:
+ case overlay::method_touch_interior:
+ case overlay::method_collinear:
+ if ( ok_for_touch(*it) )
+ {
+ found_touch = true;
+ }
+ else
+ {
+ found_not_touch = true;
+ return true;
+ }
+ break;
+ case overlay::method_none :
+ case overlay::method_disjoint :
+ case overlay::method_error :
+ break;
+ }
+ }
+
+ return false;
+ }
+
+ template <typename Turn>
+ inline bool ok_for_touch(Turn const& turn)
+ {
+ return turn.both(overlay::operation_union)
+ || turn.both(overlay::operation_blocked)
+ || turn.combination(overlay::operation_union, overlay::operation_blocked)
+ ;
+ }
+};
+
+template<typename Geometry, typename PointInRingStrategy>
+struct check_each_ring_for_within
+{
+ bool has_within;
+ Geometry const& m_geometry;
+ PointInRingStrategy const& m_strategy;
+
+ inline check_each_ring_for_within(Geometry const& g, PointInRingStrategy const& strategy)
+ : has_within(false)
+ , m_geometry(g)
+ , m_strategy(strategy)
+ {}
+
+ template <typename Range>
+ inline void apply(Range const& range)
+ {
+ typename geometry::point_type<Range>::type p;
+ geometry::point_on_border(p, range);
+ if ( !has_within && geometry::within(p, m_geometry, m_strategy) )
+ {
+ has_within = true;
+ }
+ }
+};
+
+template <typename FirstGeometry, typename SecondGeometry, typename IntersectionStrategy>
+inline bool rings_containing(FirstGeometry const& geometry1,
+ SecondGeometry const& geometry2,
+ IntersectionStrategy const& strategy)
+{
+ // NOTE: This strategy could be defined inside IntersectionStrategy
+ typedef typename IntersectionStrategy::template point_in_geometry_strategy
+ <
+ FirstGeometry, SecondGeometry
+ >::type point_in_ring_strategy_type;
+
+ point_in_ring_strategy_type point_in_ring_strategy
+ = strategy.template get_point_in_geometry_strategy<FirstGeometry, SecondGeometry>();
+
+ check_each_ring_for_within
+ <
+ FirstGeometry, point_in_ring_strategy_type
+ > checker(geometry1, point_in_ring_strategy);
+ geometry::detail::for_each_range(geometry2, checker);
+ return checker.has_within;
+}
+
+template <typename Geometry1, typename Geometry2>
+struct areal_areal
+{
+ template <typename IntersectionStrategy>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ IntersectionStrategy const& strategy)
+ {
+ typedef detail::no_rescale_policy rescale_policy_type;
+ typedef typename geometry::point_type<Geometry1>::type point_type;
+ typedef detail::overlay::turn_info
+ <
+ point_type,
+ typename segment_ratio_type<point_type, rescale_policy_type>::type
+ > turn_info;
+
+ std::deque<turn_info> turns;
+ detail::touches::areal_interrupt_policy policy;
+ rescale_policy_type robust_policy;
+ boost::geometry::get_turns
+ <
+ detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
+ detail::overlay::do_reverse<geometry::point_order<Geometry2>::value>::value,
+ detail::overlay::assign_null_policy
+ >(geometry1, geometry2, strategy, robust_policy, turns, policy);
+
+ return policy.result()
+ && ! geometry::detail::touches::rings_containing(geometry1, geometry2, strategy)
+ && ! geometry::detail::touches::rings_containing(geometry2, geometry1, strategy);
+ }
+};
+
+// P/*
+
+struct use_point_in_geometry
+{
+ template <typename Point, typename Geometry, typename Strategy>
+ static inline bool apply(Point const& point, Geometry const& geometry, Strategy const& strategy)
+ {
+ return detail::within::point_in_geometry(point, geometry, strategy) == 0;
+ }
+};
+
+
+}}
+#endif // DOXYGEN_NO_DETAIL
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch {
+
+// P/P
+
+template <typename Geometry1, typename Geometry2, typename Tag2>
+struct touches<Geometry1, Geometry2, point_tag, Tag2, pointlike_tag, pointlike_tag, false>
+{
+ template <typename Strategy>
+ static inline bool apply(Geometry1 const& , Geometry2 const& , Strategy const&)
+ {
+ return false;
+ }
+};
+
+template <typename Geometry1, typename Geometry2, typename Tag2>
+struct touches<Geometry1, Geometry2, multi_point_tag, Tag2, pointlike_tag, pointlike_tag, false>
+{
+ template <typename Strategy>
+ static inline bool apply(Geometry1 const&, Geometry2 const&, Strategy const&)
+ {
+ return false;
+ }
+};
+
+// P/*
+
+template <typename Point, typename Geometry, typename Tag2, typename CastedTag2>
+struct touches<Point, Geometry, point_tag, Tag2, pointlike_tag, CastedTag2, false>
+ : detail::touches::use_point_in_geometry
+{};
+
+template <typename MultiPoint, typename MultiGeometry, typename Tag2, typename CastedTag2>
+struct touches<MultiPoint, MultiGeometry, multi_point_tag, Tag2, pointlike_tag, CastedTag2, false>
+ : detail::relate::relate_impl
+ <
+ detail::de9im::static_mask_touches_type,
+ MultiPoint,
+ MultiGeometry
+ >
+{};
+
+template <typename Geometry, typename MultiPoint, typename Tag1, typename CastedTag1>
+struct touches<Geometry, MultiPoint, Tag1, multi_point_tag, CastedTag1, pointlike_tag, false>
+ : detail::relate::relate_impl
+ <
+ detail::de9im::static_mask_touches_type,
+ Geometry,
+ MultiPoint
+ >
+{};
+
+// Box/Box
+
+template <typename Box1, typename Box2, typename CastedTag1, typename CastedTag2>
+struct touches<Box1, Box2, box_tag, box_tag, CastedTag1, CastedTag2, false>
+ : detail::touches::box_box
+{};
+
+template <typename Box1, typename Box2>
+struct touches<Box1, Box2, box_tag, box_tag, areal_tag, areal_tag, false>
+ : detail::touches::box_box
+{};
+
+// L/L
+
+template <typename Linear1, typename Linear2, typename Tag1, typename Tag2>
+struct touches<Linear1, Linear2, Tag1, Tag2, linear_tag, linear_tag, false>
+ : detail::relate::relate_impl
+ <
+ detail::de9im::static_mask_touches_type,
+ Linear1,
+ Linear2
+ >
+{};
+
+// L/A
+
+template <typename Linear, typename Areal, typename Tag1, typename Tag2>
+struct touches<Linear, Areal, Tag1, Tag2, linear_tag, areal_tag, false>
+ : detail::relate::relate_impl
+ <
+ detail::de9im::static_mask_touches_type,
+ Linear,
+ Areal
+ >
+{};
+
+// A/L
+template <typename Linear, typename Areal, typename Tag1, typename Tag2>
+struct touches<Areal, Linear, Tag1, Tag2, areal_tag, linear_tag, false>
+ : detail::relate::relate_impl
+ <
+ detail::de9im::static_mask_touches_type,
+ Areal,
+ Linear
+ >
+{};
+
+// A/A
+
+template <typename Areal1, typename Areal2, typename Tag1, typename Tag2>
+struct touches<Areal1, Areal2, Tag1, Tag2, areal_tag, areal_tag, false>
+ : detail::relate::relate_impl
+ <
+ detail::de9im::static_mask_touches_type,
+ Areal1,
+ Areal2
+ >
+{};
+
+template <typename Areal1, typename Areal2>
+struct touches<Areal1, Areal2, ring_tag, ring_tag, areal_tag, areal_tag, false>
+ : detail::touches::areal_areal<Areal1, Areal2>
+{};
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+namespace resolve_variant {
+
+template <typename Geometry>
+struct self_touches
+{
+ static bool apply(Geometry const& geometry)
+ {
+ concepts::check<Geometry const>();
+
+ typedef typename strategy::relate::services::default_strategy
+ <
+ Geometry, Geometry
+ >::type strategy_type;
+ typedef detail::no_rescale_policy rescale_policy_type;
+ typedef typename geometry::point_type<Geometry>::type point_type;
+ typedef detail::overlay::turn_info
+ <
+ point_type,
+ typename segment_ratio_type<point_type, rescale_policy_type>::type
+ > turn_info;
+
+ typedef detail::overlay::get_turn_info
+ <
+ detail::overlay::assign_null_policy
+ > policy_type;
+
+ std::deque<turn_info> turns;
+ detail::touches::areal_interrupt_policy policy;
+ strategy_type strategy;
+ rescale_policy_type robust_policy;
+ detail::self_get_turn_points::get_turns
+ <
+ false, policy_type
+ >::apply(geometry, strategy, robust_policy, turns, policy, 0);
+
+ return policy.result();
+ }
+};
+
+}
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_TOUCHES_IMPLEMENTATION_HPP
diff --git a/boost/geometry/algorithms/detail/touches/interface.hpp b/boost/geometry/algorithms/detail/touches/interface.hpp
new file mode 100644
index 0000000000..d2e0cc8c4e
--- /dev/null
+++ b/boost/geometry/algorithms/detail/touches/interface.hpp
@@ -0,0 +1,321 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
+// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
+// Copyright (c) 2013-2015 Adam Wulkiewicz, Lodz, Poland.
+
+// This file was modified by Oracle on 2013, 2014, 2015, 2017.
+// Modifications copyright (c) 2013-2017, Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+// 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_TOUCHES_INTERFACE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_TOUCHES_INTERFACE_HPP
+
+
+#include <deque>
+
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
+
+#include <boost/geometry/core/reverse_dispatch.hpp>
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tag_cast.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+
+#include <boost/geometry/strategies/default_strategy.hpp>
+#include <boost/geometry/strategies/relate.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch {
+
+// TODO: Since CastedTags are used is Reverse needed?
+
+template
+<
+ typename Geometry1,
+ typename Geometry2,
+ typename Tag1 = typename tag<Geometry1>::type,
+ typename Tag2 = typename tag<Geometry2>::type,
+ typename CastedTag1 = typename tag_cast<Tag1, pointlike_tag, linear_tag, areal_tag>::type,
+ typename CastedTag2 = typename tag_cast<Tag2, pointlike_tag, linear_tag, areal_tag>::type,
+ bool Reverse = reverse_dispatch<Geometry1, Geometry2>::type::value
+>
+struct touches
+ : not_implemented<Tag1, Tag2>
+{};
+
+// If reversal is needed, perform it
+template
+<
+ typename Geometry1, typename Geometry2,
+ typename Tag1, typename Tag2,
+ typename CastedTag1, typename CastedTag2
+>
+struct touches<Geometry1, Geometry2, Tag1, Tag2, CastedTag1, CastedTag2, true>
+ : touches<Geometry2, Geometry1, Tag2, Tag1, CastedTag2, CastedTag1, false>
+{
+ template <typename Strategy>
+ static inline bool apply(Geometry1 const& g1, Geometry2 const& g2, Strategy const& strategy)
+ {
+ return touches<Geometry2, Geometry1>::apply(g2, g1, strategy);
+ }
+};
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+namespace resolve_strategy
+{
+
+struct touches
+{
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ return dispatch::touches
+ <
+ Geometry1, Geometry2
+ >::apply(geometry1, geometry2, strategy);
+ }
+
+ template <typename Geometry1, typename Geometry2>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ default_strategy)
+ {
+ typedef typename strategy::relate::services::default_strategy
+ <
+ Geometry1,
+ Geometry2
+ >::type strategy_type;
+
+ return dispatch::touches
+ <
+ Geometry1, Geometry2
+ >::apply(geometry1, geometry2, strategy_type());
+ }
+};
+
+} // namespace resolve_strategy
+
+
+namespace resolve_variant {
+
+template <typename Geometry1, typename Geometry2>
+struct touches
+{
+ template <typename Strategy>
+ static bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
+ {
+ concepts::check<Geometry1 const>();
+ concepts::check<Geometry2 const>();
+
+ return resolve_strategy::touches::apply(geometry1, geometry2, strategy);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
+struct touches<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
+{
+ template <typename Strategy>
+ struct visitor: boost::static_visitor<bool>
+ {
+ Geometry2 const& m_geometry2;
+ Strategy const& m_strategy;
+
+ visitor(Geometry2 const& geometry2, Strategy const& strategy)
+ : m_geometry2(geometry2)
+ , m_strategy(strategy)
+ {}
+
+ template <typename Geometry1>
+ bool operator()(Geometry1 const& geometry1) const
+ {
+ return touches<Geometry1, Geometry2>::apply(geometry1, m_geometry2, m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline bool apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ return boost::apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1);
+ }
+};
+
+template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct touches<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ template <typename Strategy>
+ struct visitor: boost::static_visitor<bool>
+ {
+ Geometry1 const& m_geometry1;
+ Strategy const& m_strategy;
+
+ visitor(Geometry1 const& geometry1, Strategy const& strategy)
+ : m_geometry1(geometry1)
+ , m_strategy(strategy)
+ {}
+
+ template <typename Geometry2>
+ bool operator()(Geometry2 const& geometry2) const
+ {
+ return touches<Geometry1, Geometry2>::apply(m_geometry1, geometry2, m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2,
+ Strategy const& strategy)
+ {
+ return boost::apply_visitor(visitor<Strategy>(geometry1, strategy), geometry2);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T1),
+ BOOST_VARIANT_ENUM_PARAMS(typename T2)>
+struct touches<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> >
+{
+ template <typename Strategy>
+ struct visitor: boost::static_visitor<bool>
+ {
+ Strategy const& m_strategy;
+
+ visitor(Strategy const& strategy)
+ : m_strategy(strategy)
+ {}
+
+ template <typename Geometry1, typename Geometry2>
+ bool operator()(Geometry1 const& geometry1,
+ Geometry2 const& geometry2) const
+ {
+ return touches<Geometry1, Geometry2>::apply(geometry1, geometry2, m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline bool apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2,
+ Strategy const& strategy)
+ {
+ return boost::apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2);
+ }
+};
+
+template <typename Geometry>
+struct self_touches;
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct self_touches<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ struct visitor: boost::static_visitor<bool>
+ {
+ template <typename Geometry>
+ bool operator()(Geometry const& geometry) const
+ {
+ return self_touches<Geometry>::apply(geometry);
+ }
+ };
+
+ static inline bool
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry)
+ {
+ return boost::apply_visitor(visitor(), geometry);
+ }
+};
+
+} // namespace resolve_variant
+
+
+/*!
+\brief \brief_check{has at least one touching point (self-tangency)}
+\note This function can be called for one geometry (self-tangency) and
+ also for two geometries (touch)
+\ingroup touches
+\tparam Geometry \tparam_geometry
+\param geometry \param_geometry
+\return \return_check{is self-touching}
+
+\qbk{distinguish,one geometry}
+\qbk{[def __one_parameter__]}
+\qbk{[include reference/algorithms/touches.qbk]}
+*/
+template <typename Geometry>
+inline bool touches(Geometry const& geometry)
+{
+ return resolve_variant::self_touches<Geometry>::apply(geometry);
+}
+
+
+/*!
+\brief \brief_check2{have at least one touching point (tangent - non overlapping)}
+\ingroup touches
+\tparam Geometry1 \tparam_geometry
+\tparam Geometry2 \tparam_geometry
+\param geometry1 \param_geometry
+\param geometry2 \param_geometry
+\return \return_check2{touch each other}
+
+\qbk{distinguish,two geometries}
+\qbk{[include reference/algorithms/touches.qbk]}
+ */
+template <typename Geometry1, typename Geometry2>
+inline bool touches(Geometry1 const& geometry1, Geometry2 const& geometry2)
+{
+ return resolve_variant::touches
+ <
+ Geometry1, Geometry2
+ >::apply(geometry1, geometry2, default_strategy());
+}
+
+/*!
+\brief \brief_check2{have at least one touching point (tangent - non overlapping)}
+\ingroup touches
+\tparam Geometry1 \tparam_geometry
+\tparam Geometry2 \tparam_geometry
+\tparam Strategy \tparam_strategy{Touches}
+\param geometry1 \param_geometry
+\param geometry2 \param_geometry
+\param strategy \param_strategy{touches}
+\return \return_check2{touch each other}
+
+\qbk{distinguish,with strategy}
+\qbk{[include reference/algorithms/touches.qbk]}
+ */
+template <typename Geometry1, typename Geometry2, typename Strategy>
+inline bool touches(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+{
+ return resolve_variant::touches
+ <
+ Geometry1, Geometry2
+ >::apply(geometry1, geometry2, strategy);
+}
+
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_TOUCHES_INTERFACE_HPP
diff --git a/boost/geometry/algorithms/detail/within/implementation.hpp b/boost/geometry/algorithms/detail/within/implementation.hpp
new file mode 100644
index 0000000000..8f1eba62e6
--- /dev/null
+++ b/boost/geometry/algorithms/detail/within/implementation.hpp
@@ -0,0 +1,306 @@
+// 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.
+
+// This file was modified by Oracle on 2013, 2014, 2017.
+// Modifications copyright (c) 2013-2017 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+// 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_WITHIN_IMPLEMENTATION_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_IMPLEMENTATION_HPP
+
+
+#include <cstddef>
+
+#include <boost/range.hpp>
+
+#include <boost/geometry/algorithms/detail/within/interface.hpp>
+
+#include <boost/geometry/core/access.hpp>
+#include <boost/geometry/core/closure.hpp>
+#include <boost/geometry/core/cs.hpp>
+#include <boost/geometry/core/exterior_ring.hpp>
+#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/core/point_order.hpp>
+#include <boost/geometry/core/ring_type.hpp>
+#include <boost/geometry/core/interior_rings.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/util/math.hpp>
+#include <boost/geometry/util/order_as_direction.hpp>
+#include <boost/geometry/views/closeable_view.hpp>
+#include <boost/geometry/views/reversible_view.hpp>
+
+#include <boost/geometry/algorithms/detail/within/multi_point.hpp>
+#include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp>
+#include <boost/geometry/algorithms/relate.hpp>
+
+#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
+#include <boost/geometry/algorithms/detail/overlay/do_reverse.hpp>
+#include <deque>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace within {
+
+struct use_point_in_geometry
+{
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
+ {
+ return detail::within::point_in_geometry(geometry1, geometry2, strategy) == 1;
+ }
+};
+
+struct use_relate
+{
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
+ {
+ typedef typename detail::de9im::static_mask_within_type
+ <
+ Geometry1, Geometry2
+ >::type within_mask;
+ return geometry::relate(geometry1, geometry2, within_mask(), strategy);
+ }
+};
+
+}} // namespace detail::within
+#endif // DOXYGEN_NO_DETAIL
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+template <typename Point, typename Box>
+struct within<Point, Box, point_tag, box_tag>
+{
+ template <typename Strategy>
+ static inline bool apply(Point const& point, Box const& box, Strategy const& strategy)
+ {
+ boost::ignore_unused_variable_warning(strategy);
+ return strategy.apply(point, box);
+ }
+};
+
+template <typename Box1, typename Box2>
+struct within<Box1, Box2, box_tag, box_tag>
+{
+ template <typename Strategy>
+ static inline bool apply(Box1 const& box1, Box2 const& box2, Strategy const& strategy)
+ {
+ assert_dimension_equal<Box1, Box2>();
+ boost::ignore_unused_variable_warning(strategy);
+ return strategy.apply(box1, box2);
+ }
+};
+
+// P/P
+
+template <typename Point1, typename Point2>
+struct within<Point1, Point2, point_tag, point_tag>
+ : public detail::within::use_point_in_geometry
+{};
+
+template <typename Point, typename MultiPoint>
+struct within<Point, MultiPoint, point_tag, multi_point_tag>
+ : public detail::within::use_point_in_geometry
+{};
+
+template <typename MultiPoint, typename Point>
+struct within<MultiPoint, Point, multi_point_tag, point_tag>
+ : public detail::within::multi_point_point
+{};
+
+template <typename MultiPoint1, typename MultiPoint2>
+struct within<MultiPoint1, MultiPoint2, multi_point_tag, multi_point_tag>
+ : public detail::within::multi_point_multi_point
+{};
+
+// P/L
+
+template <typename Point, typename Segment>
+struct within<Point, Segment, point_tag, segment_tag>
+ : public detail::within::use_point_in_geometry
+{};
+
+template <typename Point, typename Linestring>
+struct within<Point, Linestring, point_tag, linestring_tag>
+ : public detail::within::use_point_in_geometry
+{};
+
+template <typename Point, typename MultiLinestring>
+struct within<Point, MultiLinestring, point_tag, multi_linestring_tag>
+ : public detail::within::use_point_in_geometry
+{};
+
+template <typename MultiPoint, typename Segment>
+struct within<MultiPoint, Segment, multi_point_tag, segment_tag>
+ : public detail::within::multi_point_single_geometry<true>
+{};
+
+template <typename MultiPoint, typename Linestring>
+struct within<MultiPoint, Linestring, multi_point_tag, linestring_tag>
+ : public detail::within::multi_point_single_geometry<true>
+{};
+
+template <typename MultiPoint, typename MultiLinestring>
+struct within<MultiPoint, MultiLinestring, multi_point_tag, multi_linestring_tag>
+ : public detail::within::multi_point_multi_geometry<true>
+{};
+
+// P/A
+
+template <typename Point, typename Ring>
+struct within<Point, Ring, point_tag, ring_tag>
+ : public detail::within::use_point_in_geometry
+{};
+
+template <typename Point, typename Polygon>
+struct within<Point, Polygon, point_tag, polygon_tag>
+ : public detail::within::use_point_in_geometry
+{};
+
+template <typename Point, typename MultiPolygon>
+struct within<Point, MultiPolygon, point_tag, multi_polygon_tag>
+ : public detail::within::use_point_in_geometry
+{};
+
+template <typename MultiPoint, typename Ring>
+struct within<MultiPoint, Ring, multi_point_tag, ring_tag>
+ : public detail::within::multi_point_single_geometry<true>
+{};
+
+template <typename MultiPoint, typename Polygon>
+struct within<MultiPoint, Polygon, multi_point_tag, polygon_tag>
+ : public detail::within::multi_point_single_geometry<true>
+{};
+
+template <typename MultiPoint, typename MultiPolygon>
+struct within<MultiPoint, MultiPolygon, multi_point_tag, multi_polygon_tag>
+ : public detail::within::multi_point_multi_geometry<true>
+{};
+
+// L/L
+
+template <typename Linestring1, typename Linestring2>
+struct within<Linestring1, Linestring2, linestring_tag, linestring_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename Linestring, typename MultiLinestring>
+struct within<Linestring, MultiLinestring, linestring_tag, multi_linestring_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename MultiLinestring, typename Linestring>
+struct within<MultiLinestring, Linestring, multi_linestring_tag, linestring_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename MultiLinestring1, typename MultiLinestring2>
+struct within<MultiLinestring1, MultiLinestring2, multi_linestring_tag, multi_linestring_tag>
+ : public detail::within::use_relate
+{};
+
+// L/A
+
+template <typename Linestring, typename Ring>
+struct within<Linestring, Ring, linestring_tag, ring_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename MultiLinestring, typename Ring>
+struct within<MultiLinestring, Ring, multi_linestring_tag, ring_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename Linestring, typename Polygon>
+struct within<Linestring, Polygon, linestring_tag, polygon_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename MultiLinestring, typename Polygon>
+struct within<MultiLinestring, Polygon, multi_linestring_tag, polygon_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename Linestring, typename MultiPolygon>
+struct within<Linestring, MultiPolygon, linestring_tag, multi_polygon_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename MultiLinestring, typename MultiPolygon>
+struct within<MultiLinestring, MultiPolygon, multi_linestring_tag, multi_polygon_tag>
+ : public detail::within::use_relate
+{};
+
+// A/A
+
+template <typename Ring1, typename Ring2>
+struct within<Ring1, Ring2, ring_tag, ring_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename Ring, typename Polygon>
+struct within<Ring, Polygon, ring_tag, polygon_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename Polygon, typename Ring>
+struct within<Polygon, Ring, polygon_tag, ring_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename Polygon1, typename Polygon2>
+struct within<Polygon1, Polygon2, polygon_tag, polygon_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename Ring, typename MultiPolygon>
+struct within<Ring, MultiPolygon, ring_tag, multi_polygon_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename MultiPolygon, typename Ring>
+struct within<MultiPolygon, Ring, multi_polygon_tag, ring_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename Polygon, typename MultiPolygon>
+struct within<Polygon, MultiPolygon, polygon_tag, multi_polygon_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename MultiPolygon, typename Polygon>
+struct within<MultiPolygon, Polygon, multi_polygon_tag, polygon_tag>
+ : public detail::within::use_relate
+{};
+
+template <typename MultiPolygon1, typename MultiPolygon2>
+struct within<MultiPolygon1, MultiPolygon2, multi_polygon_tag, multi_polygon_tag>
+ : public detail::within::use_relate
+{};
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+#include <boost/geometry/index/rtree.hpp>
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_IMPLEMENTATION_HPP
diff --git a/boost/geometry/algorithms/detail/within/interface.hpp b/boost/geometry/algorithms/detail/within/interface.hpp
new file mode 100644
index 0000000000..23263604c2
--- /dev/null
+++ b/boost/geometry/algorithms/detail/within/interface.hpp
@@ -0,0 +1,304 @@
+// 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.
+
+// This file was modified by Oracle on 2013, 2014, 2017.
+// Modifications copyright (c) 2013-2017 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+// 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_WITHIN_INTERFACE_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_INTERFACE_HPP
+
+
+#include <boost/concept_check.hpp>
+
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
+
+#include <boost/geometry/algorithms/not_implemented.hpp>
+
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tag_cast.hpp>
+
+#include <boost/geometry/geometries/concepts/check.hpp>
+#include <boost/geometry/strategies/concepts/within_concept.hpp>
+#include <boost/geometry/strategies/default_strategy.hpp>
+#include <boost/geometry/strategies/within.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+template
+<
+ typename Geometry1,
+ typename Geometry2,
+ typename Tag1 = typename tag<Geometry1>::type,
+ typename Tag2 = typename tag<Geometry2>::type
+>
+struct within
+ : not_implemented<Tag1, Tag2>
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+namespace resolve_strategy
+{
+
+struct within
+{
+ template <typename Geometry1, typename Geometry2, typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ concepts::within::check
+ <
+ typename tag<Geometry1>::type,
+ typename tag<Geometry2>::type,
+ typename tag_cast<typename tag<Geometry2>::type, areal_tag>::type,
+ Strategy
+ >();
+
+ return dispatch::within<Geometry1, Geometry2>::apply(geometry1, geometry2, strategy);
+ }
+
+ template <typename Geometry1, typename Geometry2>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ default_strategy)
+ {
+ typedef typename strategy::within::services::default_strategy
+ <
+ Geometry1,
+ Geometry2
+ >::type strategy_type;
+
+ return apply(geometry1, geometry2, strategy_type());
+ }
+};
+
+} // namespace resolve_strategy
+
+
+namespace resolve_variant
+{
+
+template <typename Geometry1, typename Geometry2>
+struct within
+{
+ template <typename Strategy>
+ static inline bool apply(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ concepts::check<Geometry1 const>();
+ concepts::check<Geometry2 const>();
+ assert_dimension_equal<Geometry1, Geometry2>();
+
+ return resolve_strategy::within::apply(geometry1,
+ geometry2,
+ strategy);
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
+struct within<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
+{
+ template <typename Strategy>
+ struct visitor: boost::static_visitor<bool>
+ {
+ Geometry2 const& m_geometry2;
+ Strategy const& m_strategy;
+
+ visitor(Geometry2 const& geometry2, Strategy const& strategy)
+ : m_geometry2(geometry2)
+ , m_strategy(strategy)
+ {}
+
+ template <typename Geometry1>
+ bool operator()(Geometry1 const& geometry1) const
+ {
+ return within<Geometry1, Geometry2>::apply(geometry1,
+ m_geometry2,
+ m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline bool
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+ {
+ return boost::apply_visitor(visitor<Strategy>(geometry2, strategy),
+ geometry1);
+ }
+};
+
+template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct within<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ template <typename Strategy>
+ struct visitor: boost::static_visitor<bool>
+ {
+ Geometry1 const& m_geometry1;
+ Strategy const& m_strategy;
+
+ visitor(Geometry1 const& geometry1, Strategy const& strategy)
+ : m_geometry1(geometry1)
+ , m_strategy(strategy)
+ {}
+
+ template <typename Geometry2>
+ bool operator()(Geometry2 const& geometry2) const
+ {
+ return within<Geometry1, Geometry2>::apply(m_geometry1,
+ geometry2,
+ m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline bool
+ apply(Geometry1 const& geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2,
+ Strategy const& strategy)
+ {
+ return boost::apply_visitor(visitor<Strategy>(geometry1, strategy),
+ geometry2
+ );
+ }
+};
+
+template <
+ BOOST_VARIANT_ENUM_PARAMS(typename T1),
+ BOOST_VARIANT_ENUM_PARAMS(typename T2)
+>
+struct within<
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>
+>
+{
+ template <typename Strategy>
+ struct visitor: boost::static_visitor<bool>
+ {
+ Strategy const& m_strategy;
+
+ visitor(Strategy const& strategy): m_strategy(strategy) {}
+
+ template <typename Geometry1, typename Geometry2>
+ bool operator()(Geometry1 const& geometry1,
+ Geometry2 const& geometry2) const
+ {
+ return within<Geometry1, Geometry2>::apply(geometry1,
+ geometry2,
+ m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline bool
+ apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1,
+ boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2,
+ Strategy const& strategy)
+ {
+ return boost::apply_visitor(visitor<Strategy>(strategy),
+ geometry1,
+ geometry2);
+ }
+};
+
+}
+
+
+/*!
+\brief \brief_check12{is completely inside}
+\ingroup within
+\details \details_check12{within, is completely inside}.
+\tparam Geometry1 \tparam_geometry
+\tparam Geometry2 \tparam_geometry
+\param geometry1 \param_geometry which might be within the second geometry
+\param geometry2 \param_geometry which might contain the first geometry
+\return true if geometry1 is completely contained within geometry2,
+ else false
+\note The default strategy is used for within detection
+
+
+\qbk{[include reference/algorithms/within.qbk]}
+
+\qbk{
+[heading Example]
+[within]
+[within_output]
+}
+ */
+template<typename Geometry1, typename Geometry2>
+inline bool within(Geometry1 const& geometry1, Geometry2 const& geometry2)
+{
+ return resolve_variant::within
+ <
+ Geometry1,
+ Geometry2
+ >::apply(geometry1, geometry2, default_strategy());
+}
+
+/*!
+\brief \brief_check12{is completely inside} \brief_strategy
+\ingroup within
+\details \details_check12{within, is completely inside}, \brief_strategy. \details_strategy_reasons
+\tparam Geometry1 \tparam_geometry
+\tparam Geometry2 \tparam_geometry
+\param geometry1 \param_geometry which might be within the second geometry
+\param geometry2 \param_geometry which might contain the first geometry
+\param strategy strategy to be used
+\return true if geometry1 is completely contained within geometry2,
+ else false
+
+\qbk{distinguish,with strategy}
+\qbk{[include reference/algorithms/within.qbk]}
+\qbk{
+[heading Available Strategies]
+\* [link geometry.reference.strategies.strategy_within_winding Winding (coordinate system agnostic)]
+\* [link geometry.reference.strategies.strategy_within_franklin Franklin (cartesian)]
+\* [link geometry.reference.strategies.strategy_within_crossings_multiply Crossings Multiply (cartesian)]
+
+[heading Example]
+[within_strategy]
+[within_strategy_output]
+
+}
+*/
+template<typename Geometry1, typename Geometry2, typename Strategy>
+inline bool within(Geometry1 const& geometry1,
+ Geometry2 const& geometry2,
+ Strategy const& strategy)
+{
+ return resolve_variant::within
+ <
+ Geometry1,
+ Geometry2
+ >::apply(geometry1, geometry2, strategy);
+}
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_INTERFACE_HPP
diff --git a/boost/geometry/algorithms/detail/within/multi_point.hpp b/boost/geometry/algorithms/detail/within/multi_point.hpp
new file mode 100644
index 0000000000..7e85f33383
--- /dev/null
+++ b/boost/geometry/algorithms/detail/within/multi_point.hpp
@@ -0,0 +1,268 @@
+// Boost.Geometry
+
+// Copyright (c) 2017 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
+// 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_WITHIN_MULTI_POINT_HPP
+#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_MULTI_POINT_HPP
+
+
+#include <algorithm>
+#include <vector>
+
+#include <boost/range.hpp>
+#include <boost/type_traits/is_same.hpp>
+
+#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
+#include <boost/geometry/algorithms/detail/disjoint/point_box.hpp>
+#include <boost/geometry/algorithms/detail/expand_by_epsilon.hpp>
+#include <boost/geometry/algorithms/detail/relate/less.hpp>
+#include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp>
+#include <boost/geometry/algorithms/envelope.hpp>
+#include <boost/geometry/algorithms/detail/partition.hpp>
+#include <boost/geometry/core/tag.hpp>
+#include <boost/geometry/core/tag_cast.hpp>
+#include <boost/geometry/core/tags.hpp>
+
+#include <boost/geometry/geometries/box.hpp>
+
+#include <boost/geometry/index/rtree.hpp>
+
+#include <boost/geometry/strategies/covered_by.hpp>
+#include <boost/geometry/strategies/disjoint.hpp>
+
+
+namespace boost { namespace geometry {
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace within {
+
+struct multi_point_point
+{
+ template <typename MultiPoint, typename Point, typename Strategy>
+ static inline bool apply(MultiPoint const& multi_point,
+ Point const& point,
+ Strategy const& strategy)
+ {
+ typedef typename boost::range_const_iterator<MultiPoint>::type iterator;
+ for ( iterator it = boost::begin(multi_point) ; it != boost::end(multi_point) ; ++it )
+ {
+ if (! strategy.apply(*it, point))
+ {
+ return false;
+ }
+ }
+
+ // all points of MultiPoint inside Point
+ return true;
+ }
+};
+
+// NOTE: currently the strategy is ignored, math::equals() is used inside relate::less
+struct multi_point_multi_point
+{
+ template <typename MultiPoint1, typename MultiPoint2, typename Strategy>
+ static inline bool apply(MultiPoint1 const& multi_point1,
+ MultiPoint2 const& multi_point2,
+ Strategy const& /*strategy*/)
+ {
+ typedef typename boost::range_value<MultiPoint2>::type point2_type;
+
+ relate::less const less = relate::less();
+
+ std::vector<point2_type> points2(boost::begin(multi_point2), boost::end(multi_point2));
+ std::sort(points2.begin(), points2.end(), less);
+
+ bool result = false;
+
+ typedef typename boost::range_const_iterator<MultiPoint1>::type iterator;
+ for ( iterator it = boost::begin(multi_point1) ; it != boost::end(multi_point1) ; ++it )
+ {
+ if (! std::binary_search(points2.begin(), points2.end(), *it, less))
+ {
+ return false;
+ }
+ else
+ {
+ result = true;
+ }
+ }
+
+ return result;
+ }
+};
+
+
+// TODO: the complexity could be lesser
+// the second geometry could be "prepared"/sorted
+// For Linear geometries partition could be used
+// For Areal geometries point_in_geometry() would have to call the winding
+// strategy differently, currently it linearly calls the strategy for each
+// segment. So the segments would have to be sorted in a way consistent with
+// the strategy and then the strategy called only for the segments in range.
+template <bool Within>
+struct multi_point_single_geometry
+{
+ template <typename MultiPoint, typename LinearOrAreal, typename Strategy>
+ static inline bool apply(MultiPoint const& multi_point,
+ LinearOrAreal const& linear_or_areal,
+ Strategy const& strategy)
+ {
+ typedef typename boost::range_value<MultiPoint>::type point1_type;
+ typedef typename point_type<LinearOrAreal>::type point2_type;
+ typedef model::box<point2_type> box2_type;
+
+ // Create envelope of geometry
+ box2_type box;
+ geometry::envelope(linear_or_areal, box, strategy.get_envelope_strategy());
+ geometry::detail::expand_by_epsilon(box);
+
+ typedef typename strategy::covered_by::services::default_strategy
+ <
+ point1_type, box2_type
+ >::type point_in_box_type;
+
+ // Test each Point with envelope and then geometry if needed
+ // If in the exterior, break
+ bool result = false;
+
+ typedef typename boost::range_const_iterator<MultiPoint>::type iterator;
+ for ( iterator it = boost::begin(multi_point) ; it != boost::end(multi_point) ; ++it )
+ {
+ int in_val = 0;
+
+ // exterior of box and of geometry
+ if (! point_in_box_type::apply(*it, box)
+ || (in_val = point_in_geometry(*it, linear_or_areal, strategy)) < 0)
+ {
+ result = false;
+ break;
+ }
+
+ // interior : interior/boundary
+ if (Within ? in_val > 0 : in_val >= 0)
+ {
+ result = true;
+ }
+ }
+
+ return result;
+ }
+};
+
+
+// TODO: same here, probably the complexity could be lesser
+template <bool Within>
+struct multi_point_multi_geometry
+{
+ template <typename MultiPoint, typename LinearOrAreal, typename Strategy>
+ static inline bool apply(MultiPoint const& multi_point,
+ LinearOrAreal const& linear_or_areal,
+ Strategy const& strategy)
+ {
+ typedef typename point_type<LinearOrAreal>::type point2_type;
+ typedef model::box<point2_type> box2_type;
+ static const bool is_linear = is_same
+ <
+ typename tag_cast
+ <
+ typename tag<LinearOrAreal>::type,
+ linear_tag
+ >::type,
+ linear_tag
+ >::value;
+
+ typename Strategy::envelope_strategy_type const
+ envelope_strategy = strategy.get_envelope_strategy();
+
+ // TODO: box pairs could be constructed on the fly, inside the rtree
+
+ // Prepare range of envelopes and ids
+ std::size_t count2 = boost::size(linear_or_areal);
+ typedef std::pair<box2_type, std::size_t> box_pair_type;
+ typedef std::vector<box_pair_type> box_pair_vector;
+ box_pair_vector boxes(count2);
+ for (std::size_t i = 0 ; i < count2 ; ++i)
+ {
+ geometry::envelope(linear_or_areal, boxes[i].first, envelope_strategy);
+ geometry::detail::expand_by_epsilon(boxes[i].first);
+ boxes[i].second = i;
+ }
+
+ // Create R-tree
+ index::rtree<box_pair_type, index::rstar<4> > rtree(boxes.begin(), boxes.end());
+
+ // For each point find overlapping envelopes and test corresponding single geometries
+ // If a point is in the exterior break
+ bool result = false;
+
+ typedef typename boost::range_const_iterator<MultiPoint>::type iterator;
+ for ( iterator it = boost::begin(multi_point) ; it != boost::end(multi_point) ; ++it )
+ {
+ // TODO: investigate the possibility of using satisfies
+ // TODO: investigate the possibility of using iterative queries (optimization below)
+ box_pair_vector inters_boxes;
+ rtree.query(index::intersects(*it), std::back_inserter(inters_boxes));
+
+ bool found_interior = false;
+ bool found_boundary = false;
+ int boundaries = 0;
+
+ typedef typename box_pair_vector::const_iterator iterator;
+ for ( iterator box_it = inters_boxes.begin() ; box_it != inters_boxes.end() ; ++box_it )
+ {
+ int in_val = point_in_geometry(*it, range::at(linear_or_areal, box_it->second), strategy);
+
+ if (in_val > 0)
+ found_interior = true;
+ else if (in_val == 0)
+ ++boundaries;
+
+ // If the result was set previously (interior or
+ // interior/boundary found) the only thing that needs to be
+ // done for other points is to make sure they're not
+ // overlapping the exterior no need to analyse boundaries.
+ if (result && in_val >= 0)
+ {
+ break;
+ }
+ }
+
+ if ( boundaries > 0)
+ {
+ if (is_linear && boundaries % 2 == 0)
+ found_interior = true;
+ else
+ found_boundary = true;
+ }
+
+ // exterior
+ if (! found_interior && ! found_boundary)
+ {
+ result = false;
+ break;
+ }
+
+ // interior : interior/boundary
+ if (Within ? found_interior : (found_interior || found_boundary))
+ {
+ result = true;
+ }
+ }
+
+ return result;
+ }
+};
+
+}} // namespace detail::within
+#endif // DOXYGEN_NO_DETAIL
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_MULTI_POINT_HPP
diff --git a/boost/geometry/algorithms/equals.hpp b/boost/geometry/algorithms/equals.hpp
index 1479ea66fa..77b8977d22 100644
--- a/boost/geometry/algorithms/equals.hpp
+++ b/boost/geometry/algorithms/equals.hpp
@@ -22,649 +22,8 @@
#define BOOST_GEOMETRY_ALGORITHMS_EQUALS_HPP
-#include <cstddef>
-#include <vector>
-
-#include <boost/range.hpp>
-#include <boost/type_traits/is_base_of.hpp>
-
-#include <boost/variant/apply_visitor.hpp>
-#include <boost/variant/static_visitor.hpp>
-#include <boost/variant/variant_fwd.hpp>
-
-#include <boost/geometry/core/access.hpp>
-#include <boost/geometry/core/coordinate_dimension.hpp>
-#include <boost/geometry/core/geometry_id.hpp>
-#include <boost/geometry/core/reverse_dispatch.hpp>
-#include <boost/geometry/core/tags.hpp>
-
-#include <boost/geometry/geometries/concepts/check.hpp>
-
-#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
-#include <boost/geometry/algorithms/not_implemented.hpp>
-
-// For trivial checks
-#include <boost/geometry/algorithms/area.hpp>
-#include <boost/geometry/algorithms/length.hpp>
-#include <boost/geometry/util/math.hpp>
-#include <boost/geometry/util/select_coordinate_type.hpp>
-#include <boost/geometry/util/select_most_precise.hpp>
-
-#include <boost/geometry/algorithms/detail/equals/collect_vectors.hpp>
-#include <boost/geometry/algorithms/relate.hpp>
-#include <boost/geometry/algorithms/detail/relate/relate_impl.hpp>
-
-#include <boost/geometry/views/detail/indexed_point_view.hpp>
-
-
-namespace boost { namespace geometry
-{
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace equals
-{
-
-
-template
-<
- std::size_t Dimension,
- std::size_t DimensionCount
->
-struct point_point
-{
- template <typename Point1, typename Point2, typename Strategy>
- static inline bool apply(Point1 const& point1, Point2 const& point2, Strategy const& strategy)
- {
- return ! detail::disjoint::point_point
- <
- Point1, Point2,
- Dimension, DimensionCount
- >::apply(point1, point2, strategy);
- }
-};
-
-
-template
-<
- std::size_t Dimension,
- std::size_t DimensionCount
->
-struct box_box
-{
- template <typename Box1, typename Box2, typename Strategy>
- static inline bool apply(Box1 const& box1, Box2 const& box2, Strategy const& strategy)
- {
- if (!geometry::math::equals(get<min_corner, Dimension>(box1), get<min_corner, Dimension>(box2))
- || !geometry::math::equals(get<max_corner, Dimension>(box1), get<max_corner, Dimension>(box2)))
- {
- return false;
- }
- return box_box<Dimension + 1, DimensionCount>::apply(box1, box2, strategy);
- }
-};
-
-template <std::size_t DimensionCount>
-struct box_box<DimensionCount, DimensionCount>
-{
- template <typename Box1, typename Box2, typename Strategy>
- static inline bool apply(Box1 const& , Box2 const& , Strategy const& )
- {
- return true;
- }
-};
-
-
-struct segment_segment
-{
- template <typename Segment1, typename Segment2, typename Strategy>
- static inline bool apply(Segment1 const& segment1, Segment2 const& segment2, Strategy const& )
- {
- return equals::equals_point_point(
- indexed_point_view<Segment1 const, 0>(segment1),
- indexed_point_view<Segment2 const, 0>(segment2) )
- ? equals::equals_point_point(
- indexed_point_view<Segment1 const, 1>(segment1),
- indexed_point_view<Segment2 const, 1>(segment2) )
- : ( equals::equals_point_point(
- indexed_point_view<Segment1 const, 0>(segment1),
- indexed_point_view<Segment2 const, 1>(segment2) )
- && equals::equals_point_point(
- indexed_point_view<Segment1 const, 1>(segment1),
- indexed_point_view<Segment2 const, 0>(segment2) )
- );
- }
-};
-
-
-struct area_check
-{
- template <typename Geometry1, typename Geometry2, typename Strategy>
- static inline bool apply(Geometry1 const& geometry1,
- Geometry2 const& geometry2,
- Strategy const& strategy)
- {
- return geometry::math::equals(
- geometry::area(geometry1,
- strategy.template get_area_strategy<Geometry1>()),
- geometry::area(geometry2,
- strategy.template get_area_strategy<Geometry2>()));
- }
-};
-
-
-struct length_check
-{
- template <typename Geometry1, typename Geometry2, typename Strategy>
- static inline bool apply(Geometry1 const& geometry1,
- Geometry2 const& geometry2,
- Strategy const& strategy)
- {
- return geometry::math::equals(
- geometry::length(geometry1,
- strategy.template get_distance_strategy<Geometry1>()),
- geometry::length(geometry2,
- strategy.template get_distance_strategy<Geometry2>()));
- }
-};
-
-
-template <typename Geometry1, typename Geometry2, typename IntersectionStrategy>
-struct collected_vector
-{
- typedef typename geometry::select_most_precise
- <
- typename select_coordinate_type
- <
- Geometry1, Geometry2
- >::type,
- double
- >::type calculation_type;
-
- typedef geometry::collected_vector
- <
- calculation_type,
- Geometry1,
- typename IntersectionStrategy::side_strategy_type
- > type;
-};
-
-template <typename TrivialCheck>
-struct equals_by_collection
-{
- template <typename Geometry1, typename Geometry2, typename Strategy>
- static inline bool apply(Geometry1 const& geometry1,
- Geometry2 const& geometry2,
- Strategy const& strategy)
- {
- if (! TrivialCheck::apply(geometry1, geometry2, strategy))
- {
- return false;
- }
-
- typedef typename collected_vector
- <
- Geometry1, Geometry2, Strategy
- >::type collected_vector_type;
-
- std::vector<collected_vector_type> c1, c2;
-
- geometry::collect_vectors(c1, geometry1);
- geometry::collect_vectors(c2, geometry2);
-
- if (boost::size(c1) != boost::size(c2))
- {
- return false;
- }
-
- std::sort(c1.begin(), c1.end());
- std::sort(c2.begin(), c2.end());
-
- // Just check if these vectors are equal.
- return std::equal(c1.begin(), c1.end(), c2.begin());
- }
-};
-
-template<typename Geometry1, typename Geometry2>
-struct equals_by_relate
- : detail::relate::relate_impl
- <
- detail::de9im::static_mask_equals_type,
- Geometry1,
- Geometry2
- >
-{};
-
-// If collect_vectors which is a SideStrategy-dispatched optimization
-// is implemented in a way consistent with the Intersection/Side Strategy
-// then collect_vectors is used, otherwise relate is used.
-// NOTE: the result could be coneptually different for invalid
-// geometries in different coordinate systems because collect_vectors
-// and relate treat invalid geometries differently.
-template<typename TrivialCheck>
-struct equals_by_collection_or_relate
-{
- template <typename Geometry1, typename Geometry2, typename Strategy>
- static inline bool apply(Geometry1 const& geometry1,
- Geometry2 const& geometry2,
- Strategy const& strategy)
- {
- typedef typename boost::is_base_of
- <
- nyi::not_implemented_tag,
- typename collected_vector
- <
- Geometry1, Geometry2, Strategy
- >::type
- >::type enable_relate_type;
-
- return apply(geometry1, geometry2, strategy, enable_relate_type());
- }
-
-private:
- template <typename Geometry1, typename Geometry2, typename Strategy>
- static inline bool apply(Geometry1 const& geometry1,
- Geometry2 const& geometry2,
- Strategy const& strategy,
- boost::false_type /*enable_relate*/)
- {
- return equals_by_collection<TrivialCheck>::apply(geometry1, geometry2, strategy);
- }
-
- template <typename Geometry1, typename Geometry2, typename Strategy>
- static inline bool apply(Geometry1 const& geometry1,
- Geometry2 const& geometry2,
- Strategy const& strategy,
- boost::true_type /*enable_relate*/)
- {
- return equals_by_relate<Geometry1, Geometry2>::apply(geometry1, geometry2, strategy);
- }
-};
-
-
-}} // namespace detail::equals
-#endif // DOXYGEN_NO_DETAIL
-
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-template
-<
- typename Geometry1,
- typename Geometry2,
- typename Tag1 = typename tag<Geometry1>::type,
- typename Tag2 = typename tag<Geometry2>::type,
- std::size_t DimensionCount = dimension<Geometry1>::type::value,
- bool Reverse = reverse_dispatch<Geometry1, Geometry2>::type::value
->
-struct equals: not_implemented<Tag1, Tag2>
-{};
-
-
-// If reversal is needed, perform it
-template
-<
- typename Geometry1, typename Geometry2,
- typename Tag1, typename Tag2,
- std::size_t DimensionCount
->
-struct equals<Geometry1, Geometry2, Tag1, Tag2, DimensionCount, true>
- : equals<Geometry2, Geometry1, Tag2, Tag1, DimensionCount, false>
-{
- template <typename Strategy>
- static inline bool apply(Geometry1 const& g1, Geometry2 const& g2, Strategy const& strategy)
- {
- return equals
- <
- Geometry2, Geometry1,
- Tag2, Tag1,
- DimensionCount,
- false
- >::apply(g2, g1, strategy);
- }
-};
-
-
-template <typename P1, typename P2, std::size_t DimensionCount, bool Reverse>
-struct equals<P1, P2, point_tag, point_tag, DimensionCount, Reverse>
- : detail::equals::point_point<0, DimensionCount>
-{};
-
-template <typename MultiPoint1, typename MultiPoint2, std::size_t DimensionCount, bool Reverse>
-struct equals<MultiPoint1, MultiPoint2, multi_point_tag, multi_point_tag, DimensionCount, Reverse>
- : detail::equals::equals_by_relate<MultiPoint1, MultiPoint2>
-{};
-
-template <typename MultiPoint, typename Point, std::size_t DimensionCount, bool Reverse>
-struct equals<MultiPoint, Point, multi_point_tag, point_tag, DimensionCount, Reverse>
- : detail::equals::equals_by_relate<MultiPoint, Point>
-{};
-
-template <typename MultiPoint, typename Point, std::size_t DimensionCount, bool Reverse>
-struct equals<Point, MultiPoint, point_tag, multi_point_tag, DimensionCount, Reverse>
- : detail::equals::equals_by_relate<Point, MultiPoint>
-{};
-
-template <typename Box1, typename Box2, std::size_t DimensionCount, bool Reverse>
-struct equals<Box1, Box2, box_tag, box_tag, DimensionCount, Reverse>
- : detail::equals::box_box<0, DimensionCount>
-{};
-
-
-template <typename Ring1, typename Ring2, bool Reverse>
-struct equals<Ring1, Ring2, ring_tag, ring_tag, 2, Reverse>
- : detail::equals::equals_by_collection_or_relate<detail::equals::area_check>
-{};
-
-
-template <typename Polygon1, typename Polygon2, bool Reverse>
-struct equals<Polygon1, Polygon2, polygon_tag, polygon_tag, 2, Reverse>
- : detail::equals::equals_by_collection_or_relate<detail::equals::area_check>
-{};
-
-
-template <typename Polygon, typename Ring, bool Reverse>
-struct equals<Polygon, Ring, polygon_tag, ring_tag, 2, Reverse>
- : detail::equals::equals_by_collection_or_relate<detail::equals::area_check>
-{};
-
-
-template <typename Ring, typename Box, bool Reverse>
-struct equals<Ring, Box, ring_tag, box_tag, 2, Reverse>
- : detail::equals::equals_by_collection<detail::equals::area_check>
-{};
-
-
-template <typename Polygon, typename Box, bool Reverse>
-struct equals<Polygon, Box, polygon_tag, box_tag, 2, Reverse>
- : detail::equals::equals_by_collection<detail::equals::area_check>
-{};
-
-template <typename Segment1, typename Segment2, std::size_t DimensionCount, bool Reverse>
-struct equals<Segment1, Segment2, segment_tag, segment_tag, DimensionCount, Reverse>
- : detail::equals::segment_segment
-{};
-
-template <typename LineString1, typename LineString2, bool Reverse>
-struct equals<LineString1, LineString2, linestring_tag, linestring_tag, 2, Reverse>
- : detail::equals::equals_by_relate<LineString1, LineString2>
-{};
-
-template <typename LineString, typename MultiLineString, bool Reverse>
-struct equals<LineString, MultiLineString, linestring_tag, multi_linestring_tag, 2, Reverse>
- : detail::equals::equals_by_relate<LineString, MultiLineString>
-{};
-
-template <typename MultiLineString1, typename MultiLineString2, bool Reverse>
-struct equals<MultiLineString1, MultiLineString2, multi_linestring_tag, multi_linestring_tag, 2, Reverse>
- : detail::equals::equals_by_relate<MultiLineString1, MultiLineString2>
-{};
-
-
-template <typename MultiPolygon1, typename MultiPolygon2, bool Reverse>
-struct equals
- <
- MultiPolygon1, MultiPolygon2,
- multi_polygon_tag, multi_polygon_tag,
- 2,
- Reverse
- >
- : detail::equals::equals_by_collection_or_relate<detail::equals::area_check>
-{};
-
-
-template <typename Polygon, typename MultiPolygon, bool Reverse>
-struct equals
- <
- Polygon, MultiPolygon,
- polygon_tag, multi_polygon_tag,
- 2,
- Reverse
- >
- : detail::equals::equals_by_collection_or_relate<detail::equals::area_check>
-{};
-
-template <typename MultiPolygon, typename Ring, bool Reverse>
-struct equals
- <
- MultiPolygon, Ring,
- multi_polygon_tag, ring_tag,
- 2,
- Reverse
- >
- : detail::equals::equals_by_collection_or_relate<detail::equals::area_check>
-{};
-
-
-} // namespace dispatch
-#endif // DOXYGEN_NO_DISPATCH
-
-
-namespace resolve_strategy
-{
-
-struct equals
-{
- template <typename Geometry1, typename Geometry2, typename Strategy>
- static inline bool apply(Geometry1 const& geometry1,
- Geometry2 const& geometry2,
- Strategy const& strategy)
- {
- return dispatch::equals
- <
- Geometry1, Geometry2
- >::apply(geometry1, geometry2, strategy);
- }
-
- template <typename Geometry1, typename Geometry2>
- static inline bool apply(Geometry1 const& geometry1,
- Geometry2 const& geometry2,
- default_strategy)
- {
- typedef typename strategy::relate::services::default_strategy
- <
- Geometry1,
- Geometry2
- >::type strategy_type;
-
- return dispatch::equals
- <
- Geometry1, Geometry2
- >::apply(geometry1, geometry2, strategy_type());
- }
-};
-
-} // namespace resolve_strategy
-
-
-namespace resolve_variant {
-
-template <typename Geometry1, typename Geometry2>
-struct equals
-{
- template <typename Strategy>
- static inline bool apply(Geometry1 const& geometry1,
- Geometry2 const& geometry2,
- Strategy const& strategy)
- {
- concepts::check_concepts_and_equal_dimensions
- <
- Geometry1 const,
- Geometry2 const
- >();
-
- return resolve_strategy::equals
- ::apply(geometry1, geometry2, strategy);
- }
-};
-
-template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
-struct equals<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
-{
- template <typename Strategy>
- struct visitor: static_visitor<bool>
- {
- Geometry2 const& m_geometry2;
- Strategy const& m_strategy;
-
- visitor(Geometry2 const& geometry2, Strategy const& strategy)
- : m_geometry2(geometry2)
- , m_strategy(strategy)
- {}
-
- template <typename Geometry1>
- inline bool operator()(Geometry1 const& geometry1) const
- {
- return equals<Geometry1, Geometry2>
- ::apply(geometry1, m_geometry2, m_strategy);
- }
-
- };
-
- template <typename Strategy>
- static inline bool apply(
- boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
- Geometry2 const& geometry2,
- Strategy const& strategy
- )
- {
- return boost::apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1);
- }
-};
-
-template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
-struct equals<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
-{
- template <typename Strategy>
- struct visitor: static_visitor<bool>
- {
- Geometry1 const& m_geometry1;
- Strategy const& m_strategy;
-
- visitor(Geometry1 const& geometry1, Strategy const& strategy)
- : m_geometry1(geometry1)
- , m_strategy(strategy)
- {}
-
- template <typename Geometry2>
- inline bool operator()(Geometry2 const& geometry2) const
- {
- return equals<Geometry1, Geometry2>
- ::apply(m_geometry1, geometry2, m_strategy);
- }
-
- };
-
- template <typename Strategy>
- static inline bool apply(
- Geometry1 const& geometry1,
- boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2,
- Strategy const& strategy
- )
- {
- return boost::apply_visitor(visitor<Strategy>(geometry1, strategy), geometry2);
- }
-};
-
-template <
- BOOST_VARIANT_ENUM_PARAMS(typename T1),
- BOOST_VARIANT_ENUM_PARAMS(typename T2)
->
-struct equals<
- boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>,
- boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>
->
-{
- template <typename Strategy>
- struct visitor: static_visitor<bool>
- {
- Strategy const& m_strategy;
-
- visitor(Strategy const& strategy)
- : m_strategy(strategy)
- {}
-
- template <typename Geometry1, typename Geometry2>
- inline bool operator()(Geometry1 const& geometry1,
- Geometry2 const& geometry2) const
- {
- return equals<Geometry1, Geometry2>
- ::apply(geometry1, geometry2, m_strategy);
- }
-
- };
-
- template <typename Strategy>
- static inline bool apply(
- boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1,
- boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2,
- Strategy const& strategy
- )
- {
- return boost::apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2);
- }
-};
-
-} // namespace resolve_variant
-
-
-/*!
-\brief \brief_check{are spatially equal}
-\details \details_check12{equals, is spatially equal}. Spatially equal means
- that the same point set is included. A box can therefore be spatially equal
- to a ring or a polygon, or a linestring can be spatially equal to a
- multi-linestring or a segment. This only works theoretically, not all
- combinations are implemented yet.
-\ingroup equals
-\tparam Geometry1 \tparam_geometry
-\tparam Geometry2 \tparam_geometry
-\tparam Strategy \tparam_strategy{Equals}
-\param geometry1 \param_geometry
-\param geometry2 \param_geometry
-\param strategy \param_strategy{equals}
-\return \return_check2{are spatially equal}
-
-\qbk{distinguish,with strategy}
-\qbk{[include reference/algorithms/equals.qbk]}
- */
-template <typename Geometry1, typename Geometry2, typename Strategy>
-inline bool equals(Geometry1 const& geometry1,
- Geometry2 const& geometry2,
- Strategy const& strategy)
-{
- return resolve_variant::equals
- <
- Geometry1, Geometry2
- >::apply(geometry1, geometry2, strategy);
-}
-
-
-/*!
-\brief \brief_check{are spatially equal}
-\details \details_check12{equals, is spatially equal}. Spatially equal means
- that the same point set is included. A box can therefore be spatially equal
- to a ring or a polygon, or a linestring can be spatially equal to a
- multi-linestring or a segment. This only works theoretically, not all
- combinations are implemented yet.
-\ingroup equals
-\tparam Geometry1 \tparam_geometry
-\tparam Geometry2 \tparam_geometry
-\param geometry1 \param_geometry
-\param geometry2 \param_geometry
-\return \return_check2{are spatially equal}
-
-\qbk{[include reference/algorithms/equals.qbk]}
- */
-template <typename Geometry1, typename Geometry2>
-inline bool equals(Geometry1 const& geometry1, Geometry2 const& geometry2)
-{
- return resolve_variant::equals<Geometry1, Geometry2>
- ::apply(geometry1, geometry2, default_strategy());
-}
-
-
-}} // namespace boost::geometry
+#include <boost/geometry/algorithms/detail/equals/interface.hpp>
+#include <boost/geometry/algorithms/detail/equals/implementation.hpp>
#endif // BOOST_GEOMETRY_ALGORITHMS_EQUALS_HPP
diff --git a/boost/geometry/algorithms/intersects.hpp b/boost/geometry/algorithms/intersects.hpp
index 12ae169f12..503ee1a10a 100644
--- a/boost/geometry/algorithms/intersects.hpp
+++ b/boost/geometry/algorithms/intersects.hpp
@@ -21,120 +21,8 @@
#define BOOST_GEOMETRY_ALGORITHMS_INTERSECTS_HPP
-#include <deque>
+#include <boost/geometry/algorithms/detail/intersects/interface.hpp>
+#include <boost/geometry/algorithms/detail/intersects/implementation.hpp>
-#include <boost/geometry/geometries/concepts/check.hpp>
-#include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp>
-#include <boost/geometry/algorithms/disjoint.hpp>
-
-#include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
-#include <boost/geometry/policies/robustness/segment_ratio_type.hpp>
-
-#include <boost/geometry/strategies/relate.hpp>
-
-
-namespace boost { namespace geometry
-{
-
-/*!
-\brief \brief_check{has at least one intersection (crossing or self-tangency)}
-\note This function can be called for one geometry (self-intersection) and
- also for two geometries (intersection)
-\ingroup intersects
-\tparam Geometry \tparam_geometry
-\param geometry \param_geometry
-\return \return_check{is self-intersecting}
-
-\qbk{distinguish,one geometry}
-\qbk{[def __one_parameter__]}
-\qbk{[include reference/algorithms/intersects.qbk]}
-*/
-template <typename Geometry>
-inline bool intersects(Geometry const& geometry)
-{
- concepts::check<Geometry const>();
-
- typedef typename geometry::point_type<Geometry>::type point_type;
- typedef typename strategy::relate::services::default_strategy
- <
- Geometry, Geometry
- >::type strategy_type;
- typedef detail::no_rescale_policy rescale_policy_type;
-
- typedef detail::overlay::turn_info
- <
- point_type,
- typename segment_ratio_type<point_type, rescale_policy_type>::type
- > turn_info;
-
- std::deque<turn_info> turns;
-
- typedef detail::overlay::get_turn_info
- <
- detail::overlay::assign_null_policy
- > turn_policy;
-
- strategy_type strategy;
- rescale_policy_type robust_policy;
-
- detail::disjoint::disjoint_interrupt_policy policy;
- detail::self_get_turn_points::get_turns
- <
- turn_policy
- >::apply(geometry, strategy, robust_policy, turns, policy);
- return policy.has_intersections;
-}
-
-
-/*!
-\brief \brief_check2{have at least one intersection}
-\ingroup intersects
-\tparam Geometry1 \tparam_geometry
-\tparam Geometry2 \tparam_geometry
-\tparam Strategy \tparam_strategy{Intersects}
-\param geometry1 \param_geometry
-\param geometry2 \param_geometry
-\param strategy \param_strategy{intersects}
-\return \return_check2{intersect each other}
-
-\qbk{distinguish,with strategy}
-\qbk{[include reference/algorithms/intersects.qbk]}
- */
-template <typename Geometry1, typename Geometry2, typename Strategy>
-inline bool intersects(Geometry1 const& geometry1,
- Geometry2 const& geometry2,
- Strategy const& strategy)
-{
- concepts::check<Geometry1 const>();
- concepts::check<Geometry2 const>();
-
- return ! geometry::disjoint(geometry1, geometry2, strategy);
-}
-
-
-/*!
-\brief \brief_check2{have at least one intersection}
-\ingroup intersects
-\tparam Geometry1 \tparam_geometry
-\tparam Geometry2 \tparam_geometry
-\param geometry1 \param_geometry
-\param geometry2 \param_geometry
-\return \return_check2{intersect each other}
-
-\qbk{distinguish,two geometries}
-\qbk{[include reference/algorithms/intersects.qbk]}
- */
-template <typename Geometry1, typename Geometry2>
-inline bool intersects(Geometry1 const& geometry1, Geometry2 const& geometry2)
-{
- concepts::check<Geometry1 const>();
- concepts::check<Geometry2 const>();
-
- return ! geometry::disjoint(geometry1, geometry2);
-}
-
-
-
-}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_INTERSECTS_HPP
diff --git a/boost/geometry/algorithms/is_convex.hpp b/boost/geometry/algorithms/is_convex.hpp
index 8feb48db6a..4a9251b270 100644
--- a/boost/geometry/algorithms/is_convex.hpp
+++ b/boost/geometry/algorithms/is_convex.hpp
@@ -2,6 +2,11 @@
// Copyright (c) 2015 Barend Gehrels, Amsterdam, the Netherlands.
+// This file was modified by Oracle on 2017.
+// Modifications copyright (c) 2017 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
// 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)
@@ -10,17 +15,23 @@
#define BOOST_GEOMETRY_ALGORITHMS_IS_CONVEX_HPP
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
+
+#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/cs.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/core/point_type.hpp>
-#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
+#include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/iterators/ever_circling_iterator.hpp>
+#include <boost/geometry/strategies/default_strategy.hpp>
#include <boost/geometry/strategies/side.hpp>
-#include <boost/geometry/strategies/cartesian/side_by_triangle.hpp>
#include <boost/geometry/views/detail/normalized_view.hpp>
+
namespace boost { namespace geometry
{
@@ -31,15 +42,9 @@ namespace detail { namespace is_convex
struct ring_is_convex
{
- template <typename Ring>
- static inline bool apply(Ring const& ring)
+ template <typename Ring, typename SideStrategy>
+ static inline bool apply(Ring const& ring, SideStrategy const& strategy)
{
- typedef typename geometry::point_type<Ring>::type point_type;
- typedef typename strategy::side::services::default_strategy
- <
- typename cs_tag<point_type>::type
- >::type side_strategy_type;
-
std::size_t n = boost::size(ring);
if (boost::size(ring) < core_detail::closure::minimum_ring_size
<
@@ -86,7 +91,7 @@ struct ring_is_convex
// iterator
for (std::size_t i = 0; i < n; i++)
{
- int const side = side_strategy_type::apply(*previous, *current, *next);
+ int const side = strategy.apply(*previous, *current, *next);
if (side == 1)
{
// Next is on the left side of clockwise ring:
@@ -129,7 +134,8 @@ struct is_convex : not_implemented<Tag>
template <typename Box>
struct is_convex<Box, box_tag>
{
- static inline bool apply(Box const& )
+ template <typename Strategy>
+ static inline bool apply(Box const& , Strategy const& )
{
// Any box is convex (TODO: consider spherical boxes)
return true;
@@ -144,13 +150,71 @@ struct is_convex<Box, ring_tag> : detail::is_convex::ring_is_convex
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
-// TODO: variants
+namespace resolve_variant {
+
+template <typename Geometry>
+struct is_convex
+{
+ template <typename Strategy>
+ static bool apply(Geometry const& geometry, Strategy const& strategy)
+ {
+ concepts::check<Geometry>();
+ return dispatch::is_convex<Geometry>::apply(geometry, strategy);
+ }
+
+ static bool apply(Geometry const& geometry, geometry::default_strategy const&)
+ {
+ typedef typename strategy::side::services::default_strategy
+ <
+ typename cs_tag<Geometry>::type
+ >::type side_strategy;
+
+ return apply(geometry, side_strategy());
+ }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct is_convex<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+ template <typename Strategy>
+ struct visitor: boost::static_visitor<bool>
+ {
+ Strategy const& m_strategy;
+
+ visitor(Strategy const& strategy) : m_strategy(strategy) {}
+
+ template <typename Geometry>
+ bool operator()(Geometry const& geometry) const
+ {
+ return is_convex<Geometry>::apply(geometry, m_strategy);
+ }
+ };
+
+ template <typename Strategy>
+ static inline bool apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
+ Strategy const& strategy)
+ {
+ return boost::apply_visitor(visitor<Strategy>(strategy), geometry);
+ }
+};
+
+} // namespace resolve_variant
// TODO: documentation / qbk
template<typename Geometry>
inline bool is_convex(Geometry const& geometry)
{
- return dispatch::is_convex<Geometry>::apply(geometry);
+ return resolve_variant::is_convex
+ <
+ Geometry
+ >::apply(geometry, geometry::default_strategy());
+}
+
+// TODO: documentation / qbk
+template<typename Geometry, typename Strategy>
+inline bool is_convex(Geometry const& geometry, Strategy const& strategy)
+{
+ return resolve_variant::is_convex<Geometry>::apply(geometry, strategy);
}
diff --git a/boost/geometry/algorithms/overlaps.hpp b/boost/geometry/algorithms/overlaps.hpp
index bedf17599b..869a85ca98 100644
--- a/boost/geometry/algorithms/overlaps.hpp
+++ b/boost/geometry/algorithms/overlaps.hpp
@@ -20,214 +20,8 @@
#define BOOST_GEOMETRY_ALGORITHMS_OVERLAPS_HPP
-#include <cstddef>
+#include <boost/geometry/algorithms/detail/overlaps/interface.hpp>
+#include <boost/geometry/algorithms/detail/overlaps/implementation.hpp>
-#include <boost/geometry/core/access.hpp>
-
-#include <boost/geometry/algorithms/not_implemented.hpp>
-
-#include <boost/geometry/geometries/concepts/check.hpp>
-
-#include <boost/geometry/algorithms/relate.hpp>
-#include <boost/geometry/algorithms/detail/relate/relate_impl.hpp>
-
-
-namespace boost { namespace geometry
-{
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace overlaps
-{
-
-template
-<
- std::size_t Dimension,
- std::size_t DimensionCount
->
-struct box_box_loop
-{
- template <typename Box1, typename Box2>
- static inline void apply(Box1 const& b1, Box2 const& b2,
- bool& overlaps, bool& one_in_two, bool& two_in_one)
- {
- assert_dimension_equal<Box1, Box2>();
-
- typedef typename coordinate_type<Box1>::type coordinate_type1;
- typedef typename coordinate_type<Box2>::type coordinate_type2;
-
- coordinate_type1 const& min1 = get<min_corner, Dimension>(b1);
- coordinate_type1 const& max1 = get<max_corner, Dimension>(b1);
- coordinate_type2 const& min2 = get<min_corner, Dimension>(b2);
- coordinate_type2 const& max2 = get<max_corner, Dimension>(b2);
-
- // We might use the (not yet accepted) Boost.Interval
- // submission in the future
-
- // If:
- // B1: |-------|
- // B2: |------|
- // in any dimension -> no overlap
- if (max1 <= min2 || min1 >= max2)
- {
- overlaps = false;
- return;
- }
-
- // If:
- // B1: |--------------------|
- // B2: |-------------|
- // in all dimensions -> within, then no overlap
- // B1: |--------------------|
- // B2: |-------------|
- // this is "within-touch" -> then no overlap. So use < and >
- if (min1 < min2 || max1 > max2)
- {
- one_in_two = false;
- }
-
- // Same other way round
- if (min2 < min1 || max2 > max1)
- {
- two_in_one = false;
- }
-
- box_box_loop
- <
- Dimension + 1,
- DimensionCount
- >::apply(b1, b2, overlaps, one_in_two, two_in_one);
- }
-};
-
-template
-<
- std::size_t DimensionCount
->
-struct box_box_loop<DimensionCount, DimensionCount>
-{
- template <typename Box1, typename Box2>
- static inline void apply(Box1 const& , Box2 const&, bool&, bool&, bool&)
- {
- }
-};
-
-struct box_box
-{
- template <typename Box1, typename Box2, typename Strategy>
- static inline bool apply(Box1 const& b1, Box2 const& b2, Strategy const& /*strategy*/)
- {
- bool overlaps = true;
- bool within1 = true;
- bool within2 = true;
- box_box_loop
- <
- 0,
- dimension<Box1>::type::value
- >::apply(b1, b2, overlaps, within1, within2);
-
- /*
- \see http://docs.codehaus.org/display/GEOTDOC/02+Geometry+Relationships#02GeometryRelationships-Overlaps
- where is stated that "inside" is not an "overlap",
- this is true and is implemented as such.
- */
- return overlaps && ! within1 && ! within2;
- }
-};
-
-}} // namespace detail::overlaps
-#endif // DOXYGEN_NO_DETAIL
-
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-
-template
-<
- typename Geometry1,
- typename Geometry2,
- typename Tag1 = typename tag<Geometry1>::type,
- typename Tag2 = typename tag<Geometry2>::type
->
-struct overlaps
- : detail::relate::relate_impl
- <
- detail::de9im::static_mask_overlaps_type,
- Geometry1,
- Geometry2
- >
-{};
-
-
-template <typename Box1, typename Box2>
-struct overlaps<Box1, Box2, box_tag, box_tag>
- : detail::overlaps::box_box
-{};
-
-} // namespace dispatch
-#endif // DOXYGEN_NO_DISPATCH
-
-
-/*!
-\brief \brief_check2{overlap}
-\ingroup overlaps
-\tparam Geometry1 \tparam_geometry
-\tparam Geometry2 \tparam_geometry
-\tparam Strategy \tparam_strategy{Overlaps}
-\param geometry1 \param_geometry
-\param geometry2 \param_geometry
-\param strategy \param_strategy{overlaps}
-\return \return_check2{overlap}
-
-\qbk{distinguish,with strategy}
-\qbk{[include reference/algorithms/overlaps.qbk]}
-*/
-template <typename Geometry1, typename Geometry2, typename Strategy>
-inline bool overlaps(Geometry1 const& geometry1,
- Geometry2 const& geometry2,
- Strategy const& strategy)
-{
- concepts::check<Geometry1 const>();
- concepts::check<Geometry2 const>();
-
- return dispatch::overlaps
- <
- Geometry1,
- Geometry2
- >::apply(geometry1, geometry2, strategy);
-}
-
-/*!
-\brief \brief_check2{overlap}
-\ingroup overlaps
-\tparam Geometry1 \tparam_geometry
-\tparam Geometry2 \tparam_geometry
-\param geometry1 \param_geometry
-\param geometry2 \param_geometry
-\return \return_check2{overlap}
-
-\qbk{[include reference/algorithms/overlaps.qbk]}
-*/
-template <typename Geometry1, typename Geometry2>
-inline bool overlaps(Geometry1 const& geometry1, Geometry2 const& geometry2)
-{
- concepts::check<Geometry1 const>();
- concepts::check<Geometry2 const>();
-
- typedef typename strategy::relate::services::default_strategy
- <
- Geometry1,
- Geometry2
- >::type strategy_type;
-
- return dispatch::overlaps
- <
- Geometry1,
- Geometry2
- >::apply(geometry1, geometry2, strategy_type());
-}
-
-}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_OVERLAPS_HPP
diff --git a/boost/geometry/algorithms/point_on_surface.hpp b/boost/geometry/algorithms/point_on_surface.hpp
index e9041f937b..3f4d0f4afe 100644
--- a/boost/geometry/algorithms/point_on_surface.hpp
+++ b/boost/geometry/algorithms/point_on_surface.hpp
@@ -5,8 +5,8 @@
// Copyright (c) 2009-2013 Mateusz Loskot, London, UK.
// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland.
-// This file was modified by Oracle on 2014.
-// Modifications copyright (c) 2014 Oracle and/or its affiliates.
+// This file was modified by Oracle on 2014, 2017.
+// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -33,6 +33,7 @@
#include <boost/geometry/algorithms/detail/extreme_points.hpp>
#include <boost/geometry/strategies/cartesian/centroid_bashein_detmer.hpp>
+#include <boost/geometry/strategies/side.hpp>
namespace boost { namespace geometry
@@ -241,8 +242,9 @@ inline void replace_extremes_for_self_tangencies(Extremes& extremes, Intruders&
extremes = triangle;
}
-template <int Dimension, typename Geometry, typename Point>
-inline bool calculate_point_on_surface(Geometry const& geometry, Point& point)
+template <int Dimension, typename Geometry, typename Point, typename SideStrategy>
+inline bool calculate_point_on_surface(Geometry const& geometry, Point& point,
+ SideStrategy const& strategy)
{
typedef typename geometry::point_type<Geometry>::type point_type;
typedef typename geometry::coordinate_type<Geometry>::type coordinate_type;
@@ -250,7 +252,7 @@ inline bool calculate_point_on_surface(Geometry const& geometry, Point& point)
typedef std::vector<std::vector<point_type> > intruders_type;
intruders_type intruders;
- geometry::extreme_points<Dimension>(geometry, extremes, intruders);
+ geometry::extreme_points<Dimension>(geometry, extremes, intruders, strategy);
if (extremes.size() < 3)
{
@@ -291,22 +293,58 @@ inline bool calculate_point_on_surface(Geometry const& geometry, Point& point)
\tparam Geometry geometry type. This also defines the type of the output point
\param geometry Geometry to take point from
\param point Point to assign
+\param strategy side strategy
*/
-template <typename Geometry, typename Point>
-inline void point_on_surface(Geometry const& geometry, Point & point)
+template <typename Geometry, typename Point, typename SideStrategy>
+inline void point_on_surface(Geometry const& geometry, Point & point,
+ SideStrategy const& strategy)
{
concepts::check<Point>();
concepts::check<Geometry const>();
// First try in Y-direction (which should always succeed for valid polygons)
- if (! detail::point_on_surface::calculate_point_on_surface<1>(geometry, point))
+ if (! detail::point_on_surface::calculate_point_on_surface<1>(geometry, point, strategy))
{
// For invalid polygons, we might try X-direction
- detail::point_on_surface::calculate_point_on_surface<0>(geometry, point);
+ detail::point_on_surface::calculate_point_on_surface<0>(geometry, point, strategy);
}
}
/*!
+\brief Assigns a Point guaranteed to lie on the surface of the Geometry
+\tparam Geometry geometry type. This also defines the type of the output point
+\param geometry Geometry to take point from
+\param point Point to assign
+ */
+template <typename Geometry, typename Point>
+inline void point_on_surface(Geometry const& geometry, Point & point)
+{
+ typedef typename strategy::side::services::default_strategy
+ <
+ typename cs_tag<Geometry>::type
+ >::type strategy_type;
+
+ point_on_surface(geometry, point, strategy_type());
+}
+
+
+/*!
+\brief Returns point guaranteed to lie on the surface of the Geometry
+\tparam Geometry geometry type. This also defines the type of the output point
+\param geometry Geometry to take point from
+\param strategy side strategy
+\return The Point guaranteed to lie on the surface of the Geometry
+ */
+template<typename Geometry, typename SideStrategy>
+inline typename geometry::point_type<Geometry>::type
+return_point_on_surface(Geometry const& geometry, SideStrategy const& strategy)
+{
+ typename geometry::point_type<Geometry>::type result;
+ geometry::point_on_surface(geometry, result, strategy);
+ return result;
+}
+
+/*!
\brief Returns point guaranteed to lie on the surface of the Geometry
\tparam Geometry geometry type. This also defines the type of the output point
\param geometry Geometry to take point from
diff --git a/boost/geometry/algorithms/remove_spikes.hpp b/boost/geometry/algorithms/remove_spikes.hpp
index caa7fed9be..196b20c6a4 100644
--- a/boost/geometry/algorithms/remove_spikes.hpp
+++ b/boost/geometry/algorithms/remove_spikes.hpp
@@ -5,6 +5,11 @@
// Copyright (c) 2009-2013 Mateusz Loskot, London, UK.
// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland.
+// This file was modified by Oracle on 2017.
+// Modifications copyright (c) 2017 Oracle and/or its affiliates.
+
+// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
+
// 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)
@@ -34,6 +39,8 @@
#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
#include <boost/geometry/algorithms/clear.hpp>
+#include <boost/geometry/strategies/default_strategy.hpp>
+
#include <boost/geometry/util/condition.hpp>
@@ -59,20 +66,13 @@ namespace detail { namespace remove_spikes
{
-template <typename Range>
struct range_remove_spikes
{
- typedef typename strategy::side::services::default_strategy
- <
- typename cs_tag<Range>::type
- >::type side_strategy;
-
- typedef typename coordinate_type<Range>::type coordinate_type;
- typedef typename point_type<Range>::type point_type;
-
-
- static inline void apply(Range& range)
+ template <typename Range, typename SideStrategy>
+ static inline void apply(Range& range, SideStrategy const& strategy)
{
+ typedef typename point_type<Range>::type point_type;
+
std::size_t n = boost::size(range);
std::size_t const min_num_points = core_detail::closure::minimum_ring_size
<
@@ -91,7 +91,10 @@ struct range_remove_spikes
cleaned.push_back(*it);
while(cleaned.size() >= 3
- && detail::point_is_spike_or_equal(cleaned.back(), *(cleaned.end() - 3), *(cleaned.end() - 2)))
+ && detail::point_is_spike_or_equal(cleaned.back(),
+ *(cleaned.end() - 3),
+ *(cleaned.end() - 2),
+ strategy))
{
// Remove pen-ultimate point causing the spike (or which was equal)
cleaned.erase(cleaned.end() - 2);
@@ -110,13 +113,21 @@ struct range_remove_spikes
found = false;
// Check for spike in first point
int const penultimate = 2;
- while(cleaned.size() >= 3 && detail::point_is_spike_or_equal(cleaned.front(), *(cleaned.end() - penultimate), cleaned.back()))
+ while(cleaned.size() >= 3
+ && detail::point_is_spike_or_equal(cleaned.front(),
+ *(cleaned.end() - penultimate),
+ cleaned.back(),
+ strategy))
{
cleaned.pop_back();
found = true;
}
// Check for spike in second point
- while(cleaned.size() >= 3 && detail::point_is_spike_or_equal(*(cleaned.begin() + 1), cleaned.back(), cleaned.front()))
+ while(cleaned.size() >= 3
+ && detail::point_is_spike_or_equal(*(cleaned.begin() + 1),
+ cleaned.back(),
+ cleaned.front(),
+ strategy))
{
cleaned.pop_front();
found = true;
@@ -144,15 +155,13 @@ struct range_remove_spikes
};
-template <typename Polygon>
struct polygon_remove_spikes
{
- static inline void apply(Polygon& polygon)
+ template <typename Polygon, typename SideStrategy>
+ static inline void apply(Polygon& polygon, SideStrategy const& strategy)
{
- typedef typename geometry::ring_type<Polygon>::type ring_type;
-
- typedef range_remove_spikes<ring_type> per_range;
- per_range::apply(exterior_ring(polygon));
+ typedef range_remove_spikes per_range;
+ per_range::apply(exterior_ring(polygon), strategy);
typename interior_return_type<Polygon>::type
rings = interior_rings(polygon);
@@ -160,23 +169,24 @@ struct polygon_remove_spikes
for (typename detail::interior_iterator<Polygon>::type
it = boost::begin(rings); it != boost::end(rings); ++it)
{
- per_range::apply(*it);
+ per_range::apply(*it, strategy);
}
}
};
-template <typename MultiGeometry, typename SingleVersion>
+template <typename SingleVersion>
struct multi_remove_spikes
{
- static inline void apply(MultiGeometry& multi)
+ template <typename MultiGeometry, typename SideStrategy>
+ static inline void apply(MultiGeometry& multi, SideStrategy const& strategy)
{
for (typename boost::range_iterator<MultiGeometry>::type
it = boost::begin(multi);
it != boost::end(multi);
++it)
{
- SingleVersion::apply(*it);
+ SingleVersion::apply(*it, strategy);
}
}
};
@@ -199,21 +209,22 @@ template
>
struct remove_spikes
{
- static inline void apply(Geometry&)
+ template <typename SideStrategy>
+ static inline void apply(Geometry&, SideStrategy const&)
{}
};
template <typename Ring>
struct remove_spikes<Ring, ring_tag>
- : detail::remove_spikes::range_remove_spikes<Ring>
+ : detail::remove_spikes::range_remove_spikes
{};
template <typename Polygon>
struct remove_spikes<Polygon, polygon_tag>
- : detail::remove_spikes::polygon_remove_spikes<Polygon>
+ : detail::remove_spikes::polygon_remove_spikes
{};
@@ -221,11 +232,7 @@ template <typename MultiPolygon>
struct remove_spikes<MultiPolygon, multi_polygon_tag>
: detail::remove_spikes::multi_remove_spikes
<
- MultiPolygon,
detail::remove_spikes::polygon_remove_spikes
- <
- typename boost::range_value<MultiPolygon>::type
- >
>
{};
@@ -239,28 +246,46 @@ namespace resolve_variant {
template <typename Geometry>
struct remove_spikes
{
- static void apply(Geometry& geometry)
+ template <typename Strategy>
+ static void apply(Geometry& geometry, Strategy const& strategy)
{
concepts::check<Geometry>();
- dispatch::remove_spikes<Geometry>::apply(geometry);
+ dispatch::remove_spikes<Geometry>::apply(geometry, strategy);
+ }
+
+ static void apply(Geometry& geometry, geometry::default_strategy const&)
+ {
+ typedef typename strategy::side::services::default_strategy
+ <
+ typename cs_tag<Geometry>::type
+ >::type side_strategy;
+
+ apply(geometry, side_strategy());
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct remove_spikes<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
{
+ template <typename Strategy>
struct visitor: boost::static_visitor<void>
{
+ Strategy const& m_strategy;
+
+ visitor(Strategy const& strategy) : m_strategy(strategy) {}
+
template <typename Geometry>
void operator()(Geometry& geometry) const
{
- remove_spikes<Geometry>::apply(geometry);
+ remove_spikes<Geometry>::apply(geometry, m_strategy);
}
};
- static inline void apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry)
+ template <typename Strategy>
+ static inline void apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry,
+ Strategy const& strategy)
{
- boost::apply_visitor(visitor(), geometry);
+ boost::apply_visitor(visitor<Strategy>(strategy), geometry);
}
};
@@ -275,7 +300,20 @@ struct remove_spikes<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
template <typename Geometry>
inline void remove_spikes(Geometry& geometry)
{
- resolve_variant::remove_spikes<Geometry>::apply(geometry);
+ resolve_variant::remove_spikes<Geometry>::apply(geometry, geometry::default_strategy());
+}
+
+/*!
+ \ingroup remove_spikes
+ \tparam Geometry geometry type
+ \tparam Strategy side strategy type
+ \param geometry the geometry to make remove_spikes
+ \param strategy the side strategy used by the algorithm
+*/
+template <typename Geometry, typename Strategy>
+inline void remove_spikes(Geometry& geometry, Strategy const& strategy)
+{
+ resolve_variant::remove_spikes<Geometry>::apply(geometry, strategy);
}
diff --git a/boost/geometry/algorithms/touches.hpp b/boost/geometry/algorithms/touches.hpp
index 49e104d258..d358c3f20e 100644
--- a/boost/geometry/algorithms/touches.hpp
+++ b/boost/geometry/algorithms/touches.hpp
@@ -21,687 +21,8 @@
#define BOOST_GEOMETRY_ALGORITHMS_TOUCHES_HPP
-#include <deque>
+#include <boost/geometry/algorithms/detail/touches/interface.hpp>
+#include <boost/geometry/algorithms/detail/touches/implementation.hpp>
-#include <boost/variant/apply_visitor.hpp>
-#include <boost/variant/static_visitor.hpp>
-#include <boost/variant/variant_fwd.hpp>
-
-#include <boost/geometry/geometries/concepts/check.hpp>
-#include <boost/geometry/algorithms/detail/for_each_range.hpp>
-#include <boost/geometry/algorithms/detail/overlay/overlay.hpp>
-#include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp>
-#include <boost/geometry/algorithms/disjoint.hpp>
-#include <boost/geometry/algorithms/intersects.hpp>
-#include <boost/geometry/algorithms/num_geometries.hpp>
-#include <boost/geometry/algorithms/detail/sub_range.hpp>
-#include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
-
-#include <boost/geometry/algorithms/relate.hpp>
-#include <boost/geometry/algorithms/detail/relate/relate_impl.hpp>
-
-
-namespace boost { namespace geometry
-{
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace touches
-{
-
-// Box/Box
-
-template
-<
- std::size_t Dimension,
- std::size_t DimensionCount
->
-struct box_box_loop
-{
- template <typename Box1, typename Box2>
- static inline bool apply(Box1 const& b1, Box2 const& b2, bool & touch)
- {
- typedef typename coordinate_type<Box1>::type coordinate_type1;
- typedef typename coordinate_type<Box2>::type coordinate_type2;
-
- coordinate_type1 const& min1 = get<min_corner, Dimension>(b1);
- coordinate_type1 const& max1 = get<max_corner, Dimension>(b1);
- coordinate_type2 const& min2 = get<min_corner, Dimension>(b2);
- coordinate_type2 const& max2 = get<max_corner, Dimension>(b2);
-
- // TODO assert or exception?
- //BOOST_GEOMETRY_ASSERT(min1 <= max1 && min2 <= max2);
-
- if (max1 < min2 || max2 < min1)
- {
- return false;
- }
-
- if (max1 == min2 || max2 == min1)
- {
- touch = true;
- }
-
- return box_box_loop
- <
- Dimension + 1,
- DimensionCount
- >::apply(b1, b2, touch);
- }
-};
-
-template
-<
- std::size_t DimensionCount
->
-struct box_box_loop<DimensionCount, DimensionCount>
-{
- template <typename Box1, typename Box2>
- static inline bool apply(Box1 const& , Box2 const&, bool &)
- {
- return true;
- }
-};
-
-struct box_box
-{
- template <typename Box1, typename Box2, typename Strategy>
- static inline bool apply(Box1 const& b1, Box2 const& b2, Strategy const& /*strategy*/)
- {
- BOOST_STATIC_ASSERT((boost::is_same
- <
- typename geometry::coordinate_system<Box1>::type,
- typename geometry::coordinate_system<Box2>::type
- >::value
- ));
- assert_dimension_equal<Box1, Box2>();
-
- bool touches = false;
- bool ok = box_box_loop
- <
- 0,
- dimension<Box1>::type::value
- >::apply(b1, b2, touches);
-
- return ok && touches;
- }
-};
-
-// Areal/Areal
-
-struct areal_interrupt_policy
-{
- static bool const enabled = true;
- bool found_touch;
- bool found_not_touch;
-
- // dummy variable required by self_get_turn_points::get_turns
- static bool const has_intersections = false;
-
- inline bool result()
- {
- return found_touch && !found_not_touch;
- }
-
- inline areal_interrupt_policy()
- : found_touch(false), found_not_touch(false)
- {}
-
- template <typename Range>
- inline bool apply(Range const& range)
- {
- // if already rejected (temp workaround?)
- if ( found_not_touch )
- return true;
-
- typedef typename boost::range_iterator<Range const>::type iterator;
- for ( iterator it = boost::begin(range) ; it != boost::end(range) ; ++it )
- {
- if ( it->has(overlay::operation_intersection) )
- {
- found_not_touch = true;
- return true;
- }
-
- switch(it->method)
- {
- case overlay::method_crosses:
- found_not_touch = true;
- return true;
- case overlay::method_equal:
- // Segment spatially equal means: at the right side
- // the polygon internally overlaps. So return false.
- found_not_touch = true;
- return true;
- case overlay::method_touch:
- case overlay::method_touch_interior:
- case overlay::method_collinear:
- if ( ok_for_touch(*it) )
- {
- found_touch = true;
- }
- else
- {
- found_not_touch = true;
- return true;
- }
- break;
- case overlay::method_none :
- case overlay::method_disjoint :
- case overlay::method_error :
- break;
- }
- }
-
- return false;
- }
-
- template <typename Turn>
- inline bool ok_for_touch(Turn const& turn)
- {
- return turn.both(overlay::operation_union)
- || turn.both(overlay::operation_blocked)
- || turn.combination(overlay::operation_union, overlay::operation_blocked)
- ;
- }
-};
-
-template<typename Geometry, typename PointInRingStrategy>
-struct check_each_ring_for_within
-{
- bool has_within;
- Geometry const& m_geometry;
- PointInRingStrategy const& m_strategy;
-
- inline check_each_ring_for_within(Geometry const& g, PointInRingStrategy const& strategy)
- : has_within(false)
- , m_geometry(g)
- , m_strategy(strategy)
- {}
-
- template <typename Range>
- inline void apply(Range const& range)
- {
- typename geometry::point_type<Range>::type p;
- geometry::point_on_border(p, range);
- if ( !has_within && geometry::within(p, m_geometry, m_strategy) )
- {
- has_within = true;
- }
- }
-};
-
-template <typename FirstGeometry, typename SecondGeometry, typename IntersectionStrategy>
-inline bool rings_containing(FirstGeometry const& geometry1,
- SecondGeometry const& geometry2,
- IntersectionStrategy const& strategy)
-{
- // NOTE: This strategy could be defined inside IntersectionStrategy
- typedef typename IntersectionStrategy::template point_in_geometry_strategy
- <
- FirstGeometry, SecondGeometry
- >::type point_in_ring_strategy_type;
-
- point_in_ring_strategy_type point_in_ring_strategy
- = strategy.template get_point_in_geometry_strategy<FirstGeometry, SecondGeometry>();
-
- check_each_ring_for_within
- <
- FirstGeometry, point_in_ring_strategy_type
- > checker(geometry1, point_in_ring_strategy);
- geometry::detail::for_each_range(geometry2, checker);
- return checker.has_within;
-}
-
-template <typename Geometry1, typename Geometry2>
-struct areal_areal
-{
- template <typename IntersectionStrategy>
- static inline bool apply(Geometry1 const& geometry1,
- Geometry2 const& geometry2,
- IntersectionStrategy const& strategy)
- {
- typedef detail::no_rescale_policy rescale_policy_type;
- typedef typename geometry::point_type<Geometry1>::type point_type;
- typedef detail::overlay::turn_info
- <
- point_type,
- typename segment_ratio_type<point_type, rescale_policy_type>::type
- > turn_info;
-
- std::deque<turn_info> turns;
- detail::touches::areal_interrupt_policy policy;
- rescale_policy_type robust_policy;
- boost::geometry::get_turns
- <
- detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value,
- detail::overlay::do_reverse<geometry::point_order<Geometry2>::value>::value,
- detail::overlay::assign_null_policy
- >(geometry1, geometry2, strategy, robust_policy, turns, policy);
-
- return policy.result()
- && ! geometry::detail::touches::rings_containing(geometry1, geometry2, strategy)
- && ! geometry::detail::touches::rings_containing(geometry2, geometry1, strategy);
- }
-};
-
-// P/*
-
-struct use_point_in_geometry
-{
- template <typename Point, typename Geometry, typename Strategy>
- static inline bool apply(Point const& point, Geometry const& geometry, Strategy const& strategy)
- {
- return detail::within::point_in_geometry(point, geometry, strategy) == 0;
- }
-};
-
-}}
-#endif // DOXYGEN_NO_DETAIL
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch {
-
-// TODO: Since CastedTags are used is Reverse needed?
-
-template
-<
- typename Geometry1,
- typename Geometry2,
- typename Tag1 = typename tag<Geometry1>::type,
- typename Tag2 = typename tag<Geometry2>::type,
- typename CastedTag1 = typename tag_cast<Tag1, pointlike_tag, linear_tag, areal_tag>::type,
- typename CastedTag2 = typename tag_cast<Tag2, pointlike_tag, linear_tag, areal_tag>::type,
- bool Reverse = reverse_dispatch<Geometry1, Geometry2>::type::value
->
-struct touches
- : not_implemented<Tag1, Tag2>
-{};
-
-// If reversal is needed, perform it
-template
-<
- typename Geometry1, typename Geometry2,
- typename Tag1, typename Tag2,
- typename CastedTag1, typename CastedTag2
->
-struct touches<Geometry1, Geometry2, Tag1, Tag2, CastedTag1, CastedTag2, true>
- : touches<Geometry2, Geometry1, Tag2, Tag1, CastedTag2, CastedTag1, false>
-{
- template <typename Strategy>
- static inline bool apply(Geometry1 const& g1, Geometry2 const& g2, Strategy const& strategy)
- {
- return touches<Geometry2, Geometry1>::apply(g2, g1, strategy);
- }
-};
-
-// P/P
-
-template <typename Geometry1, typename Geometry2, typename Tag2>
-struct touches<Geometry1, Geometry2, point_tag, Tag2, pointlike_tag, pointlike_tag, false>
-{
- template <typename Strategy>
- static inline bool apply(Geometry1 const& , Geometry2 const& , Strategy const&)
- {
- return false;
- }
-};
-
-template <typename Geometry1, typename Geometry2, typename Tag2>
-struct touches<Geometry1, Geometry2, multi_point_tag, Tag2, pointlike_tag, pointlike_tag, false>
-{
- template <typename Strategy>
- static inline bool apply(Geometry1 const&, Geometry2 const&, Strategy const&)
- {
- return false;
- }
-};
-
-// P/*
-
-template <typename Point, typename Geometry, typename Tag2, typename CastedTag2>
-struct touches<Point, Geometry, point_tag, Tag2, pointlike_tag, CastedTag2, false>
- : detail::touches::use_point_in_geometry
-{};
-
-// TODO: support touches(MPt, Linear/Areal)
-
-// Box/Box
-
-template <typename Box1, typename Box2, typename CastedTag1, typename CastedTag2>
-struct touches<Box1, Box2, box_tag, box_tag, CastedTag1, CastedTag2, false>
- : detail::touches::box_box
-{};
-
-template <typename Box1, typename Box2>
-struct touches<Box1, Box2, box_tag, box_tag, areal_tag, areal_tag, false>
- : detail::touches::box_box
-{};
-
-// L/L
-
-template <typename Linear1, typename Linear2, typename Tag1, typename Tag2>
-struct touches<Linear1, Linear2, Tag1, Tag2, linear_tag, linear_tag, false>
- : detail::relate::relate_impl
- <
- detail::de9im::static_mask_touches_type,
- Linear1,
- Linear2
- >
-{};
-
-// L/A
-
-template <typename Linear, typename Areal, typename Tag1, typename Tag2>
-struct touches<Linear, Areal, Tag1, Tag2, linear_tag, areal_tag, false>
- : detail::relate::relate_impl
- <
- detail::de9im::static_mask_touches_type,
- Linear,
- Areal
- >
-{};
-
-// A/L
-template <typename Linear, typename Areal, typename Tag1, typename Tag2>
-struct touches<Areal, Linear, Tag1, Tag2, areal_tag, linear_tag, false>
- : detail::relate::relate_impl
- <
- detail::de9im::static_mask_touches_type,
- Areal,
- Linear
- >
-{};
-
-// A/A
-
-template <typename Areal1, typename Areal2, typename Tag1, typename Tag2>
-struct touches<Areal1, Areal2, Tag1, Tag2, areal_tag, areal_tag, false>
- : detail::relate::relate_impl
- <
- detail::de9im::static_mask_touches_type,
- Areal1,
- Areal2
- >
-{};
-
-template <typename Areal1, typename Areal2>
-struct touches<Areal1, Areal2, ring_tag, ring_tag, areal_tag, areal_tag, false>
- : detail::touches::areal_areal<Areal1, Areal2>
-{};
-
-} // namespace dispatch
-#endif // DOXYGEN_NO_DISPATCH
-
-
-namespace resolve_strategy
-{
-
-struct touches
-{
- template <typename Geometry1, typename Geometry2, typename Strategy>
- static inline bool apply(Geometry1 const& geometry1,
- Geometry2 const& geometry2,
- Strategy const& strategy)
- {
- return dispatch::touches
- <
- Geometry1, Geometry2
- >::apply(geometry1, geometry2, strategy);
- }
-
- template <typename Geometry1, typename Geometry2>
- static inline bool apply(Geometry1 const& geometry1,
- Geometry2 const& geometry2,
- default_strategy)
- {
- typedef typename strategy::relate::services::default_strategy
- <
- Geometry1,
- Geometry2
- >::type strategy_type;
-
- return dispatch::touches
- <
- Geometry1, Geometry2
- >::apply(geometry1, geometry2, strategy_type());
- }
-};
-
-} // namespace resolve_strategy
-
-
-namespace resolve_variant {
-
-template <typename Geometry1, typename Geometry2>
-struct touches
-{
- template <typename Strategy>
- static bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
- {
- concepts::check<Geometry1 const>();
- concepts::check<Geometry2 const>();
-
- return resolve_strategy::touches::apply(geometry1, geometry2, strategy);
- }
-};
-
-template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
-struct touches<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
-{
- template <typename Strategy>
- struct visitor: boost::static_visitor<bool>
- {
- Geometry2 const& m_geometry2;
- Strategy const& m_strategy;
-
- visitor(Geometry2 const& geometry2, Strategy const& strategy)
- : m_geometry2(geometry2)
- , m_strategy(strategy)
- {}
-
- template <typename Geometry1>
- bool operator()(Geometry1 const& geometry1) const
- {
- return touches<Geometry1, Geometry2>::apply(geometry1, m_geometry2, m_strategy);
- }
- };
-
- template <typename Strategy>
- static inline bool apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
- Geometry2 const& geometry2,
- Strategy const& strategy)
- {
- return boost::apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1);
- }
-};
-
-template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
-struct touches<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
-{
- template <typename Strategy>
- struct visitor: boost::static_visitor<bool>
- {
- Geometry1 const& m_geometry1;
- Strategy const& m_strategy;
-
- visitor(Geometry1 const& geometry1, Strategy const& strategy)
- : m_geometry1(geometry1)
- , m_strategy(strategy)
- {}
-
- template <typename Geometry2>
- bool operator()(Geometry2 const& geometry2) const
- {
- return touches<Geometry1, Geometry2>::apply(m_geometry1, geometry2, m_strategy);
- }
- };
-
- template <typename Strategy>
- static inline bool apply(Geometry1 const& geometry1,
- boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2,
- Strategy const& strategy)
- {
- return boost::apply_visitor(visitor<Strategy>(geometry1, strategy), geometry2);
- }
-};
-
-template <BOOST_VARIANT_ENUM_PARAMS(typename T1),
- BOOST_VARIANT_ENUM_PARAMS(typename T2)>
-struct touches<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>,
- boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> >
-{
- template <typename Strategy>
- struct visitor: boost::static_visitor<bool>
- {
- Strategy const& m_strategy;
-
- visitor(Strategy const& strategy)
- : m_strategy(strategy)
- {}
-
- template <typename Geometry1, typename Geometry2>
- bool operator()(Geometry1 const& geometry1,
- Geometry2 const& geometry2) const
- {
- return touches<Geometry1, Geometry2>::apply(geometry1, geometry2, m_strategy);
- }
- };
-
- template <typename Strategy>
- static inline bool apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1,
- boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2,
- Strategy const& strategy)
- {
- return boost::apply_visitor(visitor<Strategy>(strategy), geometry1, geometry2);
- }
-};
-
-template <typename Geometry>
-struct self_touches
-{
- static bool apply(Geometry const& geometry)
- {
- concepts::check<Geometry const>();
-
- typedef typename strategy::relate::services::default_strategy
- <
- Geometry, Geometry
- >::type strategy_type;
- typedef detail::no_rescale_policy rescale_policy_type;
- typedef typename geometry::point_type<Geometry>::type point_type;
- typedef detail::overlay::turn_info
- <
- point_type,
- typename segment_ratio_type<point_type, rescale_policy_type>::type
- > turn_info;
-
- typedef detail::overlay::get_turn_info
- <
- detail::overlay::assign_null_policy
- > policy_type;
-
- std::deque<turn_info> turns;
- detail::touches::areal_interrupt_policy policy;
- strategy_type strategy;
- rescale_policy_type robust_policy;
- detail::self_get_turn_points::get_turns
- <
- policy_type
- >::apply(geometry, strategy, robust_policy, turns, policy);
-
- return policy.result();
- }
-};
-
-template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
-struct self_touches<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
-{
- struct visitor: boost::static_visitor<bool>
- {
- template <typename Geometry>
- bool operator()(Geometry const& geometry) const
- {
- return self_touches<Geometry>::apply(geometry);
- }
- };
-
- static inline bool
- apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry)
- {
- return boost::apply_visitor(visitor(), geometry);
- }
-};
-
-} // namespace resolve_variant
-
-
-/*!
-\brief \brief_check{has at least one touching point (self-tangency)}
-\note This function can be called for one geometry (self-tangency) and
- also for two geometries (touch)
-\ingroup touches
-\tparam Geometry \tparam_geometry
-\param geometry \param_geometry
-\return \return_check{is self-touching}
-
-\qbk{distinguish,one geometry}
-\qbk{[def __one_parameter__]}
-\qbk{[include reference/algorithms/touches.qbk]}
-*/
-template <typename Geometry>
-inline bool touches(Geometry const& geometry)
-{
- return resolve_variant::self_touches<Geometry>::apply(geometry);
-}
-
-
-/*!
-\brief \brief_check2{have at least one touching point (tangent - non overlapping)}
-\ingroup touches
-\tparam Geometry1 \tparam_geometry
-\tparam Geometry2 \tparam_geometry
-\param geometry1 \param_geometry
-\param geometry2 \param_geometry
-\return \return_check2{touch each other}
-
-\qbk{distinguish,two geometries}
-\qbk{[include reference/algorithms/touches.qbk]}
- */
-template <typename Geometry1, typename Geometry2>
-inline bool touches(Geometry1 const& geometry1, Geometry2 const& geometry2)
-{
- return resolve_variant::touches
- <
- Geometry1, Geometry2
- >::apply(geometry1, geometry2, default_strategy());
-}
-
-/*!
-\brief \brief_check2{have at least one touching point (tangent - non overlapping)}
-\ingroup touches
-\tparam Geometry1 \tparam_geometry
-\tparam Geometry2 \tparam_geometry
-\tparam Strategy \tparam_strategy{Touches}
-\param geometry1 \param_geometry
-\param geometry2 \param_geometry
-\param strategy \param_strategy{touches}
-\return \return_check2{touch each other}
-
-\qbk{distinguish,with strategy}
-\qbk{[include reference/algorithms/touches.qbk]}
- */
-template <typename Geometry1, typename Geometry2, typename Strategy>
-inline bool touches(Geometry1 const& geometry1,
- Geometry2 const& geometry2,
- Strategy const& strategy)
-{
- return resolve_variant::touches
- <
- Geometry1, Geometry2
- >::apply(geometry1, geometry2, strategy);
-}
-
-
-}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_TOUCHES_HPP
diff --git a/boost/geometry/algorithms/within.hpp b/boost/geometry/algorithms/within.hpp
index ba170dd27b..e657bbda24 100644
--- a/boost/geometry/algorithms/within.hpp
+++ b/boost/geometry/algorithms/within.hpp
@@ -20,504 +20,8 @@
#define BOOST_GEOMETRY_ALGORITHMS_WITHIN_HPP
-#include <cstddef>
+#include <boost/geometry/algorithms/detail/within/interface.hpp>
+#include <boost/geometry/algorithms/detail/within/implementation.hpp>
-#include <boost/concept_check.hpp>
-#include <boost/range.hpp>
-
-#include <boost/variant/apply_visitor.hpp>
-#include <boost/variant/static_visitor.hpp>
-#include <boost/variant/variant_fwd.hpp>
-
-#include <boost/geometry/algorithms/make.hpp>
-#include <boost/geometry/algorithms/not_implemented.hpp>
-
-#include <boost/geometry/core/access.hpp>
-#include <boost/geometry/core/closure.hpp>
-#include <boost/geometry/core/cs.hpp>
-#include <boost/geometry/core/exterior_ring.hpp>
-#include <boost/geometry/core/interior_rings.hpp>
-#include <boost/geometry/core/point_order.hpp>
-#include <boost/geometry/core/ring_type.hpp>
-#include <boost/geometry/core/interior_rings.hpp>
-#include <boost/geometry/core/tags.hpp>
-
-#include <boost/geometry/geometries/concepts/check.hpp>
-#include <boost/geometry/strategies/concepts/within_concept.hpp>
-#include <boost/geometry/strategies/default_strategy.hpp>
-#include <boost/geometry/strategies/within.hpp>
-#include <boost/geometry/util/math.hpp>
-#include <boost/geometry/util/order_as_direction.hpp>
-#include <boost/geometry/views/closeable_view.hpp>
-#include <boost/geometry/views/reversible_view.hpp>
-
-#include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp>
-#include <boost/geometry/algorithms/relate.hpp>
-
-#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
-#include <boost/geometry/algorithms/detail/overlay/do_reverse.hpp>
-#include <deque>
-
-namespace boost { namespace geometry
-{
-
-#ifndef DOXYGEN_NO_DETAIL
-namespace detail { namespace within {
-
-struct use_point_in_geometry
-{
- template <typename Geometry1, typename Geometry2, typename Strategy>
- static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
- {
- return detail::within::point_in_geometry(geometry1, geometry2, strategy) == 1;
- }
-};
-
-struct use_relate
-{
- template <typename Geometry1, typename Geometry2, typename Strategy>
- static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy)
- {
- typedef typename detail::de9im::static_mask_within_type
- <
- Geometry1, Geometry2
- >::type within_mask;
- return geometry::relate(geometry1, geometry2, within_mask(), strategy);
- }
-};
-
-}} // namespace detail::within
-#endif // DOXYGEN_NO_DETAIL
-
-#ifndef DOXYGEN_NO_DISPATCH
-namespace dispatch
-{
-
-template
-<
- typename Geometry1,
- typename Geometry2,
- typename Tag1 = typename tag<Geometry1>::type,
- typename Tag2 = typename tag<Geometry2>::type
->
-struct within
- : not_implemented<Tag1, Tag2>
-{};
-
-
-template <typename Point, typename Box>
-struct within<Point, Box, point_tag, box_tag>
-{
- template <typename Strategy>
- static inline bool apply(Point const& point, Box const& box, Strategy const& strategy)
- {
- boost::ignore_unused_variable_warning(strategy);
- return strategy.apply(point, box);
- }
-};
-
-template <typename Box1, typename Box2>
-struct within<Box1, Box2, box_tag, box_tag>
-{
- template <typename Strategy>
- static inline bool apply(Box1 const& box1, Box2 const& box2, Strategy const& strategy)
- {
- assert_dimension_equal<Box1, Box2>();
- boost::ignore_unused_variable_warning(strategy);
- return strategy.apply(box1, box2);
- }
-};
-
-// P/P
-
-template <typename Point1, typename Point2>
-struct within<Point1, Point2, point_tag, point_tag>
- : public detail::within::use_point_in_geometry
-{};
-
-template <typename Point, typename MultiPoint>
-struct within<Point, MultiPoint, point_tag, multi_point_tag>
- : public detail::within::use_point_in_geometry
-{};
-
-// P/L
-
-template <typename Point, typename Segment>
-struct within<Point, Segment, point_tag, segment_tag>
- : public detail::within::use_point_in_geometry
-{};
-
-template <typename Point, typename Linestring>
-struct within<Point, Linestring, point_tag, linestring_tag>
- : public detail::within::use_point_in_geometry
-{};
-
-template <typename Point, typename MultiLinestring>
-struct within<Point, MultiLinestring, point_tag, multi_linestring_tag>
- : public detail::within::use_point_in_geometry
-{};
-
-// P/A
-
-template <typename Point, typename Ring>
-struct within<Point, Ring, point_tag, ring_tag>
- : public detail::within::use_point_in_geometry
-{};
-
-template <typename Point, typename Polygon>
-struct within<Point, Polygon, point_tag, polygon_tag>
- : public detail::within::use_point_in_geometry
-{};
-
-template <typename Point, typename MultiPolygon>
-struct within<Point, MultiPolygon, point_tag, multi_polygon_tag>
- : public detail::within::use_point_in_geometry
-{};
-
-// L/L
-
-template <typename Linestring1, typename Linestring2>
-struct within<Linestring1, Linestring2, linestring_tag, linestring_tag>
- : public detail::within::use_relate
-{};
-
-template <typename Linestring, typename MultiLinestring>
-struct within<Linestring, MultiLinestring, linestring_tag, multi_linestring_tag>
- : public detail::within::use_relate
-{};
-
-template <typename MultiLinestring, typename Linestring>
-struct within<MultiLinestring, Linestring, multi_linestring_tag, linestring_tag>
- : public detail::within::use_relate
-{};
-
-template <typename MultiLinestring1, typename MultiLinestring2>
-struct within<MultiLinestring1, MultiLinestring2, multi_linestring_tag, multi_linestring_tag>
- : public detail::within::use_relate
-{};
-
-// L/A
-
-template <typename Linestring, typename Ring>
-struct within<Linestring, Ring, linestring_tag, ring_tag>
- : public detail::within::use_relate
-{};
-
-template <typename MultiLinestring, typename Ring>
-struct within<MultiLinestring, Ring, multi_linestring_tag, ring_tag>
- : public detail::within::use_relate
-{};
-
-template <typename Linestring, typename Polygon>
-struct within<Linestring, Polygon, linestring_tag, polygon_tag>
- : public detail::within::use_relate
-{};
-
-template <typename MultiLinestring, typename Polygon>
-struct within<MultiLinestring, Polygon, multi_linestring_tag, polygon_tag>
- : public detail::within::use_relate
-{};
-
-template <typename Linestring, typename MultiPolygon>
-struct within<Linestring, MultiPolygon, linestring_tag, multi_polygon_tag>
- : public detail::within::use_relate
-{};
-
-template <typename MultiLinestring, typename MultiPolygon>
-struct within<MultiLinestring, MultiPolygon, multi_linestring_tag, multi_polygon_tag>
- : public detail::within::use_relate
-{};
-
-// A/A
-
-template <typename Ring1, typename Ring2>
-struct within<Ring1, Ring2, ring_tag, ring_tag>
- : public detail::within::use_relate
-{};
-
-template <typename Ring, typename Polygon>
-struct within<Ring, Polygon, ring_tag, polygon_tag>
- : public detail::within::use_relate
-{};
-
-template <typename Polygon, typename Ring>
-struct within<Polygon, Ring, polygon_tag, ring_tag>
- : public detail::within::use_relate
-{};
-
-template <typename Polygon1, typename Polygon2>
-struct within<Polygon1, Polygon2, polygon_tag, polygon_tag>
- : public detail::within::use_relate
-{};
-
-template <typename Ring, typename MultiPolygon>
-struct within<Ring, MultiPolygon, ring_tag, multi_polygon_tag>
- : public detail::within::use_relate
-{};
-
-template <typename MultiPolygon, typename Ring>
-struct within<MultiPolygon, Ring, multi_polygon_tag, ring_tag>
- : public detail::within::use_relate
-{};
-
-template <typename Polygon, typename MultiPolygon>
-struct within<Polygon, MultiPolygon, polygon_tag, multi_polygon_tag>
- : public detail::within::use_relate
-{};
-
-template <typename MultiPolygon, typename Polygon>
-struct within<MultiPolygon, Polygon, multi_polygon_tag, polygon_tag>
- : public detail::within::use_relate
-{};
-
-template <typename MultiPolygon1, typename MultiPolygon2>
-struct within<MultiPolygon1, MultiPolygon2, multi_polygon_tag, multi_polygon_tag>
- : public detail::within::use_relate
-{};
-
-} // namespace dispatch
-#endif // DOXYGEN_NO_DISPATCH
-
-
-namespace resolve_strategy
-{
-
-struct within
-{
- template <typename Geometry1, typename Geometry2, typename Strategy>
- static inline bool apply(Geometry1 const& geometry1,
- Geometry2 const& geometry2,
- Strategy const& strategy)
- {
- concepts::within::check
- <
- typename tag<Geometry1>::type,
- typename tag<Geometry2>::type,
- typename tag_cast<typename tag<Geometry2>::type, areal_tag>::type,
- Strategy
- >();
-
- return dispatch::within<Geometry1, Geometry2>::apply(geometry1, geometry2, strategy);
- }
-
- template <typename Geometry1, typename Geometry2>
- static inline bool apply(Geometry1 const& geometry1,
- Geometry2 const& geometry2,
- default_strategy)
- {
- typedef typename strategy::within::services::default_strategy
- <
- Geometry1,
- Geometry2
- >::type strategy_type;
-
- return apply(geometry1, geometry2, strategy_type());
- }
-};
-
-} // namespace resolve_strategy
-
-
-namespace resolve_variant
-{
-
-template <typename Geometry1, typename Geometry2>
-struct within
-{
- template <typename Strategy>
- static inline bool apply(Geometry1 const& geometry1,
- Geometry2 const& geometry2,
- Strategy const& strategy)
- {
- concepts::check<Geometry1 const>();
- concepts::check<Geometry2 const>();
- assert_dimension_equal<Geometry1, Geometry2>();
-
- return resolve_strategy::within::apply(geometry1,
- geometry2,
- strategy);
- }
-};
-
-template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
-struct within<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
-{
- template <typename Strategy>
- struct visitor: boost::static_visitor<bool>
- {
- Geometry2 const& m_geometry2;
- Strategy const& m_strategy;
-
- visitor(Geometry2 const& geometry2, Strategy const& strategy)
- : m_geometry2(geometry2)
- , m_strategy(strategy)
- {}
-
- template <typename Geometry1>
- bool operator()(Geometry1 const& geometry1) const
- {
- return within<Geometry1, Geometry2>::apply(geometry1,
- m_geometry2,
- m_strategy);
- }
- };
-
- template <typename Strategy>
- static inline bool
- apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
- Geometry2 const& geometry2,
- Strategy const& strategy)
- {
- return boost::apply_visitor(visitor<Strategy>(geometry2, strategy),
- geometry1);
- }
-};
-
-template <typename Geometry1, BOOST_VARIANT_ENUM_PARAMS(typename T)>
-struct within<Geometry1, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
-{
- template <typename Strategy>
- struct visitor: boost::static_visitor<bool>
- {
- Geometry1 const& m_geometry1;
- Strategy const& m_strategy;
-
- visitor(Geometry1 const& geometry1, Strategy const& strategy)
- : m_geometry1(geometry1)
- , m_strategy(strategy)
- {}
-
- template <typename Geometry2>
- bool operator()(Geometry2 const& geometry2) const
- {
- return within<Geometry1, Geometry2>::apply(m_geometry1,
- geometry2,
- m_strategy);
- }
- };
-
- template <typename Strategy>
- static inline bool
- apply(Geometry1 const& geometry1,
- boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry2,
- Strategy const& strategy)
- {
- return boost::apply_visitor(visitor<Strategy>(geometry1, strategy),
- geometry2
- );
- }
-};
-
-template <
- BOOST_VARIANT_ENUM_PARAMS(typename T1),
- BOOST_VARIANT_ENUM_PARAMS(typename T2)
->
-struct within<
- boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)>,
- boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)>
->
-{
- template <typename Strategy>
- struct visitor: boost::static_visitor<bool>
- {
- Strategy const& m_strategy;
-
- visitor(Strategy const& strategy): m_strategy(strategy) {}
-
- template <typename Geometry1, typename Geometry2>
- bool operator()(Geometry1 const& geometry1,
- Geometry2 const& geometry2) const
- {
- return within<Geometry1, Geometry2>::apply(geometry1,
- geometry2,
- m_strategy);
- }
- };
-
- template <typename Strategy>
- static inline bool
- apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T1)> const& geometry1,
- boost::variant<BOOST_VARIANT_ENUM_PARAMS(T2)> const& geometry2,
- Strategy const& strategy)
- {
- return boost::apply_visitor(visitor<Strategy>(strategy),
- geometry1,
- geometry2);
- }
-};
-
-}
-
-
-/*!
-\brief \brief_check12{is completely inside}
-\ingroup within
-\details \details_check12{within, is completely inside}.
-\tparam Geometry1 \tparam_geometry
-\tparam Geometry2 \tparam_geometry
-\param geometry1 \param_geometry which might be within the second geometry
-\param geometry2 \param_geometry which might contain the first geometry
-\return true if geometry1 is completely contained within geometry2,
- else false
-\note The default strategy is used for within detection
-
-
-\qbk{[include reference/algorithms/within.qbk]}
-
-\qbk{
-[heading Example]
-[within]
-[within_output]
-}
- */
-template<typename Geometry1, typename Geometry2>
-inline bool within(Geometry1 const& geometry1, Geometry2 const& geometry2)
-{
- return resolve_variant::within
- <
- Geometry1,
- Geometry2
- >::apply(geometry1, geometry2, default_strategy());
-}
-
-/*!
-\brief \brief_check12{is completely inside} \brief_strategy
-\ingroup within
-\details \details_check12{within, is completely inside}, \brief_strategy. \details_strategy_reasons
-\tparam Geometry1 \tparam_geometry
-\tparam Geometry2 \tparam_geometry
-\param geometry1 \param_geometry which might be within the second geometry
-\param geometry2 \param_geometry which might contain the first geometry
-\param strategy strategy to be used
-\return true if geometry1 is completely contained within geometry2,
- else false
-
-\qbk{distinguish,with strategy}
-\qbk{[include reference/algorithms/within.qbk]}
-\qbk{
-[heading Available Strategies]
-\* [link geometry.reference.strategies.strategy_within_winding Winding (coordinate system agnostic)]
-\* [link geometry.reference.strategies.strategy_within_franklin Franklin (cartesian)]
-\* [link geometry.reference.strategies.strategy_within_crossings_multiply Crossings Multiply (cartesian)]
-
-[heading Example]
-[within_strategy]
-[within_strategy_output]
-
-}
-*/
-template<typename Geometry1, typename Geometry2, typename Strategy>
-inline bool within(Geometry1 const& geometry1,
- Geometry2 const& geometry2,
- Strategy const& strategy)
-{
- return resolve_variant::within
- <
- Geometry1,
- Geometry2
- >::apply(geometry1, geometry2, strategy);
-}
-
-}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_WITHIN_HPP